この質問は通常、別の質問の一部として尋ねられますが、答えは長いことがわかります。他の場所にリンクできるように、ここで回答することにしました。
現時点では、Javaがオーディオサンプルを生成する方法を知りませんが、将来変更された場合は、ここがその場所になる可能性があります。 JavaFX
には、たとえば AudioSpectrumListener
のようなものがいくつかありますが、サンプルに直接アクセスする方法はまだありません。
再生や録音にjavax.sound.sampled
を使用していますが、オーディオで何かしたいのですが。
視覚的に表示したり、何らかの方法で処理したりしたいのかもしれません。
Java Soundでそれを行うためにオーディオサンプルデータにアクセスするにはどうすればよいですか?
参照:
さて、最も簡単な答えは、現時点ではJavaはプログラマー用のサンプルデータを生成できないということです。
信号処理を適用するには、次の2つの方法があります。
Control
オブジェクトを照会し、ユーザーが望むようにコントロールを設定することにより、ミキサーまたはそのコンポーネント行でサポートされている任意の処理を使用できます。ミキサーとラインでサポートされる一般的なコントロールには、ゲイン、パン、リバーブのコントロールが含まれます。必要な種類の処理がミキサーまたはそのラインによって提供されていない場合、プログラムはオーディオバイトを直接操作して、必要に応じてそれらを操作できます。
2番目の手法用の特別なAPIがないため、このページでは最初の手法について詳しく説明します。
_javax.sound.sampled
_での再生は、主にファイルとオーディオデバイス間のブリッジとして機能します。バイトはファイルから読み込まれ、送信されます。
バイトが意味のあるオーディオサンプルであると想定しないでください!たまたま8ビットのAIFFファイルがない限り、そうではありません。 (一方、サンプルがare間違いなく8ビットで署名されている場合は、canで算術演算を実行します。8ビットを使用することは、ここで説明する複雑さを回避する1つの方法です。 、遊んでいるだけなら。)
代わりに、 _AudioFormat.Encoding
_ のタイプを列挙し、それらを自分でデコードする方法を説明します。この答えはnotそれらをエンコードする方法をカバーしますが、それは下部の完全なコード例に含まれています。エンコーディングは、ほとんどの場合、逆のデコードプロセスです。
これは長い答えですが、私は完全な概要を説明したいと思いました。
一般に、デジタルオーディオについて説明するときは、 線形パルス符号変調 (LPCM)を指します。
連続音波は一定の間隔でサンプリングされ、振幅はあるスケールの整数に量子化されます。
ここに示されているのは、4ビットにサンプリングおよび量子化された正弦波です。
( 2の補数 表現の最も正の値は最も負の値より1小さいことに注意してください。これは注意すべき小さな詳細です。たとえば、オーディオをクリッピングしてこれを忘れた場合、ポジティブクリップはオーバーフローします。)
コンピューターにオーディオがある場合、これらのサンプルの配列があります。サンプル配列は、byte
配列を変換したいものです。
PCMサンプルをデコードするために、サンプルレートやチャネル数はあまり気にしないので、ここではあまり説明しません。通常、チャネルはインターリーブされているため、チャネルの配列がある場合は、次のように格納されます。
_Index 0: Sample 0 (Left Channel)
Index 1: Sample 0 (Right Channel)
Index 2: Sample 1 (Left Channel)
Index 3: Sample 1 (Right Channel)
Index 4: Sample 2 (Left Channel)
Index 5: Sample 2 (Right Channel)
...
_
つまり、ステレオの場合、配列内のサンプルは左右で交互に表示されます。
すべてのコード例は、次の宣言を前提としています。
byte[] bytes;
_ byte
から読み取られたAudioInputStream
配列。float[] samples;
_入力する出力サンプル配列。float sample;
_現在取り組んでいるサンプル。long temp;
_一般的な操作に使用される暫定値。int i;
_現在のサンプルのデータが開始するbyte
配列内の位置。_float[]
_配列内のすべてのサンプルを_-1f <= sample <= 1f
_の範囲に正規化します。私が見た浮動小数点オーディオはすべてこの方法で提供され、非常に便利です。
ソースオーディオがまだそのようになっていない場合(整数サンプルなど)、以下を使用して自分で正規化できます。
_sample = sample / fullScale(bitsPerSample);
_
ここで、fullScale
は2です。bitsPerSample-1、つまりMath.pow(2, bitsPerSample-1)
。
byte
配列を意味のあるデータに強制変換するにはどうすればよいですか?byte
配列には、分割されたサンプルフレームがすべて1行に含まれています。これは、各サンプルパケットのbyte
sの順序である endianness と呼ばれるものを除いて、実際には非常に簡単です。
これが図です。このサンプル(byte
配列にパックされている)は、10進値9999を保持します。
ビッグエンディアンとしての24ビットサンプル: bytes [i] bytes [i + 1] bytes [i + 2] ┌──────┐┌─ ─────┐┌──────┐ 00000000 00100111 00001111 リトルエンディアンとしての24ビットサンプル: bytes [i] bytes [i + 1] bytes [i + 2] ┌──────┐┌──────┐┌──────┐ 00001111 00100111 00000000
それらは同じバイナリ値を保持します。ただし、byte
の順序は逆になります。
byte
sが重要度の低いbyte
sの前に来ます。byte
sが重要度の高いbytes
の前に来ます。[〜#〜] wav [〜#〜] ファイルはリトルエンディアンの順序で保存され、 AIFFファイル はビッグエンディアンの順序で保存されます。エンディアンは _AudioFormat.isBigEndian
_ から取得できます。
byte
sを連結し、それらを_long temp
_変数に入れるには、次のようにします。
byte
が自動的にプロモートされるときに sign-extension を回避するために、各byte
とマスク_0xFF
_(_0b1111_1111
_)をビット単位でANDします。 (char
、byte
、およびshort
は、それらに対して算術演算が実行されると、int
にプロモートされます。)関連項目 機能_value & 0xff
_ Javaで実行しますか?byte
を所定の位置にビットシフトします。byte
sを一緒に。これが24ビットの例です:
_long temp;
if (isBigEndian) {
temp = (
((bytes[i ] & 0xffL) << 16)
| ((bytes[i + 1] & 0xffL) << 8)
| (bytes[i + 2] & 0xffL)
);
} else {
temp = (
(bytes[i ] & 0xffL)
| ((bytes[i + 1] & 0xffL) << 8)
| ((bytes[i + 2] & 0xffL) << 16)
);
}
_
エンディアンに基づいてシフト順序が逆になっていることに注意してください。
これはループに一般化することもできます。これは、この回答の下部にある完全なコードで確認できます。 (unpackAnyBit
およびpackAnyBit
メソッドを参照してください。)
byte
sが連結されたので、さらにいくつかの手順を実行して、それらをサンプルに変換できます。次の手順は、実際のエンコーディングによって異なります。
Encoding.PCM_SIGNED
_をデコードするにはどうすればよいですか?2の補数記号を拡張する必要があります。これは、最上位ビット(MSB)が1に設定されている場合、その上のすべてのビットを1で埋めることを意味します。符号ビットが設定されている場合、算術右シフト(_>>
_)によって自動的に入力が行われるため、通常は次のようにします。
_int bitsToExtend = Long.SIZE - bitsPerSample;
float sample = (temp << bitsToExtend) >> bitsToExtend.
_
(ここで、_Long.SIZE
_は64です。temp
変数がlong
でない場合は、別のものを使用します。代わりに_int temp
_を使用した場合は、 d 32を使用します。)
これがどのように機能するかを理解するために、8ビットから16ビットへの符号拡張の図を次に示します。
11111111はバイト値-1ですが、shortの上位ビットは0です。 バイトのMSBをshortのMSB位置にシフトインします。 0000 0000 1111 1111 << 8 ─────────────────── 1111 1111 0000 0000 シフトバックすると、右シフトですべての上位ビットが1で埋められます。 これで、短い値-1。 1111 1111 0000 0000 >> 8 ─────────────────── 1111 1111 1111 1111
正の値(MSBで0があった)は変更されません。これは、算術右シフトの優れたプロパティです。
次に、Some Assumptionsで説明されているように、サンプルを正規化します。
Javaは、1つの整数型からより大きな型(たとえば、byte
からint
)に変換するときに、自動的に符号拡張を行います。 know入力形式と出力形式が常に署名されている場合は、前の手順でバイトを連結するときに自動符号拡張を使用できます。
上記のセクション(バイト配列を意味のあるデータに強制変換するにはどうすればよいですか?)から、符号拡張が発生しないように_b & 0xFF
_を使用したことを思い出してください。最高のbyte
から_& 0xFF
_を削除するだけで、符号拡張が自動的に行われます。
たとえば、次の例では、署名付きのビッグエンディアンの16ビットサンプルをデコードします。
_for (int i = 0; i < bytes.length; i++) {
int sample = (bytes[i] << 8) // high byte is sign-extended
| (bytes[i + 1] & 0xFF); // low byte is not
// ...
}
_
Encoding.PCM_UNSIGNED
_をデコードするにはどうすればよいですか?符号付き数値に変換します。署名されていないサンプルは、次のように単純にオフセットされます。
したがって、これは非常に単純であることがわかります。オフセットを引くだけです。
_float sample = temp - fullScale(bitsPerSample);
_
次に、Some Assumptionsで説明されているように、サンプルを正規化します。
Encoding.PCM_FLOAT
_をデコードするにはどうすればよいですか?Java 7なので、これは新しいことです。
実際には、浮動小数点PCMは通常IEEE32ビットまたはIEEE64ビットのいずれかであり、すでに_±1.0
_の範囲に正規化されています。サンプルは、ユーティリティメソッド _Float#intBitsToFloat
_ および _Double#longBitsToDouble
_ で取得できます。
_// IEEE 32-bit
float sample = Float.intBitsToFloat((int) temp);
_
_// IEEE 64-bit
double sampleAsDouble = Double.longBitsToDouble(temp);
float sample = (float) sampleAsDouble; // or just use double for arithmetic
_
Encoding.ULAW
_と_Encoding.ALAW
_をデコードするにはどうすればよいですか?これらは 圧伸 電話などでより一般的な圧縮コーデックです。それらは_javax.sound.sampled
_によってサポートされています SunのAu形式 によって使用されているためだと思います。 (ただし、このタイプのコンテナーだけに限定されません。たとえば、WAVにはこれらのエンコーディングを含めることができます。)
A-law および μ-law を浮動小数点形式のように概念化できます。これらはPCM形式ですが、値の範囲は非線形です。
それらをデコードする方法は2つあります。数式の使い方を紹介します。 このブログ投稿で説明されています であるバイナリを直接操作することによってそれらをデコードすることもできますが、より難解に見えます。
どちらの場合も、圧縮データは8ビットです。標準では、A-lawはデコード時に13ビットで、μ-lawはデコード時に14ビットです。ただし、数式を適用すると、範囲は_±1.0
_になります。
数式を適用する前に、次の3つのことを行う必要があります。
±1.0
_の範囲も想定されているため、8ビット値をスケーリングする必要があります。Μ-lawの場合すべてのビットが反転するため、次のようになります。
_temp ^= 0xffL; // 0xff == 0b1111_1111
_
(long
の上位ビットを反転したくないため、_~
_を使用できないことに注意してください。)
A-lawの場合、1ビットおきが反転されるため、次のようになります。
_temp ^= 0x55L; // 0x55 == 0b0101_0101
_
(XORを使用して反転を行うことができます。 ビットをどのように設定、クリア、および切り替えますか? を参照してください)
符号と大きさを2の補数に変換するには、次のようにします。
_// 0x80 == 0b1000_0000
if ((temp & 0x80L) != 0) {
temp ^= 0x80L;
temp = -temp;
}
_
次に、いくつかの仮定で説明されているのと同じ方法で、エンコードされた数値をスケーリングします。
_sample = temp / fullScale(8);
_
これで、拡張を適用できます。
Javaに変換されたμ-law式は次のようになります:
_sample = (float) (
signum(sample)
*
(1.0 / 255.0)
*
(pow(256.0, abs(sample)) - 1.0)
);
_
Javaに変換されたA-law式は、次のようになります。
_float signum = signum(sample);
sample = abs(sample);
if (sample < (1.0 / (1.0 + log(87.7)))) {
sample = (float) (
sample * ((1.0 + log(87.7)) / 87.7)
);
} else {
sample = (float) (
exp((sample * (1.0 + log(87.7))) - 1.0) / 87.7
);
}
sample = signum * sample;
_
SimpleAudioConversion
クラスの完全なサンプルコードは次のとおりです。
_package mcve.audio;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioFormat.Encoding;
import static Java.lang.Math.*;
/**
* <p>Performs simple audio format conversion.</p>
*
* <p>Example usage:</p>
*
* <pre>{@code AudioInputStream ais = ... ;
* SourceDataLine line = ... ;
* AudioFormat fmt = ... ;
*
* // do setup
*
* for (int blen = 0; (blen = ais.read(bytes)) > -1;) {
* int slen;
* slen = SimpleAudioConversion.decode(bytes, samples, blen, fmt);
*
* // do something with samples
*
* blen = SimpleAudioConversion.encode(samples, bytes, slen, fmt);
* line.write(bytes, 0, blen);
* }}</pre>
*
* @author Radiodef
* @see <a href="http://stackoverflow.com/a/26824664/2891664">Overview on Stack Overflow</a>
*/
public final class SimpleAudioConversion {
private SimpleAudioConversion() {}
/**
* Converts from a byte array to an audio sample float array.
*
* @param bytes the byte array, filled by the AudioInputStream
* @param samples an array to fill up with audio samples
* @param blen the return value of AudioInputStream.read
* @param fmt the source AudioFormat
*
* @return the number of valid audio samples converted
*
* @throws NullPointerException if bytes, samples or fmt is null
* @throws ArrayIndexOutOfBoundsException
* if bytes.length is less than blen or
* if samples.length is less than blen / bytesPerSample(fmt.getSampleSizeInBits())
*/
public static int decode(byte[] bytes,
float[] samples,
int blen,
AudioFormat fmt) {
int bitsPerSample = fmt.getSampleSizeInBits();
int bytesPerSample = bytesPerSample(bitsPerSample);
boolean isBigEndian = fmt.isBigEndian();
Encoding encoding = fmt.getEncoding();
double fullScale = fullScale(bitsPerSample);
int i = 0;
int s = 0;
while (i < blen) {
long temp = unpackBits(bytes, i, isBigEndian, bytesPerSample);
float sample = 0f;
if (encoding == Encoding.PCM_SIGNED) {
temp = extendSign(temp, bitsPerSample);
sample = (float) (temp / fullScale);
} else if (encoding == Encoding.PCM_UNSIGNED) {
temp = unsignedToSigned(temp, bitsPerSample);
sample = (float) (temp / fullScale);
} else if (encoding == Encoding.PCM_FLOAT) {
if (bitsPerSample == 32) {
sample = Float.intBitsToFloat((int) temp);
} else if (bitsPerSample == 64) {
sample = (float) Double.longBitsToDouble(temp);
}
} else if (encoding == Encoding.ULAW) {
sample = bitsToMuLaw(temp);
} else if (encoding == Encoding.ALAW) {
sample = bitsToALaw(temp);
}
samples[s] = sample;
i += bytesPerSample;
s++;
}
return s;
}
/**
* Converts from an audio sample float array to a byte array.
*
* @param samples an array of audio samples to encode
* @param bytes an array to fill up with bytes
* @param slen the return value of the decode method
* @param fmt the destination AudioFormat
*
* @return the number of valid bytes converted
*
* @throws NullPointerException if samples, bytes or fmt is null
* @throws ArrayIndexOutOfBoundsException
* if samples.length is less than slen or
* if bytes.length is less than slen * bytesPerSample(fmt.getSampleSizeInBits())
*/
public static int encode(float[] samples,
byte[] bytes,
int slen,
AudioFormat fmt) {
int bitsPerSample = fmt.getSampleSizeInBits();
int bytesPerSample = bytesPerSample(bitsPerSample);
boolean isBigEndian = fmt.isBigEndian();
Encoding encoding = fmt.getEncoding();
double fullScale = fullScale(bitsPerSample);
int i = 0;
int s = 0;
while (s < slen) {
float sample = samples[s];
long temp = 0L;
if (encoding == Encoding.PCM_SIGNED) {
temp = (long) (sample * fullScale);
} else if (encoding == Encoding.PCM_UNSIGNED) {
temp = (long) (sample * fullScale);
temp = signedToUnsigned(temp, bitsPerSample);
} else if (encoding == Encoding.PCM_FLOAT) {
if (bitsPerSample == 32) {
temp = Float.floatToRawIntBits(sample);
} else if (bitsPerSample == 64) {
temp = Double.doubleToRawLongBits(sample);
}
} else if (encoding == Encoding.ULAW) {
temp = muLawToBits(sample);
} else if (encoding == Encoding.ALAW) {
temp = aLawToBits(sample);
}
packBits(bytes, i, temp, isBigEndian, bytesPerSample);
i += bytesPerSample;
s++;
}
return i;
}
/**
* Computes the block-aligned bytes per sample of the audio format,
* using Math.ceil(bitsPerSample / 8.0).
* <p>
* Round towards the ceiling because formats that allow bit depths
* in non-integral multiples of 8 typically pad up to the nearest
* integral multiple of 8. So for example, a 31-bit AIFF file will
* actually store 32-bit blocks.
*
* @param bitsPerSample the return value of AudioFormat.getSampleSizeInBits
* @return The block-aligned bytes per sample of the audio format.
*/
public static int bytesPerSample(int bitsPerSample) {
return (int) ceil(bitsPerSample / 8.0); // optimization: ((bitsPerSample + 7) >>> 3)
}
/**
* Computes the largest magnitude representable by the audio format,
* using Math.pow(2.0, bitsPerSample - 1). Note that for two's complement
* audio, the largest positive value is one less than the return value of
* this method.
* <p>
* The result is returned as a double because in the case that
* bitsPerSample is 64, a long would overflow.
*
* @param bitsPerSample the return value of AudioFormat.getBitsPerSample
* @return the largest magnitude representable by the audio format
*/
public static double fullScale(int bitsPerSample) {
return pow(2.0, bitsPerSample - 1); // optimization: (1L << (bitsPerSample - 1))
}
private static long unpackBits(byte[] bytes,
int i,
boolean isBigEndian,
int bytesPerSample) {
switch (bytesPerSample) {
case 1: return unpack8Bit(bytes, i);
case 2: return unpack16Bit(bytes, i, isBigEndian);
case 3: return unpack24Bit(bytes, i, isBigEndian);
default: return unpackAnyBit(bytes, i, isBigEndian, bytesPerSample);
}
}
private static long unpack8Bit(byte[] bytes, int i) {
return bytes[i] & 0xffL;
}
private static long unpack16Bit(byte[] bytes,
int i,
boolean isBigEndian) {
if (isBigEndian) {
return (
((bytes[i ] & 0xffL) << 8)
| (bytes[i + 1] & 0xffL)
);
} else {
return (
(bytes[i ] & 0xffL)
| ((bytes[i + 1] & 0xffL) << 8)
);
}
}
private static long unpack24Bit(byte[] bytes,
int i,
boolean isBigEndian) {
if (isBigEndian) {
return (
((bytes[i ] & 0xffL) << 16)
| ((bytes[i + 1] & 0xffL) << 8)
| (bytes[i + 2] & 0xffL)
);
} else {
return (
(bytes[i ] & 0xffL)
| ((bytes[i + 1] & 0xffL) << 8)
| ((bytes[i + 2] & 0xffL) << 16)
);
}
}
private static long unpackAnyBit(byte[] bytes,
int i,
boolean isBigEndian,
int bytesPerSample) {
long temp = 0;
if (isBigEndian) {
for (int b = 0; b < bytesPerSample; b++) {
temp |= (bytes[i + b] & 0xffL) << (
8 * (bytesPerSample - b - 1)
);
}
} else {
for (int b = 0; b < bytesPerSample; b++) {
temp |= (bytes[i + b] & 0xffL) << (8 * b);
}
}
return temp;
}
private static void packBits(byte[] bytes,
int i,
long temp,
boolean isBigEndian,
int bytesPerSample) {
switch (bytesPerSample) {
case 1: pack8Bit(bytes, i, temp);
break;
case 2: pack16Bit(bytes, i, temp, isBigEndian);
break;
case 3: pack24Bit(bytes, i, temp, isBigEndian);
break;
default: packAnyBit(bytes, i, temp, isBigEndian, bytesPerSample);
break;
}
}
private static void pack8Bit(byte[] bytes, int i, long temp) {
bytes[i] = (byte) (temp & 0xffL);
}
private static void pack16Bit(byte[] bytes,
int i,
long temp,
boolean isBigEndian) {
if (isBigEndian) {
bytes[i ] = (byte) ((temp >>> 8) & 0xffL);
bytes[i + 1] = (byte) ( temp & 0xffL);
} else {
bytes[i ] = (byte) ( temp & 0xffL);
bytes[i + 1] = (byte) ((temp >>> 8) & 0xffL);
}
}
private static void pack24Bit(byte[] bytes,
int i,
long temp,
boolean isBigEndian) {
if (isBigEndian) {
bytes[i ] = (byte) ((temp >>> 16) & 0xffL);
bytes[i + 1] = (byte) ((temp >>> 8) & 0xffL);
bytes[i + 2] = (byte) ( temp & 0xffL);
} else {
bytes[i ] = (byte) ( temp & 0xffL);
bytes[i + 1] = (byte) ((temp >>> 8) & 0xffL);
bytes[i + 2] = (byte) ((temp >>> 16) & 0xffL);
}
}
private static void packAnyBit(byte[] bytes,
int i,
long temp,
boolean isBigEndian,
int bytesPerSample) {
if (isBigEndian) {
for (int b = 0; b < bytesPerSample; b++) {
bytes[i + b] = (byte) (
(temp >>> (8 * (bytesPerSample - b - 1))) & 0xffL
);
}
} else {
for (int b = 0; b < bytesPerSample; b++) {
bytes[i + b] = (byte) ((temp >>> (8 * b)) & 0xffL);
}
}
}
private static long extendSign(long temp, int bitsPerSample) {
int bitsToExtend = Long.SIZE - bitsPerSample;
return (temp << bitsToExtend) >> bitsToExtend;
}
private static long unsignedToSigned(long temp, int bitsPerSample) {
return temp - (long) fullScale(bitsPerSample);
}
private static long signedToUnsigned(long temp, int bitsPerSample) {
return temp + (long) fullScale(bitsPerSample);
}
// mu-law constant
private static final double MU = 255.0;
// A-law constant
private static final double A = 87.7;
// natural logarithm of A
private static final double LN_A = log(A);
private static float bitsToMuLaw(long temp) {
temp ^= 0xffL;
if ((temp & 0x80L) != 0) {
temp = -(temp ^ 0x80L);
}
float sample = (float) (temp / fullScale(8));
return (float) (
signum(sample)
*
(1.0 / MU)
*
(pow(1.0 + MU, abs(sample)) - 1.0)
);
}
private static long muLawToBits(float sample) {
double sign = signum(sample);
sample = abs(sample);
sample = (float) (
sign * (log(1.0 + (MU * sample)) / log(1.0 + MU))
);
long temp = (long) (sample * fullScale(8));
if (temp < 0) {
temp = -temp ^ 0x80L;
}
return temp ^ 0xffL;
}
private static float bitsToALaw(long temp) {
temp ^= 0x55L;
if ((temp & 0x80L) != 0) {
temp = -(temp ^ 0x80L);
}
float sample = (float) (temp / fullScale(8));
float sign = signum(sample);
sample = abs(sample);
if (sample < (1.0 / (1.0 + LN_A))) {
sample = (float) (sample * ((1.0 + LN_A) / A));
} else {
sample = (float) (exp((sample * (1.0 + LN_A)) - 1.0) / A);
}
return sign * sample;
}
private static long aLawToBits(float sample) {
double sign = signum(sample);
sample = abs(sample);
if (sample < (1.0 / A)) {
sample = (float) ((A * sample) / (1.0 + LN_A));
} else {
sample = (float) ((1.0 + log(A * sample)) / (1.0 + LN_A));
}
sample *= sign;
long temp = (long) (sample * fullScale(8));
if (temp < 0) {
temp = -temp ^ 0x80L;
}
return temp ^ 0x55L;
}
}
_
これは、現在再生中のサウンドから実際のサンプルデータを取得する方法です。 その他の優れた回答 は、データの意味を示します。私のWindows10マシンYMMV以外のOSで試したことはありません。私にとっては、現在のシステムのデフォルトの録音デバイスをプルします。 Windowsでは、サウンドを再生するには、「マイク」ではなく「ステレオミックス」に設定します。 「ステレオミックス」を表示するには、「無効なデバイスを表示」を切り替える必要がある場合があります。
import javax.sound.sampled.*;
public class SampleAudio {
private static long extendSign(long temp, int bitsPerSample) {
int extensionBits = 64 - bitsPerSample;
return (temp << extensionBits) >> extensionBits;
}
public static void main(String[] args) throws LineUnavailableException {
float sampleRate = 8000;
int sampleSizeBits = 16;
int numChannels = 1; // Mono
AudioFormat format = new AudioFormat(sampleRate, sampleSizeBits, numChannels, true, true);
TargetDataLine tdl = AudioSystem.getTargetDataLine(format);
tdl.open(format);
tdl.start();
if (!tdl.isOpen()) {
System.exit(1);
}
byte[] data = new byte[(int)sampleRate*10];
int read = tdl.read(data, 0, (int)sampleRate*10);
if (read > 0) {
for (int i = 0; i < read-1; i = i + 2) {
long val = ((data[i] & 0xffL) << 8L) | (data[i + 1] & 0xffL);
long valf = extendSign(val, 16);
System.out.println(i + "\t" + valf);
}
}
tdl.close();
}
}