Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Сборка WAV-файла

25K
03 июня 2008 года
Mein
17 / / 09.08.2007
Вот код:

В функцию засылаются внешние данные, пережевываются к формату 16 бит и выплёвываются в wav-файл

Код:
void SEISM_SIGNAL::SaveToWav(CArray<double,double> *data_array)
{
    CArray <int,int>WAVarray;
    WAVEFORMATEX m_pcm;
    double max=0;
   
    //Init PCM
    m_pcm.nChannels=2;
    m_pcm.nSamplesPerSec=freq;
    m_pcm.wBitsPerSample=16;
    m_pcm.wFormatTag=WAVE_FORMAT_PCM;
    m_pcm.nBlockAlign = m_pcm.nChannels * m_pcm.wBitsPerSample/8;
    m_pcm.nAvgBytesPerSec = m_pcm.nSamplesPerSec * m_pcm.nChannels * m_pcm.wBitsPerSample/8;

    //Приводим сигнал к формату 16бит
    for (int i=0; i<data_array->GetSize();i++)
    {
        double temp=data_array->GetAt(i);
        if (temp > max) max=temp;
    }
   
    double coeff=16383/max; //не нормализуем по максимуму, чтобы исключить переполнение

    for (i=0; i<data_array->GetSize();i++)
    {
        double temp=data_array->GetAt(i)*coeff;
        int val=(int)temp;
        WAVarray.Add(temp);
    }

    CFile f("1.wav", CFile::modeCreate | CFile::modeWrite);
       
    f.Write("RIFF", 4) ;
    DWORD dwFileSize = WAVarray.GetSize() * m_pcm.nBlockAlign + 36 ;
    f.Write(&dwFileSize, sizeof(dwFileSize)) ;
    f.Write("WAVEfmt ", 8) ;
    DWORD dwFmtSize = 16;
    f.Write(&dwFmtSize, sizeof(dwFmtSize)) ;
    f.Write(&m_pcm.wFormatTag, sizeof(m_pcm.wFormatTag)) ;
    f.Write(&m_pcm.nChannels, sizeof(m_pcm.nChannels)) ;
    f.Write(&m_pcm.nSamplesPerSec, sizeof(m_pcm.nSamplesPerSec)) ;
    f.Write(&m_pcm.nAvgBytesPerSec, sizeof(m_pcm.nAvgBytesPerSec)) ;
    f.Write(&m_pcm.nBlockAlign, sizeof(m_pcm.nBlockAlign)) ;
    f.Write(&m_pcm.wBitsPerSample, sizeof(m_pcm.wBitsPerSample)) ;
    f.Write("data", 4) ;
    DWORD dwNum = WAVarray.GetSize() * m_pcm.nBlockAlign;
    f.Write(&dwNum, sizeof(dwNum)) ;
    f.Write(WAVarray.GetData(),dwNum);

    f.Close();
}


Так работает более менее корректно: в левом канале данные, правый пустой (все значения - нулевые).
Фишка в том, что если собирать моно-сигнал:
 
Код:
m_pcm.nChannels=1;

То нули из правого канала перескакивают в левый и получается примерно следующая картина: отсчет, ноль, отсчет, ноль и т.д.
В чём тут может быть фишка?
401
05 июня 2008 года
Br@in RIPper
289 / / 15.02.2003
Чем отличается моно wav файл от стерео?
В моно выборки идут так: выборка1, выборка2, выборка3, ..., выборкаN
В стерео: выборкаRight1, выборкаLeft1, выборкаRight2, выборкаLeft2, выборкаRight3, выборкаLeft3, ..., выборкаRightN, выборкаLeftN.

В предоставленном коде я не нашел пересчета данных в зависимости от количества каналов.
Т.е. на выходе получаем: выборка1 (Right1), выборка2 (Left1), выборка3(Right2), выборка4(Left2) и т.д.

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

Нужно сначала преобразовать данные от стерео звука к моно. Самое простое - это выкинуть один из каналов, либо смикшировать 2 канала (среднее из двух выборок - левой и правой). При микшировании следует помнить, что если работаем с реальным аудио сигналом, то если он идет в 2х каналах в противофазе, то в результате микширования получим ноль :)

P.S.
Размер одной выборки в данном случае 2 байта (16 бит). Надо помнить, что если будем менять формат с 16 бит на 8 бит, соответственно надо перелопатить и буфер данных
25K
05 июня 2008 года
Mein
17 / / 09.08.2007
Тут есть одномерный массив с данными (целые числа), которые просто последовательно рисуются в файл.
Один за одним. Последовательно.
В стерео первой идёт "левая" выборка. Но это действительно, не суть важно.
На входе НЕТ файла, ни стерео ни моно. Он СОБИРАЕТСЯ из отсчетов. При этом корректно работает только стерео сборка.
401
05 июня 2008 года
Br@in RIPper
289 / / 15.02.2003
Суть в том, какие данные данные лежат во входном одномерном массиве.
Проще говоря этот одномерный массив трактуется по разному при сборке в стерео и моно WAV файлов.

В случае стерео массив данных состоит из структур
struct STEREO_SAMPLE
{
short leftSample;
short rightSample;
};

В случае моно -
struct MONO_SAMPLE
{
short monoSample;
};

каждая структура (элемент массива структур) - это одна выборка.

Если на входе одномерный массив, с выборками для 2х каналов (левый/правый), перед тем как писать в файл нужно этот массив преобразовать в моно.

Может я не правильно понял суть проблемы? Чего собственно нужно добиться?
25K
05 июня 2008 года
Mein
17 / / 09.08.2007
Это-то и так понятно )

Если утрировать до "на пальцах", то
есть массив {1,2,3,4,5,6,7} (WAVarray)
физически он представляет собой целочисленные отсчеты, полученные от сейсмического датчика

Этот массив надо представить в виде моно wav-файла.
401
05 июня 2008 года
Br@in RIPper
289 / / 15.02.2003
а в чем проблема?
401
05 июня 2008 года
Br@in RIPper
289 / / 15.02.2003
А, кажется я понял. Дело в том, что в качестве одной выборки записывается int, который имеет размерность 4 байта, т.е. две выборки. Следовательно, если значение этого int'а меньше 65535, то вторая, фантомная, выборка будет равна нулю.

WAVarray надо определять как
CArray <short,short>WAVarray;

т.е. длина элемента массива (в байтах) должна быть равна битности WAV файла, в данном случае 16 бит
25K
05 июня 2008 года
Mein
17 / / 09.08.2007
Да, действительно!
Жара в офисе неблагоприятно сказывается на деятельность серого вещества.
Br@in RIPper, Спасибо!

Тему можно считать закрытой
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог