2014-09-28 3 views
7

Я пытаюсь сделать приложение для записи вызовов в Android. Я использую громкоговоритель для записи как восходящего, так и нисходящего звука. Единственная проблема, с которой я столкнулся, - слишком низкий объем. Я увеличил объем устройства с помощью AudioManager до max, и он не может выйти за рамки этого.Увеличение громкости записанного звука

Я впервые использовал MediaRecorder, но поскольку он имел ограниченные функции и обеспечивает сжатый звук, я пробовал использовать AudioRecorder. Тем не менее я не понял, как увеличить звук. Я также проверил проекты в Github, но это бесполезно. Я искал stackoverflow в течение последних двух недель, но ничего не нашел.

Я вполне уверен, что это возможно, так как это делают многие другие приложения. Например, это делает автоматический регистратор вызовов.

Я понимаю, что мне нужно что-то сделать с аудио-буфером, но я не совсем уверен, что с этим нужно сделать. Можете ли вы направить меня на это.

Обновление: -
Я сожалею, что я забыл упомянуть, что я уже использую Gain. Мой код почти похож на RehearsalAssistant (на самом деле я получил его оттуда). Коэффициент усиления не работает более 10 дБ, и это не увеличивает громкость звука. Я хотел бы, чтобы я мог слушать аудио, не вкладывая слух в динамик, чего не хватает в моем коде.

Я задал аналогичный вопрос о функционировании громкости/громкости в SoundDesign SE here. В нем упоминается, что коэффициент усиления и громкости связан, но он не устанавливает фактический уровень громкости. Я не уверен, как все работает, но я решил получить громкий объем.

ответ

12

Вы, очевидно, имеют AudioRecord материал работает, поэтому я пропущу решение для sampleRate и inputSource. Главное, что вам нужно соответствующим образом манипулировать каждым образцом ваших записанных данных в вашем цикле записи, чтобы увеличить громкость. Как так:

int minRecBufBytes = AudioRecord.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT); 
    // ... 
    audioRecord = new AudioRecord(inputSource, sampleRate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, minRecBufBytes); 

    // Setup the recording buffer, size, and pointer (in this case quadruple buffering) 
    int recBufferByteSize = minRecBufBytes*2; 
    byte[] recBuffer = new byte[recBufferByteSize]; 
    int frameByteSize = minRecBufBytes/2; 
    int sampleBytes = frameByteSize; 
    int recBufferBytePtr = 0; 

    audioRecord.startRecording(); 

    // Do the following in the loop you prefer, e.g. 
    while (continueRecording) { 
     int reallySampledBytes = audioRecord.read(recBuffer, recBufferBytePtr, sampleBytes); 

     int i = 0; 
     while (i < reallySampledBytes) { 
      float sample = (float)(recBuffer[recBufferBytePtr+i ] & 0xFF 
            | recBuffer[recBufferBytePtr+i+1] << 8); 

      // THIS is the point were the work is done: 
      // Increase level by about 6dB: 
      sample *= 2; 
      // Or increase level by 20dB: 
      // sample *= 10; 
      // Or if you prefer any dB value, then calculate the gain factor outside the loop 
      // float gainFactor = (float)Math.pow(10., dB/20.); // dB to gain factor 
      // sample *= gainFactor; 

      // Avoid 16-bit-integer overflow when writing back the manipulated data: 
      if (sample >= 32767f) { 
       recBuffer[recBufferBytePtr+i ] = (byte)0xFF; 
       recBuffer[recBufferBytePtr+i+1] =  0x7F; 
      } else if (sample <= -32768f) { 
       recBuffer[recBufferBytePtr+i ] =  0x00; 
       recBuffer[recBufferBytePtr+i+1] = (byte)0x80; 
      } else { 
       int s = (int)(0.5f + sample); // Here, dithering would be more appropriate 
       recBuffer[recBufferBytePtr+i ] = (byte)(s & 0xFF); 
       recBuffer[recBufferBytePtr+i+1] = (byte)(s >> 8 & 0xFF); 
      } 
      i += 2; 
     } 

     // Do other stuff like saving the part of buffer to a file 
     // if (reallySampledBytes > 0) { ... save recBuffer+recBufferBytePtr, length: reallySampledBytes 

     // Then move the recording pointer to the next position in the recording buffer 
     recBufferBytePtr += reallySampledBytes; 

     // Wrap around at the end of the recording buffer, e.g. like so: 
     if (recBufferBytePtr >= recBufferByteSize) { 
      recBufferBytePtr = 0; 
      sampleBytes = frameByteSize; 
     } else { 
      sampleBytes = recBufferByteSize - recBufferBytePtr; 
      if (sampleBytes > frameByteSize) 
       sampleBytes = frameByteSize; 
     } 
    } 
+0

На самом деле я уже использую коэффициент усиления, но он не работает более чем на 10 дБ. Я использую код с этого URL-адреса - http://sourceforge.net/p/rehearsalassist/code/HEAD/tree/android/branches/pause_and_gain/src/urbanstew/RehearsalAssistant/RehearsalAudioRecorder.java – noob

+0

Пожалуйста, проверьте обновленную информацию по вопросу слишком. Благодарю. – noob

+0

Вы говорите, что это не работает более чем на 10 дБ? Что именно вы наблюдаете, скажем, 12 или 20 дБ? –

0

простое использование формата MPEG_4

Для увеличения записи вызовов громкости используйте AudioManager следующим образом:

int deviceCallVol; 
AudioManager audioManager; 

Начать запись:

audioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); 
//get the current volume set 
deviceCallVol = audioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL); 
//set volume to maximum 
     audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, audioManager.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL), 0); 

    recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL); 
    recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); 
    recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); 
    recorder.setAudioEncodingBitRate(32); 
    recorder.setAudioSamplingRate(44100); 

Остановить запись:

// вновь обратиться объем до исходного состояния

audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL, deviceCallVol, 0); 
+0

Спасибо за ответ. Я уже пробовал разные форматы. MediaRecorder определенно не решает мою цель (за исключением того, что есть хак или работа вокруг). Я вроде как ожидаю какой-то алгоритм, который можно применить к звуковому буферу, чтобы улучшить громкость. – noob

+0

Спасибо за этот ответ. У меня были подобные проблемы, и смена MPEG_4/AAC из 3GPP/AMR_NB значительно улучшила качество и объем. – tpaczesny

1

В моем приложении я использую с открытым исходным кодом sonic library. Его основная цель - ускорить/замедлить речь, но помимо этого она также позволяет увеличить громкость. Я применяю его для воспроизведения, но он должен работать для записи аналогичным образом. Просто передайте свои образцы, прежде чем сжимать их. Он также имеет интерфейс Java. Надеюсь это поможет.

+0

Спасибо, я проверю. – noob

2

Благодаря Хартмуту и ​​работнику для решения. Код Хартмута работал около 12-14 дБ. Я тоже объединил код из звуковой библиотеки, чтобы увеличить громкость, но это увеличило слишком много шума и искажений, поэтому я сохранил громкость 1,5-2,0 и вместо этого попытался увеличить коэффициент усиления. У меня приличный звук, который не звучит слишком громко в телефоне, но при прослушивании на ПК звучит достаточно громко. Похоже, это самое дальнее, что я мог бы сделать.

Я отправляю свой последний код, чтобы увеличить громкость. Имейте в виду, что использование увеличения mVolume увеличивает слишком большой шум. Попробуйте увеличить коэффициент усиления.

private AudioRecord.OnRecordPositionUpdateListener updateListener = new AudioRecord.OnRecordPositionUpdateListener() { 
     @Override 
     public void onPeriodicNotification(AudioRecord recorder) { 
      aRecorder.read(bBuffer, bBuffer.capacity()); // Fill buffer 
      if (getState() != State.RECORDING) 
       return; 
      try { 
       if (bSamples == 16) { 
        shBuffer.rewind(); 
        int bLength = shBuffer.capacity(); // Faster than accessing buffer.capacity each time 
        for (int i = 0; i < bLength; i++) { // 16bit sample size 
         short curSample = (short) (shBuffer.get(i) * gain); 
         if (curSample > cAmplitude) { // Check amplitude 
          cAmplitude = curSample; 
         } 
         if(mVolume != 1.0f) { 
          // Adjust output volume. 
          int fixedPointVolume = (int)(mVolume*4096.0f); 
          int value = (curSample*fixedPointVolume) >> 12; 
          if(value > 32767) { 
           value = 32767; 
          } else if(value < -32767) { 
           value = -32767; 
          } 
          curSample = (short)value; 
          /*scaleSamples(outputBuffer, originalNumOutputSamples, numOutputSamples - originalNumOutputSamples, 
            mVolume, nChannels);*/ 
         } 
         shBuffer.put(curSample); 
        } 
       } else { // 8bit sample size 
        int bLength = bBuffer.capacity(); // Faster than accessing buffer.capacity each time 
        bBuffer.rewind(); 
        for (int i = 0; i < bLength; i++) { 
         byte curSample = (byte) (bBuffer.get(i) * gain); 
         if (curSample > cAmplitude) { // Check amplitude 
          cAmplitude = curSample; 
         } 
         bBuffer.put(curSample); 
        } 
       } 
       bBuffer.rewind(); 
       fChannel.write(bBuffer); // Write buffer to file 
       payloadSize += bBuffer.capacity(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
       Log.e(NoobAudioRecorder.class.getName(), "Error occured in updateListener, recording is aborted"); 
       stop(); 
      } 
     } 

     @Override 
     public void onMarkerReached(AudioRecord recorder) { 
      // NOT USED 
     } 
    };