问题
public TargetDataLine targetDataLine;
private static AudioFormat getAudioFormat()
{
return new AudioFormat(16000, 16, 2, true, false);
}
AudioFormat a = getAudioFormat();
DataLine.Info info = new DataLine.Info(TargetDataLine.class, a);
targetDataLine = (TargetDataLine) AudioSystem.getLine(info);
targetDataLine.open(a);
targetDataLine.start();
AudioInputStream ais = new AudioInputStream(targetDataLine);
AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File("record.wav"));
- How can i calculate the decibel of audio at the same time?
- How can i calculate the decibel of existing wav file?
回答1:
Assumption One: You would like to process and save the data at the end of your recording.
- Read data into a temporary short buffer using TargetDataLine.read()
- Write data into a
ByteArrayOutputStream
using ByteArrayOutputStream.write() - Convert the
ByteArrayOutputStream
intobyte[]
array. - Encode byte data into samples
- Calculate RMS, Peak, etc. and convert them into decibels.
- Construct
ByteArrayInputStream
using yourbyte[]
array Produce your audio file using
AudioSystem.write()
int numBytesRead = 0; byte[] buffer = new byte[1024]; ByteArrayOutputStream outStream = new ByteArrayOutputStream(); boolean stopRecording = false; while (!stopRecording) { numBytesRead = targetDataLine.read(buffer, 0, buffer.length); //short[] samples = encodeToSample(buffer, buffer.length); // process samples - calculate decibels if (numBytesRead > 0) { outStream.write(buffer, 0, numBytesRead); } } outStream.close(); byte[] data = outStream.toByteArray(); ByteArrayInputStream bais = new ByteArrayInputStream(data); AudioInputStream ais = new AudioInputStream(bais, a, data.length); AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File("record.wav"));
Assumption Two: You would like to read, process, and save the data continuously.
You need an intermediate class in order to convert ByteArrayOutputStream
to ByteArrayInputStream
. In a background thread capture audio data, and in another thread process and save the data when your desired amount of data is available.
Encoding: You can encode audio samples from your byte[]
array. In your case, two consecutive bytes produce one sample. You will get the samples for both channels one after another. If you have any channel specific processing then you need to segregate the samples for each channel. The following code snippet may help you for encoding -
public static short[] encodeToSample(byte[] srcBuffer, int numBytes) {
byte[] tempBuffer = new byte[2];
int nSamples = numBytes / 2;
short[] samples = new short[nSamples]; // 16-bit signed value
for (int i = 0; i < nSamples; i++) {
tempBuffer[0] = srcBuffer[2 * i];
tempBuffer[1] = srcBuffer[2 * i + 1];
samples[i] = bytesToShort(tempBuffer);
}
return samples;
}
public static short bytesToShort(byte [] buffer) {
ByteBuffer bb = ByteBuffer.allocate(2);
bb.order(ByteOrder.BIG_ENDIAN);
bb.put(buffer[0]);
bb.put(buffer[1]);
return bb.getShort(0);
}
Decibel: Db is a logarithmic ratio of a given level with a reference level. For example, if you would like to calculate RMS/Peak in dBFS, following code snippet may help you.
public static void calculatePeakAndRms(short [] samples) {
double sumOfSampleSq = 0.0; // sum of square of normalized samples.
double peakSample = 0.0; // peak sample.
for (short sample : samples) {
double normSample = (double) sample / 32767; // normalized the sample with maximum value.
sumOfSampleSq += (normSample * normSample);
if (Math.abs(sample) > peakSample) {
peakSample = Math.abs(sample);
}
}
double rms = 10*Math.log10(sumOfSampleSq / samples.length);
double peak = 20*Math.log10(peakSample / 32767);
}
来源:https://stackoverflow.com/questions/49097889/how-to-calculate-the-decibel-of-audio-signal-and-record-the-audio-in-java