2009-04-11 18 views
5

Durante l'esecuzione del codice riportato di seguito viene visualizzata una leggera distorsione (simile al ronzio). A causa della sua natura sottile, fa credere che ci sia una sorta di aliasing in corso con il byte casting.Rumore di fondo durante la generazione di onda sinusoidale in Java

Formato audio = PCM_SIGNED 44100,0 Hz, 16 bit, stereo, 4 byte/telaio, big-endian

Nota: codice presuppone (per ora) che i dati sono in grande endian.

public static void playFreq(AudioFormat audioFormat, double frequency, SourceDataLine sourceDataLine) 
{ 
    System.out.println(audioFormat); 
    double sampleRate = audioFormat.getSampleRate(); 
    int sampleSizeInBytes = audioFormat.getSampleSizeInBits()/8; 
    int channels = audioFormat.getChannels(); 

    byte audioBuffer[] = new byte[(int)Math.pow(2.0, 19.0) * channels * sampleSizeInBytes]; 

    for (int i = 0; i < audioBuffer.length; i+=sampleSizeInBytes*channels) 
    { 
     int wave = (int) (127.0 * Math.sin(2.0 * Math.PI * frequency * i/(sampleRate * sampleSizeInBytes * channels)) ); 

     //wave = (wave > 0 ? 127 : -127); 

     if (channels == 1) 
     { 
      if (sampleSizeInBytes == 1) 
      { 
       audioBuffer[i] = (byte) (wave); 
      } 

      else if (sampleSizeInBytes == 2) 
      { 
       audioBuffer[i] = (byte) (wave); 
       audioBuffer[i+1] = (byte)(wave >>> 8); 
      } 
     } 

     else if (channels == 2) 
     { 
      if (sampleSizeInBytes == 1) 
      { 
       audioBuffer[i] = (byte) (wave); 
       audioBuffer[i+1] = (byte) (wave); 
      } 

      else if (sampleSizeInBytes == 2) 
      { 
       audioBuffer[i] = (byte) (wave); 
       audioBuffer[i+1] = (byte)(wave >>> 8); 

       audioBuffer[i+2] = (byte) (wave); 
       audioBuffer[i+3] = (byte)(wave >>> 8); 
      } 
     } 
    } 

    sourceDataLine.write(audioBuffer, 0, audioBuffer.length); 
} 

risposta

7

I tuoi commenti dicono che il codice assume big-endian.

Tecnicamente sei realtà output in little-endian, tuttavia non sembra avere importanza perché attraverso un capriccio fortunato vostra byte più significativo è sempre 0.

EDIT: per spiegare che un ulteriore - quando il tuo valore è al suo valore massimo di 127, dovresti scrivere (0x00, 0x7f), ma l'output effettivo dal tuo codice è (0x7f, 0x00) che è 32512. Questo è vicino al valore massimo 16 bit di 32767, ma con gli 8 bit in basso tutti a zero. Sarebbe preferibile utilizzare sempre 32767 come valore massimo e quindi scartare gli 8 bit in basso se necessario.

Ciò significa che anche se si stanno inviando dati a 16 bit, la risoluzione effettiva è solo di 8 bit. Questo sembra spiegare la mancanza di qualità del suono.

Ho creato una versione del codice che scarica semplicemente i dati non elaborati in un file e non è in grado di vedere qualcosa che non va altrimenti con lo spostamento del bit stesso. Non ci sono cambiamenti inaspettati di segno o bit mancanti, ma c'è un ronzio coerente con la qualità del campione a 8 bit.

Inoltre, per quel che vale la matematica sarà più facile se si calcola l'equazione d'onda sulla base di conteggi di esempio, e poi preoccuparsi di scostamenti di byte separatamente:

int samples = 2 << 19; 
byte audioBuffer[] = new byte[samples * channels * sampleSizeInBytes]; 

for (int i = 0, j = 0; i < samples; ++i) 
{ 
    int wave = (int)(32767.0 * Math.sin(2.0 * Math.PI * frequency * i/sampleRate)); 
    byte msb = (byte)(wave >>> 8); 
    byte lsb = (byte) wave; 

    for (int c = 0; c < channels; ++c) { 
     audioBuffer[j++] = msb; 
     if (sampleSizeInBytes > 1) { 
      audioBuffer[j++] = lsb; 
     } 
    } 
} 
+0

Ah! Guarda l'errore ora, dopo aver corretto la parte di ampiezza l'errore è diventato molto evidente, ma anche il tuo codice è più efficiente. Grazie! – yxk

+0

Analisi ben fatte! –

2

Suppongo che stiate chiamando questo codice ripetutamente per riprodurre un suono lungo.

C'è una possibilità che l'onda che stai generando non sta per completare un periodo intero prima che sia scritta?

Se l'onda si "interrompe" prima che completi un periodo completo e poi l'onda successiva venga scritta nell'output, sentirai sicuramente qualcosa di strano e presumo che possa essere ciò che sta causando il ronzio.

Ad esempio:

 /-------\    /-------\    /-------\ 
    -----/   \  -----/   \  -----/   \ 
        \      \      \ 
        \-----     \-----     \----- 

Avviso scollamento tra parti di questa onda. Questo potrebbe causare il ronzio.

+0

Sì, non è che problema perché il buffer è abbastanza grande per il suono attraverso molti cicli. Rende conto del clic ma non per il ronzio costante. – yxk

+0

questa non è la risposta corretta - il codice genera chiaramente molti campioni e non c'è troncamento alla fine di ogni ciclo – Alnitak

+0

e ho testato il codice per verificare - si tratta di un errore di quantizzazione involontario a 8 bit che sta causando il ronzio. – Alnitak

Problemi correlati