Общие сведения

Предыдущая  Содержание  Следующая  V*D*V

При синтезе результатом работы является поток звуковых данных, которые далее можно либо проиграть, либо записать как звуковой файл.

 

PCM wav файл имеет простую структуру, состоящую из заголовка и данных.

Заголовок

Заголовок содержит информацию, позволяющую определить, как надо работать с данными.

 

wav_header = {'R', 'I', 'F', 'F',//sRIFF [4]

                  0, 0, 0, 0,//riff_size//full_size - 8

                  'W', 'A', 'V', 'E', 'f', 'm', 't', ' ',//sWAVEfmt[8]

                  0x10, 00, 00, 00,//nExt

                  0x01, 00,//wFormatTag

                  0x01, 00,//nChannels

                  0x11, 0x2B, 00, 00,//nSamplesPerSec

                  0x11, 0x2B, 00, 00,//nAvgBytesPerSec

                  0x01, 00,//nBlockAlign

                  0x08, 00,//wBitsPerSample

                  'd', 'a', 't', 'a',//sdata[4]

                  00, 00, 00, 00};//data_size//full_size - 44

 

Поля заголовка. Для всех полей младший байт - первый:

sRIFF - текстовое поле "RIFF". 4 байта.

RIFF size - 4 байта, определяющие размер идущих дальше данных. RIFF size = полное число данных в байтах (включая заголовок) - 8.

sWAVEfmt - текстовое поле "WAVEfmt ", 8 байт.

nExt - дополнительное поле. 4 байта. Для PCM файла 0x00000010.

wFormatTag - поле, определяющее алгоритм компрессии. 2 байта. Для PCM файла 0x00000001.

nChannels - число каналов. 2 байта.

nSamplesPerSec - число сэмплов в секунду. 4 байта. nSamplesPerSec = частота дискретизации.

nAvgBytesPerSec - число байтов в секунду. 4 байта. nAvgBytesPerSec = частота дискретизации * число каналов * ( число бит в сэмпле / 8 ).

nBlockAlign - число байтов на блок данных. 2 байта. nBlockAlign = число бит в сэмпле / 8 * число каналов.

wBitsPerSample - число битов в сэмпле. 2 байта.

sdata - текстовое поле "data". 4 байта.

data size - размер данных. data size = полное число данных в байтах (включая заголовок) - 44.

Звук

Звуковые данные располагаются после заголовка и представляют собой просто числовые значения отсчетов.

Для 8-ми битных данных средним уровнем считается число 128. Таким образом, числу 0 соответствует -128 (минимальное значение), числу 255 соответствует 127 (максимальное значение).

Для 16-ти битных данных средним уровнем считается число 0. Таким образом, -32768 - минимальное значение, 32767 - максимальное.

 

Пример, стерео, 16 бит:

л1, п1, л2, п2, л3, п3...

Реализация

public final class Snd

{

   private static int m_sampleRate = 32000;

   //

   //private static final int RIFF = 0;

  private static final int RIFF_SIZE = 4;

  //private static final int WAVE_FMT = 8;

  //private static final int EXT = 16;

  //private static final int FORMAT_TAG = 20;

  private static final int CHANNELS = 22;

  private static final int SAMPLES_PER_SEC = 24;

  private static final int AVG_BYTES_PER_SEC = 28;

  private static final int BLOCK_ALIGN = 32;

  private static final int BITS_PER_SAMPLE = 34;

  //private static final int SDATA = 36;

  private static final int DATA_SIZE = 40;

  private static byte[] wav_header = {'R', 'I', 'F', 'F',//sRIFF [4]

                           0, 0, 0, 0,//riff_size//full_size - 8

                          'W', 'A', 'V', 'E', 'f', 'm', 't', ' ',//sWAVEfmt[8]

                           0x10, 00, 00, 00,//nExt

                           0x01, 00,//wFormatTag

                           0x01, 00,//nChannels

                           0x11, 0x2B, 00, 00,//nSamplesPerSec

                           0x11, 0x2B, 00, 00,//nAvgBytesPerSec

                           0x01, 00,//nBlockAlign

                           0x08, 00,//wBitsPerSample

                          'd', 'a', 't', 'a',//sdata[4]

                           00, 00, 00, 00};//data_size//full_size - 44

  //

  public static void setSoundFormat(int sampleRate, int bitPerSample, int channels) {

       m_sampleRate = sampleRate;

      valueToByte( sampleRate, 4, wav_header, SAMPLES_PER_SEC );

      valueToByte( sampleRate * channels * ( bitPerSample / 8 ), 4, wav_header, AVG_BYTES_PER_SEC );

      valueToByte( bitPerSample, 2, wav_header, BITS_PER_SAMPLE );

      valueToByte( bitPerSample * channels / 8, 2, wav_header, BLOCK_ALIGN );

      valueToByte( channels, 2, wav_header, CHANNELS );

   }

  public static int getSampleRate() { return m_sampleRate; }

  public static void valueToByte(long value, int byteCount, byte[] data, int offset) {

       for(int i = 0; i < byteCount; i++)

           data[offset++] = (byte) (value >> (i << 3));

   }

  public static void writeHeader(byte[] snd) {

       System.arraycopy( wav_header, 0, snd, 0, wav_header.length );

       Snd.valueToByte( snd.length - 8, 4, snd, RIFF_SIZE );

       Snd.valueToByte( snd.length - wav_header.length, 4, snd, DATA_SIZE );

   }

   public static byte[] toSndStream(short[] d) {

       byte[] b = new byte[d.length * 2 + wav_header.length];

       for( int i = wav_header.length, k = 0; i < b.length; ) {

           int s = (int)d[k++];

           b[i++] = (byte)s;

           b[i++] = (byte)(s>>8);

       }

       Snd.writeHeader( b );

       return b;

  }

  public static byte[] toSndStream(double[] d) {

       byte[] b = new byte[d.length * 2 + wav_header.length];

       for( int i = wav_header.length, k = 0; i < b.length; ) {

           int s = (int)d[k++];

           b[i++] = (byte)s;

           b[i++] = (byte)(s>>8);

       }

       Snd.writeHeader( b );

       return b;

  }

}

 

Предыдущая  Содержание  Следующая