Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.145.191.214] |
|
Сообщ.
#1
,
|
|
|
Переписал пример из книжки. Он работает для звука 8-ми битного звука. Попытался сделать звук 16-битным и начались проблемы. Вот код:
LPDIRECTSOUND8 DS = NULL; HWND GetConsoleWindowHandle() { char title[512]; GetConsoleTitle(title, sizeof(title)); return FindWindow(NULL, title); } void InitAudio(int bitsPerSample, int samplesPerSec) { HRESULT hr; stringstream error; //Шаг 1: создание интерфейса DirectSound (выбираем устройство по умолчанию) hr = DirectSoundCreate8(NULL, &DS, NULL); if (FAILED(hr)) { error << "DirectSoundCreate8 error: " << DXGetErrorString8(hr) << endl; throw (error.str()); } //Шаг 2: создание уровня кооперации hr = DS->SetCooperativeLevel(GetConsoleWindowHandle(), DSSCL_PRIORITY); if (FAILED(hr)) { error << "SetCooperativeLevel error: " << DXGetErrorString8(hr) << endl; throw (error.str()); } //Шаг 3: Создание первичного буфера LPDIRECTSOUNDBUFFER primary = NULL; DSBUFFERDESC dsbd; ZeroMemory(&dsbd, sizeof(DSBUFFERDESC)); dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; dsbd.dwSize = sizeof(DSBUFFERDESC); dsbd.dwBufferBytes = 0; dsbd.lpwfxFormat = NULL; hr = DS->CreateSoundBuffer(&dsbd, &primary, NULL); if (FAILED(hr)) { error << "CreateSoundBuffer error (primary buffer): " << DXGetErrorString8(hr) << endl; throw error.str(); } //Задаём формат первичного буфера WAVEFORMATEX wfx; ZeroMemory(&wfx, sizeof(WAVEFORMATEX)); wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nChannels = (WORD)1; wfx.nSamplesPerSec = samplesPerSec; wfx.wBitsPerSample = (WORD)bitsPerSample; wfx.nBlockAlign = (WORD)(wfx.wBitsPerSample * wfx.nChannels / 8); wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; hr = primary->SetFormat(&wfx); if (FAILED(hr)) { error << "SetFormat error: " << DXGetErrorString8(hr) << endl; throw error.str(); } //primary больше не нужен SAFE_RELEASE(primary); } int CreateSecondaryBuffer(LPDIRECTSOUNDBUFFER *buffer, int secs, int samplerate, int bitspersample, DWORD flags) { HRESULT hr; stringstream error; DSBUFFERDESC dsbd; WAVEFORMATEX wfx; ZeroMemory(&wfx, sizeof(WAVEFORMATEX)); wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nChannels = 1; wfx.nSamplesPerSec = samplerate; wfx.wBitsPerSample = bitspersample; wfx.nBlockAlign = (WORD)(wfx.wBitsPerSample * wfx.nChannels / 8); wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; ZeroMemory(&dsbd, sizeof(DSBUFFERDESC)); dsbd.dwSize = sizeof(DSBUFFERDESC); dsbd.dwFlags = flags; dsbd.dwBufferBytes = samplerate * bitspersample * 1 * secs / 8; dsbd.guid3DAlgorithm = GUID_NULL; dsbd.lpwfxFormat = &wfx; hr = DS->CreateSoundBuffer(&dsbd, buffer, NULL); if (FAILED(hr)) { error << "CreateSoundBuffer error (secondary buffer): " << DXGetErrorString8(hr) << endl; throw error.str(); } //Возвращаем размер буфера return dsbd.dwBufferBytes; } void FillBuffer(LPDIRECTSOUNDBUFFER buffer, float freq, int size, int samplerate, int bitsPerSample) { HRESULT hr; stringstream error; unsigned char *bufferBytes; DWORD lockedSize; //Запираем буфер hr = buffer->Lock(0, size, (void **)(&bufferBytes), &lockedSize, NULL, NULL, 0L); if (FAILED(hr)) { error << "Lock error: " << DXGetErrorString8(hr) << endl; throw error.str(); } for (DWORD q = 0; q < lockedSize; q++) { //Определяем цикл, в котором находимся float pos = freq / (float)samplerate * (float)q; //Берём остаток и переводим в радианы float r = (pos - floor(pos)) * 2 * PI; float value = sin(r); //Получили значение в диапазоне [-1; 1]. Умножаем на 127 и прибавляем 127, //чтобы получить значение в диапазоне [0; 256] bufferBytes[q] = (value * 127 + 127) / 8; //float k = pow((float)2, bitsPerSample)/2; //bufferBytes[q] = (value * k + k) / 8; } //Отпираем буфер buffer->Unlock(bufferBytes, lockedSize, NULL, 0); } void PlayBuffer(LPDIRECTSOUNDBUFFER buffer) { buffer->Play(0, 0, DSBPLAY_LOOPING); } void main(int argc, char* argv[]) { LPDIRECTSOUNDBUFFER DsBuffer; int BitsPerSample = 16; int SamplesPerSec = 44100; try { cout << endl << "Tone Generator. Version 1.0" << endl << endl; cout << "Initializing DirectSound..." << endl; InitAudio(BitsPerSample, SamplesPerSec); cout << "Creating sound buffer..." << endl; int bufferSize = CreateSecondaryBuffer(&DsBuffer, 1, SamplesPerSec, BitsPerSample, 0); cout << "Fill buffer with data..." << endl; FillBuffer(DsBuffer, 440.0, bufferSize, SamplesPerSec, BitsPerSample); //440 Гц - "Ля" первой октавы cout << "Now playing... (press ant key to exit)" << endl; PlayBuffer(DsBuffer); getch(); DsBuffer->Stop(); cout << "Releasing sound buffer..." << endl; SAFE_RELEASE(DsBuffer); cout << "Un-initializing DirectSound..." << endl; SAFE_RELEASE(DS); } catch(string error) { cout << error << endl; getch(); exit(-1); } } Для 16-битного звука, насколько я понимаю, нужно unsigned char *bufferBytes сменить на unsigned short. После этого появляется Access Violation на строчке bufferBytes[q] = (value * 127 + 127) / 8; Появилось предположение, что unsigned short занимает в 2 раза больше места, чем unsigned char, и я попробовал вместо size передавать size*2 в Lock(). Но Lock начал жаловаться на плохой параметр. Как вывести 16-битный моно-звук с заданной частотой? |
Сообщ.
#2
,
|
|
|
Цитата zlib @ Появилось предположение, что unsigned short занимает в 2 раза больше места, чем unsigned char Ужас... Не зная даже базовых типов данных, пытаться программировать под DirectX... Куда мы идем... Меняем: Цитата zlib @ unsigned char *bufferBytes; на signed short *bufferBytes; Цитата zlib @ for (DWORD q = 0; q < lockedSize; q++) на for (DWORD q = 0; q < lockedSize / 2; q++) и Цитата zlib @ bufferBytes[q] = (value * 127 + 127) / 8; на bufferBytes[q] = value * 32767 / 8; И в дальнейшем рекомендую не выдергивать сырцы из середины книжки, а читать ёё внимательно сначала. А перед этим прочесть что-нить просто по С++, для общего развития. |
Сообщ.
#3
,
|
|
|
Спасибо.
Книжка была для американцев, поэтому в ней мало что объяснялось по-человечески (МакКаски "Звук в играх. Технологии программирования"). |
Сообщ.
#4
,
|
|
|
вроде даже проще можно реализовать... еще бы разобраться какой минимально-безглючный размер у буффера :\
#include "dsound.h" #include <math.h> #include <stdio.h> #define PI 3.14159265359 LPDIRECTSOUND DS = NULL; int InitAudio(LPDIRECTSOUNDBUFFER *buffer, int secs, int samplerate, int bitspersample) { WAVEFORMATEX wfx; DSBUFFERDESC dsbd; ZeroMemory(&wfx, sizeof(WAVEFORMATEX)); wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nChannels = 1; wfx.nSamplesPerSec = samplerate; wfx.wBitsPerSample = bitspersample; wfx.nBlockAlign = (WORD)(wfx.wBitsPerSample * wfx.nChannels / 8); wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; ZeroMemory(&dsbd, sizeof(DSBUFFERDESC)); dsbd.dwSize = sizeof(DSBUFFERDESC); dsbd.dwFlags = DSBCAPS_GLOBALFOCUS; dsbd.dwBufferBytes = samplerate * secs; dsbd.lpwfxFormat = &wfx; DirectSoundCreate(NULL, &DS, NULL); DS->SetCooperativeLevel(GetForegroundWindow(), DSSCL_PRIORITY); DS->CreateSoundBuffer(&dsbd, buffer, NULL); //Возвращаем размер буфера return dsbd.dwBufferBytes; } void FillBuffer(LPDIRECTSOUNDBUFFER buffer, float freq, int size, int samplerate, int bitsPerSample) { short *bufferBytes; DWORD lockedSize; //Запираем буфер buffer->Lock(0, size, (void **)(&bufferBytes), &lockedSize, NULL, NULL, 0L); for (DWORD q = 0; q < lockedSize / 2; q++) { //Определяем цикл, в котором находимся float pos = freq / (float)samplerate * (float)q; //Берём остаток и переводим в радианы float r = (pos - floor(pos)) * 2 * PI; float value = sin(r); bufferBytes[q] = value * 32767 / 8; } //Отпираем буфер buffer->Unlock(bufferBytes, lockedSize, NULL, 0); } void main(int argc, char* argv[]) { LPDIRECTSOUNDBUFFER DsBuffer; int BitsPerSample = 16; int SamplesPerSec = 48000; int bufferSize = InitAudio(&DsBuffer, 1, SamplesPerSec, BitsPerSample); printf ("Creating %d bytes sound buffer \n",bufferSize); printf ("Fill buffer with data...\n");//, bufferSize); FillBuffer(DsBuffer, 440.0, bufferSize, SamplesPerSec, BitsPerSample); //440 Гц - "Ля" первой октавы printf ("Now playing... (press ant key to exit) \n"); DsBuffer->Play(0, 0, DSBPLAY_LOOPING); getchar(); DsBuffer->Stop(); printf ("Free DirectSound...\n"); DsBuffer->Release(); DS->Release(); } Добавлено хм.. вроде со значением равным Цитата dsbd.dwBufferBytes = 2400;//samplerate * secs; звучит без лагов.. это гуд разобраться бы еще как на ходу WAVE генерировать |
Сообщ.
#5
,
|
|
|
Акак это можна сделать в Буилдере????
|
Сообщ.
#6
,
|
|
|
Цитата VCJ @ Это в раздел, посвященный Borland C++ Builder Акак это можна сделать в Буилдере???? |