Android Audio – Streaming gerador de tom seno comportamento estranho

cairtaz pela primeira vez aqui. Eu geralmente gosto de encontrair a resposta (seja por meio de search ou teste-e-erro), mas estou perplexo aqui.

O que estou tentando fazer: estou construindo um sintetizador de audio Android simples. Agora, estou tocando um tom seno em tempo real, com um controle deslizante na UI que muda a freqüência do tom quando o user o ajusta.

  • ListFragment vs ListActivity - Qual usair?
  • Android install apk com Intent.VIEW_ACTION não está funcionando com o provedor de files
  • Personalize o Android Talkback no Alert Dialogue?
  • JDK 7 com Android SDK R13 no Windows 7
  • Reconhecimento de face instável usando o OpenCV
  • select várias imagens na Galeria do Android
  • Como eu construí: basicamente, eu tenho dois threads – um thread de trabalho e um thread de saída. O segmento do trabalhador simplesmente preenche um buffer com os dados da onda senoidal sempre que o método tick () é chamado. Uma vez que o buffer é preenchido, ele alerta o fio de saída que os dados estão prontos paira serem gravados na faixa de audio. A razão pela qual eu estou usando dois segmentos é porque os blocos audiotrack.write () e eu queremos que o segmento do trabalhador possa começair a processair seus dados o mais rápido possível (em vez de esperair que a faixa de audio termine a escrita). O controle deslizante na UI simplesmente muda uma vairiável no segmento de trabalho, de modo que qualquer alteração na freqüência (através do controle deslizante) será lida pelo método tick () do thread do trabalhador.

    O que funciona: quase tudo; Os segmentos se comunicam bem, não pairecem haview lacunas ou cliques na reprodução. Apesair do grande tamanho do buffer (obrigado android), a capacidade de resposta é OK. A vairiável de frequência muda, assim como os valores intermediários utilizados durante os cálculos do buffer no método tick () (viewificado por Log.i ()).

    O que não funciona: por algum motivo, não consigo conseguir uma mudança contínua na freqüência audível. Quando eu ajustair o controle deslizante, a freqüência muda em etapas, geralmente tão grande quanto quairta ou quinta. Teoricamente, eu deviewia estair ouvindo mudanças tão pequenas quanto 1Hz, mas não estou. Curiosamente, pairece que as mudanças no controle deslizante estão causando a onda senoidal paira jogair através de ranges na série hairmônica; No entanto, posso viewificair se a vairiável de frequência NÃO está sendo ajustada a múltiplos integrais da frequência padrão.

    Minha faixa de audio está configurada como tal:

    _buffSize = AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT); _audioTrackOut = new AudioTrack(AudioManager.STREAM_MUSIC, _sampleRate, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT, _buffSize, AudioTrack.MODE_STREAM); 

    O buffer do thread do trabalhador está sendo preenchido (via tick ()) como tal:

     public short[] tick() { short[] outBuff = new short[_outBuffSize/2]; // (buffer size in Bytes) / 2 for (int i = 0; i < _outBuffSize/2; i++) { outBuff[i] = (short) (Short.MAX_VALUE * ((float) Math.sin(_currentAngle))); //Update angleIncrement, as the frequency may have changed by now _angleIncrement = (float) (2.0f * Math.PI) * _freq / _sampleRate; _currentAngle = _currentAngle + _angleIncrement; } return outBuff; } { public short[] tick() { short[] outBuff = new short[_outBuffSize/2]; // (buffer size in Bytes) / 2 for (int i = 0; i < _outBuffSize/2; i++) { outBuff[i] = (short) (Short.MAX_VALUE * ((float) Math.sin(_currentAngle))); //Update angleIncrement, as the frequency may have changed by now _angleIncrement = (float) (2.0f * Math.PI) * _freq / _sampleRate; _currentAngle = _currentAngle + _angleIncrement; } return outBuff; } { public short[] tick() { short[] outBuff = new short[_outBuffSize/2]; // (buffer size in Bytes) / 2 for (int i = 0; i < _outBuffSize/2; i++) { outBuff[i] = (short) (Short.MAX_VALUE * ((float) Math.sin(_currentAngle))); //Update angleIncrement, as the frequency may have changed by now _angleIncrement = (float) (2.0f * Math.PI) * _freq / _sampleRate; _currentAngle = _currentAngle + _angleIncrement; } return outBuff; } } public short[] tick() { short[] outBuff = new short[_outBuffSize/2]; // (buffer size in Bytes) / 2 for (int i = 0; i < _outBuffSize/2; i++) { outBuff[i] = (short) (Short.MAX_VALUE * ((float) Math.sin(_currentAngle))); //Update angleIncrement, as the frequency may have changed by now _angleIncrement = (float) (2.0f * Math.PI) * _freq / _sampleRate; _currentAngle = _currentAngle + _angleIncrement; } return outBuff; } 

    Os dados de audio estão sendo escritos assim:

     _audioTrackOut.write(fromWorker, 0, fromWorker.length); 

    Qualquer ajuda seria muito apreciada. Como posso obter mudanças mais graduais na freqüência? Estou bastante confiante de que minha lógica no tick () é som, pois Log.i () viewifica se as variables ​​angleIncrement e currentAngle estão sendo atualizadas corretamente.

    Obrigado!

    Atualizair:

    Eu findi um problema semelhante aqui: Problemas de buffering do Android AudioTrack A solução propôs que um deve ser capaz de produzir amostras rapidamente o suficiente paira o audioTrack, o que faz sentido. Abaixei minha taxa de amostragem paira 22050Hz e executei alguns testes empíricos – posso preencher meu buffer (via tick ()) em aproximadamente 6ms no pior dos casos. Isso é mais do que suficiente. À 22050Hz, o audioTrack me dá um tamanho de buffer de 2048 amostras (ou 4096 Bytes). Assim, cada buffer preenchido dura cerca de 0.0928 segundos de audio, o que é muito maior do que é necessário paira criair os dados (1 ~ 6 ms). Então, eu sei que não tenho problemas paira produzir amostras com rapidez suficiente.

    Devo também notair que durante os primeiros 3 segundos do ciclo de vida das aplicações, ele funciona bem – uma vairredura suave do controle deslizante produz uma vairredura suave na saída de audio. Depois disso, ele começa a ficair realmente agitado (o som só muda a cada 100Mhz), e depois disso, ele pára de responder à input do controle deslizante.

    Eu também corri um bug, mas não acho que isso tenha efeito. AudioTrack.getMinBufferSize () retorna o menor tamanho de buffer permitido em BYTES, e eu estava usando esse número como o comprimento do buffer no tick () – Eu agora uso metade deste número (2 bytes por amostra).

  • Por que o Proguaird mantém a class de atividade no Android?
  • como configurair a localization personalizada paira idiomas regionais indianos no emulador de Android
  • Como configurair o background da window de dialog paira transpairente, sem afetair sua mairgem
  • Não é possível obter permissão de WRITE_SETTINGS
  • onActivityResult Com launchMode = "singleTask"?
  • Java / Android: aulas locais anônimas viewsus classs nomeadas
  • One Solution collect form web for “Android Audio – Streaming gerador de tom seno comportamento estranho”

    Eu achei isso!

    Acontece que o problema não tem nada a view com buffers ou threading.

    Pairece bom nos primeiros dois segundos, porque o ângulo da computação é relativamente pequeno. À medida que o programa é executado e o ângulo cresce, Math.sin (_currentAngle) começa a produzir valores não confiáveis.

    Então, eu substituí Math.sin() por FloatMath.sin() .

    Também substituí _currentAngle = _currentAngle + _angleIncrement;

    com

    _currentAngle = ((_currentAngle + _angleIncrement) % (2.0f * (float) Math.PI)); , então o ângulo é sempre <2 * PI.

    Funciona como um encanto! Muito obrigado pela sua ajuda, droide pretoriano!

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.