Вопрос: наложение эффекта "эхо" на wav файлы

Тема в разделе "MS Visual C++", создана пользователем Firefox, 15 ноя 2010.

  1. Firefox

    Firefox Гость

    Здравствуйте. мне необходимо внести в файл со звуком(речь) в формате wav эхо. данные звуковые сохранила в массив байтов. чтоб внести эхо необходимо сделать сдвиг по времени и наложить их ещё раз. смотрела пример из книги по звуку("Программирование звука на pc" 2001г) не поняла если честно. в других источника нигде больше не могу найти ничего по этому поводу. есть много готовых программ ревербераторов с такой функцией, но кода от них тоже в нете не найти. Подскажите как решить такую проблемку.
     
  2. DarkKnight

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    Я если честно с этим вопросом никогда не сталкивался, так что с ходу сказать не могу, но если выложишь ссылку на книгу, то помогу....
     
  3. Firefox

    Firefox Гость

    http://progbook.ru/c/630-sekunov-obrabotka-zvuka-na-pc.html вот эта книга. там много классов наследуется и нет комментариев к переменным в классах. гн понимаю например что они берут за n,n1,n2.
     
  4. DarkKnight

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    Щас откачаю... Почитаю и к вечеру что-нить скажу.... Наверно ;-)

    Добавлено: В том смысле, что, если сам сращу ;-))
     
  5. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    Какие-нибудь наброски делали?

    Добавлено:
    Файл моно? 16-бит или 8 ? (от этого зависит способ реализации)
     
  6. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    Допустим:
    S - количество сэмплов в массиве.
    N - количество повторов эхо.
    K - коэффециент затухания. тип double. от 0 до 1.
    signed short src[1024] - массив сэмплов формата 16-бит моно.
    signed short dst[1024] - массив такого же размера (кстати может быть и больше, но не для этого алгоритма). В него мы будем помещать то что у нас получится.

    При условии что:
    sizeof( short ) == 2

    Получаем примерно следующее:
    Код (C++):
    memset( dst, 0, S * sizeof( short ) );
    for ( j = 0; j < N; j++ ) {
    offset = (double)j / N * S; // смещение накладываемой копии
    for ( i = 0; i < S; i++ ) {
    k = offset + i; // смещение накладываемого сэмпла

    // чтобы не выйти за пределы массива (можно сделать лучше)
    if ( k < S ) {
    // накладываем немного приглушенную копию
    dst[offset] += floor( (double)src[i] / ((double)(j + 1) * K + 1) );
    }
    }
    }
    Прошу заметить что это не опробованный алгоритм. Возможно я что-то не досмотрел.. В общем на свой страх и риск. Если выйдет черепаха - просьба камни не кидать!
     
  7. DarkKnight

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    Если честно, книга мне на первый взгял очень не понравилась, грубо все как то, больше учебник по физике, чем литература по программированию....
    С эхом, нужно подумать еще, скорее всего lazybiz прав про алгоритм, но все как он и сказал зависит именно от формата... Я завтра проверю, щас дома, нет возможности, да и спать охото.... А что бы у тебя после книги мозги на место встати, вот код, как данные получить, и воспроизвести их.... Использовал DX в примере.

    Код (C++):
    #include <iostream>
    #include <Windows.h> // Нам она понадобится для структуры WAVEFORMATEX
    #include <dsound.h> //Подгрузим DirectX Sound я другими путями звук не вывожу
    #include <fstream> //Файловые поток

    #pragma comment(lib,"dsound.lib") //Либка саунда DX


    using namespace std;

    ::IDirectSound8 *pDirectSound; //Глобально определим интерфес

    void main(void)
    {
    setlocale(LC_ALL,"Russian"); //Локаль
    ::DirectSoundCreate8(0,&pDirectSound,NULL); //Использовать будем 8-е иксы
    pDirectSound->SetCooperativeLevel(::GetForegroundWindow(),DSSCL_NORMAL); //Закажем уровень доступа как стандартный


    ifstream file("C:/1.wav",ios::beg | ios::in|ios::binary); //Наша wav'ка
    if (!file) cout<<"Не удалось открыть файл"<<endl;

    DWORD dwRIFF = 0; //И так идет формат wav-файла, он относится к RIFF-файлам, поэтому читаем 4 байта структуы
    file.read((char*) &dwRIFF,4);
    if (dwRIFF != MAKEFOURCC('R','I','F','F')) //Если RIFF не получили, то значит какую то залепу открыли
    {
    cout<<"Файл не является RIFF - formated"<<endl;
    return;
    }

    file.ignore(4); //Пропустим 4 байта там какая то охинея нам совершенно не нужна
    DWORD dwWave = 0; //Секция WAVE
    DWORD dwFormat = 0; // Секция fmt /формат файла/
    long lSizeFmt = 0; //Размер секции fmt

    file.read((char*)&dwWave,4); //Читаем 4 байта, там для Wav-файла должно быть название секции WAVE
    if (dwWave != MAKEFOURCC('W','A','V','E')) //Проверим
    {
    cout<<"Файл не имеет секции WAVE"<<endl;
    return;
    }

    file.read((char*)&dwFormat,4); //Если все ОК... То читаем
    if (dwFormat != MAKEFOURCC('f','m','t',' ')) //Если секция fmt - не найдена
    {
    cout<<"Файл не имеет Format(fmt)-Секции "<<endl;
    return;
    }
    file.read((char*)&lSizeFmt,4); //Еще читаем 4 байта, там у нас размер секции формат, где идет сам формат + может идти всякая охинея, формат лежит в 16 байтах
    WAVEFORMATEX WaveFormat = WAVEFORMATEX(); //Определим структуру винды
    file.read((char*)&WaveFormat,16); //Прочитаем ее
    file.ignore(lSizeFmt-16); //Пропустим охинею
    if (WaveFormat.wFormatTag != 1) //Если таг <>1 то значит есть компрессия файла, ее разбирать мы не будем, работаем не с жатыми данными
    {
    cout<<"Файл имеет компрессию"<<endl;
    return;
    }

    DWORD dwSection = 0; //Следующая секция у нас или fact(Не обязательная) или data(это как раз наш звук)
    file.read((char*)&dwSection,4); //Читаем заголовок
    if (dwSection == MAKEFOURCC('f','a','c','t')) //Если все же fact - то пропускаем ее
    {
    cout<<"Файл имеет секцию fact"<<endl;
    DWORD dwSizeFact = 0;
    file.read((char*)&dwSizeFact,4);
    file.ignore(dwSizeFact);
    file.read((char*)&dwSection,4);
    }

    if (dwSection != MAKEFOURCC('d','a','t','a')) //Ну а теперь сама data - это то, над чем мы будем работать
    {
    cout<<"Не найдена секция data"<<endl;
    return;
    }
    DWORD dwDataSize =0;
    file.read((char*)&dwDataSize,4); //Прочитаем ее размер
    char *pData = new char[dwDataSize]; //Динамически выделим переменную типа char[размер звуковых данных]
    file.read(pData,dwDataSize); //Прочитаем в нее все звуковые данные
    file.close(); //Закроем файл, он нам уже не нужен, у нас есть pData

    ::IDirectSoundBuffer *pSoundBuffer; //Определим указатель на звуковой буфер DX-а
    ::DSBUFFERDESC dsBuffer = DSBUFFERDESC(); //Структура формата буфера
    //Заполни ее
    dsBuffer.dwBufferBytes = dwDataSize; //Сколько инфы (в байтах)
    dsBuffer.dwFlags = DSBCAPS_STATIC; //Флаг буфера, у нас буфер как статичный (может быть поточным)
    dsBuffer.dwSize = sizeof(DSBUFFERDESC); //Размер структуры, как любят ребята из Microsoft
    dsBuffer.lpwfxFormat = &WaveFormat; //Формат буфера, мы как раз запишим туда сведения из Wav-Format

    pDirectSound->CreateSoundBuffer(&dsBuffer,&pSoundBuffer,NULL); //Создадим буфер

    void *pDst = 0;
    DWORD dwSize = 0;
    pSoundBuffer->Lock(0,0,&pDst,&dwSize,0,0,DSBLOCK_ENTIREBUFFER);//Заблокируем буфер
    memcpy(pDst,pData,dwSize); //Запишим нашу pData в него
    pSoundBuffer->Unlock(pDst,dwSize,0,0); //Разблокируем
    pSoundBuffer->Play(0,0,0); //Начнем грать

    DWORD hrStatus = 0;
    do
    {
    pSoundBuffer->GetStatus(&hrStatus); //В цикле получаем статус
    }
    while (hrStatus == DSBSTATUS_PLAYING); //выполнять : Пока статус "Грает"

    pDirectSound->Release(); //Освободим интерфейс
    pDirectSound = NULL;
    }
    Вообщем завтра продолжу описание....
     
  8. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    Только что вспомнил что давным давно видел простой пример в Winamp SDK. Вот наглядный пример:

    Код (C++):
    int modify_samples1(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate)
    {
    // echo doesn't support 8 bit right now cause I'm lazy.
    if (bps==16)
    {
    int x,s;
    s = numsamples*nch;

    memcpy(echo_buf2,     echo_buf,   s*2);
    memcpy(echo_buf,        echo_buf+s,  s*2);
    memcpy(echo_buf+s,   echo_buf+s*2, s*2);
    memcpy(echo_buf+s*2,echo_buf+s*3, s*2);
    memcpy(echo_buf+s*3,samples, s*2);

    for (x = 0; x < s; x ++)
    {
    int s = samples[x]/2+echo_buf2[x]/2;
    samples[x] = (s>32767?32767:s<-32768?-32768:s);
    }
    }
    return numsamples;
    }
    Скачать можно отсюда: http://download.nullsoft.com/winamp/plugin.../WA5.55_SDK.exe
     
  9. DarkKnight

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    Да, принцип как раз такой как Лайзи описал.....
    Вот я реализацию свою доработал, щас расскажу от чего отталкивался...
    Вообщем сам принцип эхо - это отражающая волна (которая при отражении само собой иммет потери), зависит отражение от того на каком расстоянии стоит отражающая поверхность :) Ну про скорость звука не буду ничего говорить, при потери из-за плотности воздуха тоже ;-)
    Вообщем основное - это коэффициент этого затухания.. Пошла 1 - вернулась например 0.7....
    Следовательно нам нужно перезаписывать(повторять) данные через равный промежуток времени(скорость звука же не меняется), но с разным коэффициентом...

    Для примера я выбрал на абум (3 эха (с коэффициентами 0.6 0.3 0.1) волна возвращается за 0.5 секунды, и того наша композиция должна вырасти ровно на 1.5 секунд (3*0.5)
    В реализации не буду использовать ни циклы, но новые переменные, ни сдвиги (для наглядности)
    Если есть недочеты в реализации, или все же принцип формирования эха - совершенно другой, сразу извиняюсь, потому как сам додумывал, мог и ошибатся в выводах.

    Код (C++):
    #include <iostream>
    #include <Windows.h> // Нам она понадобится для структуры WAVEFORMATEX
    #include <dsound.h> //Подгрузим DirectX Sound я другими путями звук не вывожу
    #include <fstream> //Файловые поток

    #pragma comment(lib,"dsound.lib") //Либка саунда DX


    using namespace std;

    ::IDirectSound8 *pDirectSound; //Глобально определим интерфес

    void main(void)
    {
    setlocale(LC_ALL,"Russian"); //Локаль
    ::DirectSoundCreate8(0,&pDirectSound,NULL); //Использовать будем 8-е иксы
    pDirectSound->SetCooperativeLevel(::GetForegroundWindow(),DSSCL_NORMAL); //Закажем уровень доступа как стандартный


    ifstream file("C:/2.wav",ios::beg | ios::in|ios::binary); //Наша wav'ка
    if (!file) cout<<"Не удалось открыть файл"<<endl;

    DWORD dwRIFF = 0; //И так идет формат wav-файла, он относится к RIFF-файлам, поэтому читаем 4 байта структуы
    file.read((char*) &dwRIFF,4);
    if (dwRIFF != MAKEFOURCC('R','I','F','F')) //Если RIFF не получили, то значит какую то залепу открыли
    {
    cout<<"Файл не является RIFF - formated"<<endl;
    return;
    }

    file.ignore(4); //Пропустим 4 байта там какая то охинея нам совершенно не нужна
    DWORD dwWave = 0; //Секция WAVE
    DWORD dwFormat = 0; // Секция fmt /формат файла/
    long lSizeFmt = 0; //Размер секции fmt

    file.read((char*)&dwWave,4); //Читаем 4 байта, там для Wav-файла должно быть название секции WAVE
    if (dwWave != MAKEFOURCC('W','A','V','E')) //Проверим
    {
    cout<<"Файл не имеет секции WAVE"<<endl;
    return;
    }

    file.read((char*)&dwFormat,4); //Если все ОК... То читаем
    if (dwFormat != MAKEFOURCC('f','m','t',' ')) //Если секция fmt - не найдена
    {
    cout<<"Файл не имеет Format(fmt)-Секции "<<endl;
    return;
    }
    file.read((char*)&lSizeFmt,4); //Еще читаем 4 байта, там у нас размер секции формат, где идет сам формат + может идти всякая охинея, формат лежит в 16 байтах
    WAVEFORMATEX WaveFormat = WAVEFORMATEX(); //Определим структуру винды
    file.read((char*)&WaveFormat,16); //Прочитаем ее
    file.ignore(lSizeFmt-16); //Пропустим охинею
    if (WaveFormat.wFormatTag != 1) //Если таг <>1 то значит есть компрессия файла, ее разбирать мы не будем, работаем не с жатыми данными
    {
    cout<<"Файл имеет компрессию"<<endl;
    return;
    }

    DWORD dwSection = 0; //Следующая секция у нас или fact(Не обязательная) или data(это как раз наш звук)
    file.read((char*)&dwSection,4); //Читаем заголовок
    if (dwSection == MAKEFOURCC('f','a','c','t')) //Если все же fact - то пропускаем ее
    {
    cout<<"Файл имеет секцию fact"<<endl;
    DWORD dwSizeFact = 0;
    file.read((char*)&dwSizeFact,4);
    file.ignore(dwSizeFact);
    file.read((char*)&dwSection,4);
    }

    if (dwSection != MAKEFOURCC('d','a','t','a')) //Ну а теперь сама data - это то, над чем мы будем работать
    {
    cout<<"Не найдена секция data"<<endl;
    return;
    }
    DWORD dwDataSize =0;
    file.read((char*)&dwDataSize,4); //Прочитаем ее размер
    char *pData = new char[dwDataSize]; //Динамически выделим переменную типа char[размер звуковых данных]

    file.read(pData,dwDataSize); //Прочитаем в нее все звуковые данные
    file.close(); //Закроем файл, он нам уже не нужен, у нас есть pData

    //И так реализация эха
    char *pDataEcho = new char[dwDataSize+int(1.5*WaveFormat.nAvgBytesPerSec)]; //Введем новую указатель на данные и увеличим его на 1.5(секунды) * Байты в секунду
    memset(pDataEcho,0,dwDataSize+1.5*WaveFormat.nAvgBytesPerSec); //обнулим его
    for (int i = 0; i<dwDataSize; i++) //Обходим весь массив (исходных данных) которые из файла вытащили
    {
    //Теперь по принципу сумматора складываем данные
    pDataEcho[i] += pData[i]; //Текущий байт (исходны) данных
    pDataEcho[i+int(0.5*WaveFormat.nAvgBytesPerSec)]+= 0.6 * pData[i]; //Сдвигаем на 0.5 секунд и слогаем текущий(исходный) байт * на коэффициент первого затухания
    pDataEcho[i+int(1*WaveFormat.nAvgBytesPerSec)]+= 0.3 * pData[i]; //Сдвигаем на 1 секунду и так же (только коэффициент 0.3)
    pDataEcho[i+int(1.5*WaveFormat.nAvgBytesPerSec)]+= 0.1 * pData[i]; //И последняя волна через 1.5 секунды которая дойдет (коэф. 0.1) -почти не ощутимый
    }
    pData = pDataEcho; //Заменим данные
    dwDataSize+=WaveFormat.nAvgBytesPerSec; //Увеличим размер, что бы DS прочитал добавление 1.5 секунды
    //Ну вот и все... Эхо - не реальное, в природе наверное такого добится не возможно, но я же для примера только


    ::IDirectSoundBuffer *pSoundBuffer; //Определим указатель на звуковой буфер DX-а
    ::DSBUFFERDESC dsBuffer = DSBUFFERDESC(); //Структура формата буфера
    //Заполни ее
    dsBuffer.dwBufferBytes = dwDataSize; //Сколько инфы (в байтах)
    dsBuffer.dwFlags = DSBCAPS_STATIC; //Флаг буфера, у нас буфер как статичный (может быть поточным)
    dsBuffer.dwSize = sizeof(DSBUFFERDESC); //Размер структуры, как любят ребята из Microsoft
    dsBuffer.lpwfxFormat = &WaveFormat; //Формат буфера, мы как раз запишим туда сведения из Wav-Format

    pDirectSound->CreateSoundBuffer(&dsBuffer,&pSoundBuffer,NULL); //Создадим буфер

    void *pDst = 0;
    DWORD dwSize = 0;
    pSoundBuffer->Lock(0,0,&pDst,&dwSize,0,0,DSBLOCK_ENTIREBUFFER);//Заблокируем буфер
    memcpy(pDst,pData,dwSize); //Запишим нашу pData в него
    pSoundBuffer->Unlock(pDst,dwSize,0,0); //Разблокируем
    pSoundBuffer->Play(0,0,0); //Начнем грать

    DWORD hrStatus = 0;
    do
    {
    pSoundBuffer->GetStatus(&hrStatus); //В цикле получаем статус
    }
    while (hrStatus == DSBSTATUS_PLAYING); //выполнять : Пока статус "Грает"

    pDirectSound->Release(); //Освободим интерфейс
    pDirectSound = NULL;

    }
     
  10. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    DarkKnight125
    Там не плохо бы было добавить условие проверки, чтобы сумма всех эхо не вышла за пределы возможно допустимых значений.
    Но от этого не будет толку до тех пор пока мы будем прибавлять сразу в буфер. Нужно ввести какую-то переменную.
    Например:
    Код (C++):
    for (int i = 0; i<dwDataSize; i++) {
    signed long sum;
    sum = pData[i];
    sum += pData[i + int(0.5*WaveFormat.nAvgBytesPerSec)];
    sum += pData[i + int(1.0*WaveFormat.nAvgBytesPerSec)];
    pDataEcho[i] = (sum > 32767 ? 32767 : sum < -32768 ? -32768 : sum);
    }
    Это не рабочий кусок кода! Это пример того что я имею в виду! Весь смысл в последней строке.
    DarkKnight125 для твоей реализации он не подойдет, т.к. ты считаешь все эхо за один прием. Придется немного менять код.


    Добавлено: DarkKnight125
    И еще не совсем понял, ты оперируешь байтами, у тебя wav-ка 8-битная? Если да то вопросов нет)) В целом пример очень наглядный)
     
  11. DarkKnight

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    А тут разнице же нет Лайз, без разницы 8бит или 16, это только будет влият на время эхи, а так эхо будет по всем каналам не зависимо от размерности...
    Все равно на 1 канал отводится только 1 байт.....
     
  12. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    Я в том смысле что 8-битные форматы мало уже где используются))
     
  13. DarkKnight

    DarkKnight Well-Known Member
    C\C++ Team

    Регистрация:
    1 авг 2010
    Сообщения:
    653
    Симпатии:
    0
    ;-))) Я использую ;-))) Когда с гитары напрямую пишу через виндовскую звукозапись ;-))))))))))))))))) Адское качество ;-))))
     
  14. Firefox

    Firefox Гость

    Всем большое спасибо))завтра на работе буду юзать. ато мне на работе наговорили математики про преобразования фурье и свёртки разного рода. читала - голова пухнет.
     
  15. Firefox

    Firefox Гость

    Подскажите пожалуйста, создаю новый файл и записываю в него данные считанные, но файл не проигрывается в итоге, где ошибка(думаю где-то в размере одного из блоков).
    Код (C++):
    LPTSTR m_FileName=L"sound1.wav";
    HMMIO m_pFile;
    MMRESULT mmReturn = 0;
    m_pFile = ::mmioOpen(m_FileName,NULL, MMIO_CREATE|MMIO_WRITE|MMIO_EXCLUSIVE | MMIO_ALLOCBUF);
    if(m_pFile == NULL)
    {
    //m_Mode = FILE_ERROR;
    return FALSE;
    }
    MMCKINFO    m_MMCKInfoParent;
    m_MMCKInfoParent.cksize=0;
    ZeroMemory(&m_MMCKInfoParent, sizeof(MMCKINFO));
    m_MMCKInfoParent.fccType = mmioFOURCC('W','A','V','E');
    MMRESULT mmResult;
    mmResult= ::mmioCreateChunk( m_pFile,&m_MMCKInfoParent, MMIO_CREATERIFF);
    if(mmResult!=MMSYSERR_NOERROR)
    {
    ::MessageBox(NULL,L"Ошибка при создании сегмента wave", L"Ошибка",MB_OK|MB_SYSTEMMODAL);
    mmReturn=::mmioClose(m_pFile,NULL);
    return false;
    }
    if(mmioAscend(m_pFile,&m_MMCKInfoParent,0)!=MMSYSERR_NOERROR)
    {
    ::MessageBox(NULL,L"Ошибка при зактытии сегмента wave", L"Ошибка",MB_OK|MB_SYSTEMMODAL);
    mmReturn=::mmioClose(m_pFile,NULL);
    return false;
    }

    MMCKINFO    m_MMCKInfoChild;
    ZeroMemory(&m_MMCKInfoChild, sizeof(MMCKINFO));
    m_MMCKInfoChild.ckid=mmioFOURCC('f','m','t',' ');
    mmResult= ::mmioCreateChunk( m_pFile,&m_MMCKInfoChild, NULL);
    if(mmResult!=MMSYSERR_NOERROR)
    {
    ::MessageBox(NULL,L"Ошибка при создании сегмента fmt", L"Ошибка",MB_OK|MB_SYSTEMMODAL);
    mmReturn=::mmioClose(m_pFile,NULL);
    return false;
    }
    m_MMCKInfoChild.cksize=sizeof(WAVEFORMATEX);
    int cksize=m_MMCKInfoChild.cksize;

    mmResult = ::mmioWrite(m_pFile, (char*)&m_Format,MMCKInfoChild. cksize);
    if (mmResult!=cksize)
    {
    ::MessageBox(NULL,L"Ошибка при создании сегмента fmt и записи его содержмого", L"Ошибка",MB_OK|MB_SYSTEMMODAL);
    mmReturn=::mmioClose(m_pFile,NULL);
    return false;
    }
    if(mmioAscend(m_pFile,&m_MMCKInfoChild,0)!=MMSYSERR_NOERROR)
    {
    ::MessageBox(NULL,L"Ошибка при зактытии сегмента fmt", L"Ошибка",MB_OK|MB_SYSTEMMODAL);
    mmReturn=::mmioClose(m_pFile,NULL);
    return false;
    }

    m_MMCKInfoChild.ckid=mmioFOURCC('f','a','c','t');

    mmResult= ::mmioCreateChunk( m_pFile,&m_MMCKInfoChild, NULL);
    if(mmResult!=MMSYSERR_NOERROR)
    {
    ::MessageBox(NULL,L"Ошибка при создании сегмента fact", L"Ошибка",MB_OK|MB_SYSTEMMODAL);
    mmReturn=::mmioClose(m_pFile,NULL);
    return false;
    }
    mmResult = ::mmioWrite(m_pFile, (char*)&m_Format, sizeof(DWORD));
    if (mmResult!=sizeof(DWORD))
    {
    ::MessageBox(NULL,L"Ошибка при создании сегмента fact и записи его содержмого",L"Ошибка",MB_OK|MB_SYSTEMMODAL);
    mmReturn=::mmioClose(m_pFile,NULL);
    return false;
    }
    if(mmioAscend(m_pFile,&m_MMCKInfoChild,0)!=MMSYSERR_NOERROR)
    {
    ::MessageBox(NULL,L"Ошибка при зактытии сегмента fact", L"Ошибка",MB_OK|MB_SYSTEMMODAL);
    mmReturn=::mmioClose(m_pFile,NULL);
    return false;
    }
    m_MMCKInfoChild.ckid=mmioFOURCC('d','a','t','a');
    m_MMCKInfoChild.fccType=NULL;
    m_MMCKInfoChild.cksize =dwDataSize+sizeof('data');
    mmResult= ::mmioCreateChunk( m_pFile,&m_MMCKInfoChild, NULL);
    if(mmResult!=MMSYSERR_NOERROR)
    {
    ::MessageBox(NULL,L"Ошибка при создании сегмента data", L"Ошибка",MB_OK|MB_SYSTEMMODAL);
    mmReturn=::mmioClose(m_pFile,NULL);
    return false;
    }
    if(ui.pushButton->isChecked())
    {
    mmioWrite(m_pFile,pData,dwDataSize);
    }
    if(mmioAscend(m_pFile,&m_MMCKInfoChild,0)!=MMSYSERR_NOERROR)
    {
    ::MessageBox(NULL,L"Ошибка при зактытии сегмента data", L"Ошибка",MB_OK|MB_SYSTEMMODAL);
    mmReturn=::mmioClose(m_pFile,NULL);
    return false;
    }
    mmioClose(m_pFile,0);
    пробовала разные размеры блоков писать(0, sizeof(WAVEFORMATEX)) но не выходит.Как я поняла что при использовании функции mmioAscend размер должен автоматически заполняться или нет?
     
  16. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    Вот с этими mmio я, честно говоря, дел ни разу не имел..
    Посмотри в прикрепленном файле, возможно поможет разобраться.
     

    Вложения:

    • RTCompress.zip
      Размер файла:
      11,6 КБ
      Просмотров:
      15
  17. Firefox

    Firefox Гость

    Пробовала ваш пример, но тоже не воспроизводится файл. У меня просто проблема из предыдущего примера по созданию эха, там при воспроизведении файла средствами DirectSound блокируется у меня программа, а так как у меня в это время идет обмен данными по сети с другими программами это очень плохо. может быть можно как-то воспроизводить чтоб не происходило блокировки интерфейса и процессов. я решила сделать запись в файл и воспроизводить средствами Qt(делаю работу с использованием этой библиотеки), так как функции работы со звуком там ничего не блокируют. Подскажите пожалуйста. впервые столкнулась с обработкой звука, и до нового года надо решить эту проблему.
     
  18. Firefox

    Firefox Гость

    Спасибо. уже сделала но никак не могу домой принести чтоб выложить целиком))надеюсь после праздников скину прогу. может кому понадобиться.
    Код (C++):
    // .cpp - чтение из файла, внесение эхо, добавление шума, запись в новый файл
    #include "record.h"
    #define N2 22050
    using namespace std;
    ::IDirectSound8 *pDirectSound; //Глобально определим интерфес
    bool flag_record=0;
    DWORD dwDataSize =0;
    DWORD fact1=0;
    //write
    HMMIO       hmmioOut = NULL; // handle to open output WAVE file
    MMCKINFO      ckOutRIFF;
    MMCKINFO      ckOut;     
    PCMWAVEFORMAT pcmWaveFormat;
    MMIOINFO      mmioinfoOut;  
    long         lSamples; // number of samples

    //

    record::record(QWidget *parent, Qt::WFlags flags)
    : QWidget(parent, flags)
    {
    ui.setupUi(this);
    m_hRecord=NULL;

    }

    record::~record()
    {

    }

    void record::on_pushButton_clicked(bool bn)
    {
    if(bn==true)
    {
    func(1, "Sound10.wav");
    }
    else flag_record=0;
    ui.pushButton->setChecked(false);

    }
    bool record::func(int isk, QString File_name_record)
    {
    File_Name="out.wav";
    QFile outfile(File_Name);


    setlocale(LC_ALL,"Russian"); //Локаль
    ::DirectSoundCreate8(0,&pDirectSound,NULL); //Использовать будем 8-е иксы
    pDirectSound->SetCooperativeLevel(::GetForegroundWindow(),DSSCL_NORMAL); //Закажем уровень доступа как стандартный


    ifstream file("D:\\Sounds\\Iskaz0\\Sound6.wav"/*File_name_record*/,ios::beg | ios::in|ios::binary); //Наша wav'ка
    if (!file)
    QMessageBox::warning(0,"error","error open file");

    DWORD dwRIFF = 0; //И так идет формат wav-файла, он относится к RIFF-файлам, поэтому читаем 4 байта структуы
    file.read((char*) &dwRIFF,4);
    if (dwRIFF != MAKEFOURCC('R','I','F','F')) //Если RIFF не получили, то значит какую то залепу открыли
    {
    cout<<"Файл не является RIFF - formated"<<endl;
    return 0;
    }

    file.ignore(4); //Пропустим 4 байта там какая то охинея нам совершенно не нужна
    DWORD dwWave = 0; //Секция WAVE
    DWORD dwFormat = 0; // Секция fmt /формат файла/
    long lSizeFmt = 0; //Размер секции fmt

    file.read((char*)&dwWave,4); //Читаем 4 байта, там для Wav-файла должно быть название секции WAVE
    if (dwWave != MAKEFOURCC('W','A','V','E')) //Проверим
    {
    cout<<"Файл не имеет секции WAVE"<<endl;
    return 0;
    }

    file.read((char*)&dwFormat,4); //Если все ОК... То читаем
    if (dwFormat != MAKEFOURCC('f','m','t',' ')) //Если секция fmt - не найдена
    {
    cout<<"Файл не имеет Format(fmt)-Секции "<<endl;
    return 0;
    }
    file.read((char*)&lSizeFmt,4); //Еще читаем 4 байта, там у нас размер секции формат, где идет сам формат + может идти всякая охинея, формат лежит в 16 байтах
    WAVEFORMATEX WaveFormat = WAVEFORMATEX(); //Определим структуру винды
    file.read((char*)&WaveFormat,16); //Прочитаем ее
    file.ignore(lSizeFmt-16); //Пропустим охинею
    if (WaveFormat.wFormatTag != 1) //Если таг <>1 то значит есть компрессия файла, ее разбирать мы не будем, работаем не с жатыми данными
    {
    cout<<"Файл имеет компрессию"<<endl;
    return 0;
    }

    DWORD dwSection = 0; //Следующая секция у нас или fact(Не обязательная) или data(это как раз наш звук)
    file.read((char*)&dwSection,4); //Читаем заголовок
    if (dwSection == MAKEFOURCC('f','a','c','t')) //Если все же fact - то пропускаем ее
    {
    cout<<"Файл имеет секцию fact"<<endl;
    DWORD dwSizeFact = 0;
    file.read((char*)&dwSizeFact,4);
    file.ignore(dwSizeFact);
    file.read((char*)&dwSection,4);
    fact1=dwSection;
    }

    if (dwSection != MAKEFOURCC('d','a','t','a')) //Ну а теперь сама data - это то, над чем мы будем работать
    {
    cout<<"Не найдена секция data"<<endl;
    return 0;
    }
    file.read((char*)&dwDataSize,4); //Прочитаем ее размер
    char *pData = new char[dwDataSize]; //Динамически выделим переменную типа char[размер звуковых данных]

    file.read(pData,dwDataSize); //Прочитаем в нее все звуковые данные
    file.close(); //Закроем файл, он нам уже не нужен, у нас есть pData

    //И так реализация эха
    char *pDataEcho = new char[dwDataSize+int(1.5*WaveFormat.nAvgBytesPerSec)]; //Введем новую указатель на данные и увеличим его на 1.5(секунды) * Байты в секунду
    memset(pDataEcho,0,dwDataSize+1.5*WaveFormat.nAvgBytesPerSec); //обнулим его
    for (int i = 0; i<dwDataSize; i++) //Обходим весь массив (исходных данных) которые из файла вытащили
    {
    //Теперь по принципу сумматора складываем данные
    pDataEcho[i] += pData[i]; //Текущий байт (исходны) данных
    if(isk==0)
    {
    pDataEcho[i]=pData[i];
    }
    if(isk==1)
    {

    pDataEcho[i+int(0.5*WaveFormat.nAvgBytesPerSec)]+= 0.6 * pData[i]; //Сдвигаем на 0.5 секунд и слогаем текущий(исходный) байт * на коэффициент первого затухания
    }
    if(isk==2)
    {
    pDataEcho[i+int(0.5*WaveFormat.nAvgBytesPerSec)]+= 0.6 * pData[i]; //Сдвигаем на 0.5 секунд и слогаем текущий(исходный) байт * на коэффициент первого затухания
    pDataEcho[i+int(1*WaveFormat.nAvgBytesPerSec)]+= 0.3 * pData[i]; //Сдвигаем на 1 секунду и так же (только коэффициент 0.3)
    }
    if(isk==3)
    {
    pDataEcho[i+int(0.5*WaveFormat.nAvgBytesPerSec)]+= 0.6 * pData[i]; //Сдвигаем на 0.5 секунд и слогаем текущий(исходный) байт * на коэффициент первого затухания
    pDataEcho[i+int(1*WaveFormat.nAvgBytesPerSec)]+= 0.3 * pData[i]; //Сдвигаем на 1 секунду и так же (только коэффициент 0.3)
    pDataEcho[i+int(1.5*WaveFormat.nAvgBytesPerSec)]+= 0.1 * pData[i]; //И последняя волна через 1.5 секунды которая дойдет (коэф. 0.1) -почти не ощутимый
    }
    }
    pData = pDataEcho; //Заменим данные
    char *mass;
    for (int i = 0; i<dwDataSize; i++) //Обходим весь массив (исходных данных) которые из файла вытащили
    {
    if(isk==1)
    {
    pDataEcho[i]=pData[i]+qrand()/1000;

    }
    if(isk==2)
    {
    pDataEcho[i]=127-pData[i];
    pDataEcho[i]=pData[i]+qrand()/1000;
    }
    if(isk==3)
    {
    pDataEcho[i]=127-pData[i];
    pDataEcho[i]=pData[i]+qrand()/400;
    }
    }
    pData = pDataEcho; //Заменим данные
    dwDataSize+=WaveFormat.nAvgBytesPerSec; //Увеличим размер, что бы DS прочитал добавление 1.5 секунды
    //Ну вот и все... Эхо - не реальное, в природе наверное такого добится не возможно, но я же для примера только


    // Write the PCMWAVEFORMAT structure
    //----------------------------------------------
    pcmWaveFormat.wf.wFormatTag=WAVE_FORMAT_PCM;
    pcmWaveFormat.wf.nChannels=1;
    pcmWaveFormat.wf.nBlockAlign=2;
    pcmWaveFormat.wf.nSamplesPerSec=N2;
    pcmWaveFormat.wf.nAvgBytesPerSec=N2*2;
    pcmWaveFormat.wBitsPerSample=16;

    //----------------------------------------------


    hmmioOut = mmioOpen(L"out.wav", NULL,
    MMIO_ALLOCBUF | MMIO_WRITE | MMIO_CREATE);
    if (hmmioOut == NULL)
    cout<<"error opening out file "<<endl;

    // Write the PCMWAVEFORMAT structure
    ckOutRIFF.fccType = mmioFOURCC('W', 'A', 'V', 'E');
    if (mmioCreateChunk(hmmioOut, &ckOutRIFF, MMIO_CREATERIFF) != 0)
    cout<<"error creating out file wave "<<endl;

    ckOut.ckid = mmioFOURCC('f', 'm', 't', ' ');
    if (mmioCreateChunk(hmmioOut, &ckOut, 0) != 0)
    cout<<"error creating out file fmt "<<endl;


    if (mmioWrite(hmmioOut, (HPSTR) &pcmWaveFormat, sizeof(pcmWaveFormat))
    != sizeof(pcmWaveFormat))
    cout<<"error writing size of fmt "<<endl; // cannot write file, probably

    if (mmioAscend(hmmioOut, &ckOut, 0) != 0)
    cout<<"error writing size of fmt 2 "<<endl; // cannot write file, probably

    ckOut.ckid = mmioFOURCC('d', 'a', 't', 'a');
    if (mmioCreateChunk(hmmioOut, &ckOut, 0) != 0)
    cout<<"error creating out file data "<<endl;


    // Write/read in file of the I/O buffers.

    for (int lSamples =2*N2; lSamples > 0; lSamples--)
    {
    if (mmioinfoOut.pchNext == mmioinfoOut.pchEndWrite)
    {
    mmioinfoOut.dwFlags |= MMIO_DIRTY;
    if (mmioAdvance(hmmioOut, &mmioinfoOut, MMIO_WRITE) != 0)
    cout<<"error write "<<endl;
    }
    *(mmioinfoOut.pchNext)++ =pDataEcho[2*N2-lSamples];
    }
    if (mmioGetInfo(hmmioOut, &mmioinfoOut, 0) != 0)
    cout<<"error writing data in file "<<endl;
    ckOut.cksize = sizeof(pcmWaveFormat)*10;
    mmioinfoOut.dwFlags |= MMIO_DIRTY;
    if (mmioSetInfo(hmmioOut, &mmioinfoOut, 0) != 0)
    cout<<"error end "<<endl;

    if (mmioAscend(hmmioOut, &ckOut, 0) != 0)
    cout<<"error end "<<endl;

    if (mmioAscend(hmmioOut, &ckOutRIFF, 0) != 0)
    cout<<"error end "<<endl;

    if (hmmioOut != NULL)
    mmioClose(hmmioOut, 0);
     
  19. lazybiz

    lazybiz Well-Known Member
    C\C++ Team

    Регистрация:
    3 ноя 2010
    Сообщения:
    1.344
    Симпатии:
    0
    Что-то у тебя конца программы не видно....
     
  20. Firefox

    Firefox Гость

    просто в конце скобку забыла докопировать)))

    Добавлено:
     
Загрузка...
Похожие Темы - Вопрос наложение эффекта
  1. Генералл
    Ответов:
    2
    Просмотров:
    63
  2. ApplePen
    Ответов:
    0
    Просмотров:
    64
  3. gURaBA_N
    Ответов:
    3
    Просмотров:
    94
  4. ghost
    Ответов:
    1
    Просмотров:
    89
  5. kartaman
    Ответов:
    0
    Просмотров:
    128

Поделиться этой страницей