#winapi #audio #wave
#winapi #Аудио #волна
Вопрос:
Как мне, скажем, воспроизвести звук с заданной амплитудой и заданным частотным составом (скажем, состоящий из частот 2 кГц и 3 кГц) изначально в Windows (32-разрядная и 64-разрядная версии, вплоть до Windows 7)?
(Под «изначально» я подразумеваю без использования внешней библиотеки.)
Я считаю, что для этого нужен метод waveOutWrite, но я понятия не имею, как это работает.
Ответ №1:
У меня что-то работает…
#define _USE_MATH_DEFINES 1
#include <math.h>
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <mmreg.h>
#include <complex>
#pragma comment(lib, "Winmm.lib")
MMRESULT play(float nSeconds,
float signal(float timeInSeconds, unsigned short channel, void *context),
void *context = NULL, unsigned long samplesPerSecond = 48000)
{
UINT timePeriod = 1;
MMRESULT mmresult = MMSYSERR_NOERROR;
WAVEFORMATEX waveFormat = {0};
waveFormat.cbSize = 0;
waveFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
waveFormat.nChannels = 2;
waveFormat.nSamplesPerSec = samplesPerSecond;
const size_t nBuffer =
(size_t)(nSeconds * waveFormat.nChannels * waveFormat.nSamplesPerSec);
float *buffer;
waveFormat.wBitsPerSample = CHAR_BIT * sizeof(buffer[0]);
waveFormat.nBlockAlign =
waveFormat.nChannels * waveFormat.wBitsPerSample / CHAR_BIT;
waveFormat.nAvgBytesPerSec =
waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
buffer = (float *)calloc(nBuffer, sizeof(*buffer));
__try
{
for (size_t i = 0; i < nBuffer; i = waveFormat.nChannels)
for (unsigned short j = 0; j < waveFormat.nChannels; j )
buffer[i j] = signal((i j) * nSeconds / nBuffer, j, context);
HWAVEOUT hWavOut = NULL;
mmresult = waveOutOpen(amp;hWavOut, WAVE_MAPPER,
amp;waveFormat, NULL, NULL, CALLBACK_NULL);
if (mmresult == MMSYSERR_NOERROR)
{
__try
{
timeBeginPeriod(timePeriod);
__try
{
WAVEHDR hdr = {0};
hdr.dwBufferLength =
(ULONG)(nBuffer * sizeof(buffer[0]));
hdr.lpData = (LPSTR)amp;buffer[0];
mmresult = waveOutPrepareHeader(hWavOut,
amp;hdr, sizeof(hdr));
if (mmresult == MMSYSERR_NOERROR)
{
__try
{
ULONG start = GetTickCount();
mmresult =
waveOutWrite(hWavOut, amp;hdr, sizeof(hdr));
Sleep((ULONG)(1000 * nSeconds
- (GetTickCount() - start)));
}
__finally
{ waveOutUnprepareHeader(hWavOut, amp;hdr, sizeof(hdr)); }
}
}
__finally { timeEndPeriod(timePeriod); }
}
__finally { waveOutClose(hWavOut); }
}
}
__finally { free(buffer); }
return mmresu<
}
// Triangle wave generator
float triangle(float timeInSeconds, unsigned short channel, void *context)
{
const float frequency = *(const float *)context;
const float angle = (float)(frequency * 2 * M_PI * timeInSeconds);
switch (channel)
{
case 0: return (float)asin(sin(angle 0 * M_PI / 2));
default: return (float)asin(sin(angle 1 * M_PI / 2));
}
}
// Pure tone generator
float pure(float timeInSeconds, unsigned short channel, void *context)
{
const float frequency = *(const float *)context;
const float angle = (float)(frequency * 2 * M_PI * timeInSeconds);
switch (channel)
{
case 0: return (float)sin(angle 0 * M_PI / 2);
default: return (float)sin(angle 1 * M_PI / 2);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
float frequency = 2 * 261.626F;
play(1, pure, amp;frequency);
return 0;
}
Комментарии:
1. 1. Но я думаю, что генератор треугольных волн ошибочен. Согласно Википедии :
return (float)asin(sin(angle 0 * M_PI / 2)) * 2 / M_PI;
.
Ответ №2:
BOOL WINAPI Beep(
__in DWORD dwFreq,
__in DWORD dwDuration
);
Ответ №3:
waveOut
Функции обрабатывают данные о форме звукового сигнала (в формате WAV, если я правильно помню).
Хотя это предназначено для приложений WPF, следующая ссылка должна оказаться полезной для любого настольного приложения:
Ответ №4:
Звуковой сигнал подается через динамик ПК или с помощью Directx Sound. Я могу предложить несколько фрагментов, если вам нужно.
Комментарии:
1. Ну, функция звукового сигнала не работает, потому что она не может генерировать комбинацию частот. Звук DirectX кажется излишним, поскольку я просто хочу сгенерировать простой звуковой сигнал … есть ли какой-нибудь способ сделать это с помощью чего-то вроде
waveOutWrite
? Я думаю, что это правильный способ, но я понятия не имею, какие данные ему предоставить.2. @Mehrdad: wavOutWrite ожидает фрагменты звука в формате WAV, iirc.
3. @Adam: Ах, это отличный ответ. =) Не стесняйтесь опубликовать это, чтобы я мог принять это! (Кстати, это полные данные wave или только их часть? Нужно ли мне также отправлять все заголовки RIFF?)