Иммитатор телефонного гудка
Модераторы: Duncon, Hawk, Romeo, Eugie
Привет всем! Подскажите, пожалуйста, каким образом можно программно синтезировать звук, похожий на гудок в телефонной трубке? Я конечно могу тупо найти некий WAV-файл с таким звуком и проигрывать его из программы.
Но мне хотелось бы иметь возможность самому устанавливать частоту сигнала, его уровень, длительность звучания, а так же режим воспроизведения (моно/стерео).
Но мне хотелось бы иметь возможность самому устанавливать частоту сигнала, его уровень, длительность звучания, а так же режим воспроизведения (моно/стерео).
Поумнеть несложно, куда труднее от дури избавиться.
Могу предложить свой вариант:
Однако на сегодняшний день использование функций waveIn/waveOut считается как бы уже устаревшей технологией. Вместо них Microsoft предлагает более современные библиотеки, типа DirectSound или Windows Audio Session (WAS).
Код: Выделить всё
#include "stdafx.h"
#include <Mmsystem.h>
#include <math.h>
#include <atlsync.h>
#pragma comment (lib, "Winmm.lib")
ATL::CEvent _Event(TRUE, FALSE);
void CALLBACK waveOutProc(HWAVEOUT hWaveOut, UINT uMsg,
DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
switch (uMsg)
{
case MM_WOM_OPEN:
_Event.Reset();
break;
case MM_WOM_DONE:
_Event.Set();
break;
default:
break;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
WAVEFORMATEX waveForm = {0};
waveForm.nChannels = 2; // Режим стерео
waveForm.nSamplesPerSec = 45000;
waveForm.wBitsPerSample = 16;
waveForm.wFormatTag = WAVE_FORMAT_PCM;
waveForm.nBlockAlign = waveForm.nChannels * waveForm.wBitsPerSample/8;
waveForm.nAvgBytesPerSec = waveForm.nSamplesPerSec * waveForm.nBlockAlign;
//
HWAVEOUT hWaveOut = NULL;
MMRESULT mmr = waveOutOpen( &hWaveOut, WAVE_MAPPER,
&waveForm, (DWORD_PTR)waveOutProc,
0, CALLBACK_FUNCTION);
if (mmr == MMSYSERR_NOERROR)
{
DWORD* pBuff = new DWORD[waveForm.nSamplesPerSec];
WAVEHDR waveHdr = {0};
waveHdr.lpData = reinterpret_cast<LPSTR>(pBuff);
waveHdr.dwBufferLength = waveForm.nAvgBytesPerSec;
//
const int Frequency = 750; // Частота в герцах
const int ts = waveForm.nSamplesPerSec/Frequency;
const double Pi = acos(-1.0); // Число ПИ
for (DWORD n = 0; n < waveForm.nSamplesPerSec; n++)
{
int vol = 20000; // Уровень сигнала
double dSample1 = // Левый канал
sin(Pi*n/ts)*vol +
sin(Pi*n*3/ts)*vol/2 +
sin(Pi*n*5/ts)*vol/4 +
sin(Pi*n*9/ts)*vol/8;
double dSample2 = // Правый канал
cos(Pi*n/ts)*vol -
cos(Pi*n*3/ts)*vol/2 -
cos(Pi*n*5/ts)*vol/4 -
cos(Pi*n*9/ts)*vol/8;
pBuff[n] = MAKELONG((WORD)dSample1, (WORD)dSample2);
}
//
mmr = waveOutPrepareHeader(hWaveOut, &waveHdr, sizeof(WAVEHDR));
if (mmr == MMSYSERR_NOERROR)
{
mmr = waveOutWrite(hWaveOut, &waveHdr, sizeof(WAVEHDR));
::WaitForSingleObject(_Event, INFINITE);
}
waveOutUnprepareHeader(hWaveOut, &waveHdr, sizeof(WAVEHDR));
waveOutClose(hWaveOut);
delete[] pBuff;
}
return 0;
}
Однако на сегодняшний день использование функций waveIn/waveOut считается как бы уже устаревшей технологией. Вместо них Microsoft предлагает более современные библиотеки, типа DirectSound или Windows Audio Session (WAS).
- Romeo
- Сообщения: 3126
- Зарегистрирован: 02 мар 2004, 17:25
- Откуда: Крым, Севастополь
- Контактная информация:
Виталик, я в очередной раз поражаюсь количеством самплов в твоей бездонной библиотеке готовых решений 

Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Обалдеть! Прямо как настоящий телефонный зуммер. Просто потрясающе.
WinMain, огромное тебе спасибо.
А не подскажешь, что нужно поменять для переключения режима звучания в моно и для изменения времени звучания?
WinMain, огромное тебе спасибо.
А не подскажешь, что нужно поменять для переключения режима звучания в моно и для изменения времени звучания?
Поумнеть несложно, куда труднее от дури избавиться.
Вот так будет выглядеть этот код при воспроизведении в режиме моно и с временем звучания 2.5 сек:
Код: Выделить всё
#include "stdafx.h"
#include <math.h>
#include <atlsync.h>
#include <Mmsystem.h>
#pragma comment (lib, "Winmm.lib")
ATL::CEvent _Event(TRUE, FALSE);
void CALLBACK waveOutProc(HWAVEOUT hWaveOut, UINT uMsg,
DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
switch (uMsg)
{
case MM_WOM_OPEN:
_Event.Reset();
break;
case MM_WOM_DONE:
_Event.Set();
break;
default:
break;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
WAVEFORMATEX waveForm = {0};
waveForm.nChannels = 1; // Режим моно
waveForm.nSamplesPerSec = 45000;
waveForm.wBitsPerSample = 16;
waveForm.wFormatTag = WAVE_FORMAT_PCM;
waveForm.nBlockAlign = waveForm.nChannels * waveForm.wBitsPerSample/8;
waveForm.nAvgBytesPerSec = waveForm.nSamplesPerSec * waveForm.nBlockAlign;
//
HWAVEOUT hWaveOut = NULL;
MMRESULT mmr = waveOutOpen( &hWaveOut, WAVE_MAPPER,
&waveForm, (DWORD_PTR)waveOutProc,
0, CALLBACK_FUNCTION);
if (mmr == MMSYSERR_NOERROR)
{
const DWORD dwDuration = 2500; // Время в миллисекундах
const DWORD dwTotalSamples =
::MulDiv(waveForm.nSamplesPerSec, dwDuration, 1000);
WORD* pBuff = new WORD[dwTotalSamples];
WAVEHDR waveHdr = {0};
waveHdr.lpData = reinterpret_cast<LPSTR>(pBuff);
waveHdr.dwBufferLength = dwTotalSamples * waveForm.nBlockAlign;
//
const int Frequency = 750; // Частота в герцах
const int ts = waveForm.nSamplesPerSec/Frequency;
const double Pi = acos(-1.0); // Число ПИ
for (DWORD n = 0; n < dwTotalSamples; n++)
{
int vol = 20000; // Уровень сигнала
double dSample =
sin(Pi*n/ts)*vol +
sin(Pi*n*3/ts)*vol/2 +
sin(Pi*n*5/ts)*vol/4 +
sin(Pi*n*9/ts)*vol/8;
pBuff[n] = (WORD)dSample;
}
//
mmr = waveOutPrepareHeader(hWaveOut, &waveHdr, sizeof(WAVEHDR));
if (mmr == MMSYSERR_NOERROR)
{
waveOutWrite(hWaveOut, &waveHdr, sizeof(WAVEHDR));
::WaitForSingleObject(_Event, INFINITE);
}
waveOutUnprepareHeader(hWaveOut, &waveHdr, sizeof(WAVEHDR));
waveOutClose(hWaveOut);
delete[] pBuff;
}
return 0;
}
Какая прелесть. :-)
А как бы мне ещё научиться сохранять синтезируемые звуки в WAV-файлы?
А как бы мне ещё научиться сохранять синтезируемые звуки в WAV-файлы?
Поумнеть несложно, куда труднее от дури избавиться.
В принципе, формат WAV-файла (не сжатого) довольно прост.Decoder писал(а):Какая прелесть. :-)
А как бы мне ещё научиться сохранять синтезируемые звуки в WAV-файлы?
Вот, например, описание.
Т.е. сначала записывается (в файл) загоровок, затем данные.
Про заголовок что-то там явно перечислено, что-то надо заполнить в зависимости от твоих данных и содержимого записи WAVEFORMATEX waveForm (которая заполняется в прведенных WinMain-ом примерах).
Могу предложить такой вариант функции записи звука в WAV-файл...
Применительно к предыдущим примерам, эту функцию можно вызывать перед удалением динамического массива данных. Это будет выглядеть примерно так...
Код: Выделить всё
BOOL waveSaveToFile(LPCTSTR szFileName, LPWAVEFORMATEX lpWaveFormat, LPWAVEHDR lpWaveHdr)
{
if (szFileName == NULL || lpWaveFormat == NULL || lpWaveHdr == NULL)
{
return FALSE;
}
//
struct _WAVEFILEHEADER {
FOURCC fccSignRIFF;
DWORD dwChunkSize;
FOURCC fccSignWAVE;
FOURCC fccSignFmt;
DWORD dwDataOffset;
WAVEFORMAT waveFormat;
WORD wBitsPerSample;
FOURCC fccDataSign;
DWORD dwDataSize;
} fileHdr;
//
fileHdr.fccSignRIFF = FOURCC_RIFF;
fileHdr.fccSignWAVE = mmioFOURCC('W','A','V','E');
fileHdr.fccSignFmt = mmioFOURCC('f','m','t',' ');
fileHdr.fccDataSign = mmioFOURCC('d','a','t','a');
fileHdr.dwDataSize = lpWaveHdr->dwBufferLength;
fileHdr.dwDataOffset = sizeof(WAVEFORMAT) + sizeof(WORD);
fileHdr.dwChunkSize = fileHdr.dwDataSize + sizeof(fileHdr) - sizeof(FOURCC);
fileHdr.wBitsPerSample = lpWaveFormat->wBitsPerSample;
fileHdr.waveFormat.wFormatTag = lpWaveFormat->wFormatTag;
fileHdr.waveFormat.nChannels = lpWaveFormat->nChannels;
fileHdr.waveFormat.nSamplesPerSec = lpWaveFormat->nSamplesPerSec;
fileHdr.waveFormat.nBlockAlign = lpWaveFormat->nBlockAlign;
fileHdr.waveFormat.nAvgBytesPerSec = lpWaveFormat->nAvgBytesPerSec;
//
FILE* f = NULL;
_tfopen_s(&f, szFileName, _T("wb"));
if (f == NULL)
{
return FALSE;
}
fwrite(&fileHdr, 1, sizeof(fileHdr), f);
fwrite(lpWaveHdr->lpData, 1, fileHdr.dwDataSize, f);
fclose(f);
//
return TRUE;
}
Применительно к предыдущим примерам, эту функцию можно вызывать перед удалением динамического массива данных. Это будет выглядеть примерно так...
Код: Выделить всё
. . . . .
waveSaveToFile(_T("Phone.wav"), &waveForm, &waveHdr);
delete[] pBuff;