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

  • Автор темы Firefox
  • Дата начала
F

Firefox

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

DarkKnight

Я если честно с этим вопросом никогда не сталкивался, так что с ходу сказать не могу, но если выложишь ссылку на книгу, то помогу....
 
F

Firefox

вот эта книга. там много классов наследуется и нет комментариев к переменным в классах. гн понимаю например что они берут за n,n1,n2.
 
D

DarkKnight

Щас откачаю... Почитаю и к вечеру что-нить скажу.... Наверно ;-)

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

lazybiz

Допустим:
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) );
}
}
}

Прошу заметить что это не опробованный алгоритм. Возможно я что-то не досмотрел.. В общем на свой страх и риск. Если выйдет черепаха - просьба камни не кидать!
 
D

DarkKnight

Если честно, книга мне на первый взгял очень не понравилась, грубо все как то, больше учебник по физике, чем литература по программированию....
С эхом, нужно подумать еще, скорее всего 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;
}
Вообщем завтра продолжу описание....
 
L

lazybiz

Только что вспомнил что давным давно видел простой пример в 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;
}

Скачать можно отсюда:
 
D

DarkKnight

Да, принцип как раз такой как Лайзи описал.....
Вот я реализацию свою доработал, щас расскажу от чего отталкивался...
Вообщем сам принцип эхо - это отражающая волна (которая при отражении само собой иммет потери), зависит отражение от того на каком расстоянии стоит отражающая поверхность :) Ну про скорость звука не буду ничего говорить, при потери из-за плотности воздуха тоже ;-)
Вообщем основное - это коэффициент этого затухания.. Пошла 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;

}
 
L

lazybiz

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-битная? Если да то вопросов нет)) В целом пример очень наглядный)
 
D

DarkKnight

И еще не совсем понял, ты оперируешь байтами, у тебя wav-ка 8-битная? Если да то вопросов нет)) В целом пример очень наглядный)
А тут разнице же нет Лайз, без разницы 8бит или 16, это только будет влият на время эхи, а так эхо будет по всем каналам не зависимо от размерности...
Все равно на 1 канал отводится только 1 байт.....
 
L

lazybiz

Я в том смысле что 8-битные форматы мало уже где используются))
 
D

DarkKnight

;-))) Я использую ;-))) Когда с гитары напрямую пишу через виндовскую звукозапись ;-))))))))))))))))) Адское качество ;-))))
 
F

Firefox

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

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 размер должен автоматически заполняться или нет?
 
L

lazybiz

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

Вложения

  • RTCompress.zip
    11,6 КБ · Просмотры: 205
F

Firefox

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

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);
 
L

lazybiz

Что-то у тебя конца программы не видно....
 
F

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);}
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!