Android 声音录制音量调节

最近做一个录屏项目,录制的系统声音音量偏小,需要调大

录音的方式采用了AudioRecord,可以拿到音频原始数据,于是想到从音频数据下手

之前没有接触过类似的知识,对这个东西也不懂,参考网上做法,需要使用到一个公式

公式:

A1 = A2 * pow(10, db/20)

A1 和 A2 是两个声音的振幅,A2为原始音频振幅,A1为根据所指定db大小计算出来的调节音量后的音频振幅

频率与振幅

声音有两个基本的物理属性:频率与振幅。声音的振幅就是音量,频率的高低就是指音调,频率用赫兹(Hz)作单位。人耳只能听到20Hz到20khz范围的声音。

代码

int db = 20;//db为0表示保持音量不变,db为负数表示较低音量,为正数表示提高音量
private double factor = Math.pow(10,(double)db / 20);

//调节PCM数据音量
//pData原始音频byte数组,nLen原始音频byte数组长度,data2转换后新音频byte数组,nBitsPerSample采样率,multiple表示Math.pow()返回值
public int amplifyPCMData(byte[] pData, int nLen, byte[] data2, int nBitsPerSample, float multiple){
    int nCur = 0;
    if (16 == nBitsPerSample){
        while (nCur < nLen){
            short volum = getShort(pData, nCur);
            float pcmval = volum * multiple;
            //volum = (short)(volum * multiple);
            //数据溢出处理
            if (pcmval < 32767 && pcmval > -32768){
                volum = (short)pcmval;
            }else if (pcmval > 32767) {
                volum = (short)32767;
            } else if (pcmval < -32768) {
                volum = (short)-32768;
            }
            data2[nCur]   = (byte)( volum       & 0xFF);
            nCur += 2;
        }
    }
    return 0;
}

private short getShort(byte[] data, int start){
    return (short)((data[start] & 0xFF) | (data[start+1] << 8));
}

db

db为0表示保持音量不变,db为负数表示较低音量,为正数表示提高音量,声音调节步长最好是2db 

数据溢出处理

每个样本取值范围是有限制的,调节音量时不可能随便增大,比如一个signed 16 bits的样本,值为5000,我们放大10倍,由于有符号位16bits数据取值范围为-32768~32767,5000乘以10得到的50000超过了32767,数据溢出了,最后值可能变为-15536,不是我们期望的。此时我们就需要裁剪了,确保数值在正确范围内

AudioRecord使用示例

/**
 * Thread to capture audio data from internal mic as uncompressed 16bit PCM data
 * and write them to the MediaCodec encoder
 */
private class AudioThread extends Thread {
    @Override
    public void run() {
        android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
        try {
            final int min_buffer_size = AudioRecord.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO,AudioFormat.ENCODING_PCM_16BIT);
            int buffer_size = SAMPLES_PER_FRAME * FRAMES_PER_BUFFER;
            if (buffer_size < min_buffer_size)
                buffer_size = ((min_buffer_size / SAMPLES_PER_FRAME) + 1) * SAMPLES_PER_FRAME * 2;
            AudioRecord audioRecord  = new AudioRecord(mAudioSource, SAMPLE_RATE,AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, buffer_size);
            if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED)
                audioRecord = null;
            if (audioRecord != null) {
                try {
                    if (mIsCapturing) {
                        if (DEBUG) Log.v(TAG, "AudioThread:start audio recording");
                        final ByteBuffer buf = ByteBuffer.allocateDirect(SAMPLES_PER_FRAME);
                        int readBytes;
                        audioRecord.startRecording();
                        try {
                            for (; mIsCapturing && !mRequestStop && !mIsEOS;) {
                                // read audio data from internal mic
                                if (!isPause){
                                    buf.clear();
                                    readBytes = audioRecord.read(buf, SAMPLES_PER_FRAME);
                                    if (readBytes > 0) {
                                        // set audio data to encoder
                                        buf.position(readBytes);
                                        buf.flip();

                                        if (mAudioSource == 99999){
                                            //录制系统声音音量处理
                                            byte[] byteYuan = new byte[buf.remaining()];
                                            buf.get(byteYuan,0,byteYuan.length);
                                            byte[] byteYuanNew = new byte[byteYuan.length];
                                            amplifyPCMData(byteYuan,byteYuan.length,byteYuanNew,16,(float) factor);
                                            buf.clear();
                                            buf.put(byteYuanNew);
                                            buf.position(readBytes);
                                            buf.flip();
                                        }
                                        encode(buf, readBytes, getPTSUs());
                                        frameAvailableSoon();
                                     }
                                 }
                             }
                        } finally {
                            Log.e(TAG,"audio end");
                            audioRecord.stop();
                        }
                    }
                } catch (Exception e) {
                    Log.e(TAG, "AudioRecord failed to startRecording");
                    if (mExecptionCallback != null){
                        mExecptionCallback.recordException(e);
                    }
                }finally {
                    audioRecord.release();
                }
            } else {
                Log.e(TAG, "failed to initialize AudioRecord");
            }
        } catch (final Exception e) {
            Log.e(TAG, "AudioThread#run", e);
        }
        if (DEBUG) Log.v(TAG, "AudioThread:finished");
    }
}

参考:https://www.jianshu.com/p/50c697bec409 

 

你可能感兴趣的:(Android,录音)