Hi,
I found no thread that is actually dealing with my topic, so I decided to start a new one:
I use Dev-C++, downloaded the DirectX-DevPack and installed it. But I cannot find any tutorials on how to write a small program (can be command line only) that initializes the directsound routines and uses them for a small buffer playback of (let's say) a sine wave or a triangle wave.
Note:
I don't want to play a .wav file or something like that - there are plenty of tutorials for that out there.
I want to write a program allows me to fill the playback buffer with my own data and then play that buffer.
Is there anyone here who has done this before?
Regards,
outrider
Initialize DirectSound in c++ (with Dev-C++)
Started by outrider, Oct 31 2007 07:33 AM
8 replies to this topic
#1
Posted 31 October 2007 - 07:33 AM
#3
Posted 31 October 2007 - 08:57 AM
Yes, thank you. I am aware of that and have a copy of it on my hard drive.
But (it just so happens) I am a total c++ newbie and would appreciate some basic help. I know this forum is not for helping lazy newbies and I do not consider myself lazy at all. I just do not understand the documentation as much as I need to get a simple sine wave played.
A simple main.cpp where the sound system is initialized would help a lot!
That's how far I got (and I do know that it's not very far indeed):
I linked the dsound.lib as described in the documentation and included the Dsound.h file.
Thank you all very much for your help!
But (it just so happens) I am a total c++ newbie and would appreciate some basic help. I know this forum is not for helping lazy newbies and I do not consider myself lazy at all. I just do not understand the documentation as much as I need to get a simple sine wave played.
A simple main.cpp where the sound system is initialized would help a lot!
That's how far I got (and I do know that it's not very far indeed):
I linked the dsound.lib as described in the documentation and included the Dsound.h file.
#include <cstdlib>
#include <iostream>
#include <Dsound.h>
using namespace std;
int main(int argc, char *argv[])
{
system("PAUSE");
return 0;
}
Thank you all very much for your help!
#5
Posted 31 October 2007 - 11:24 AM
Ok, I got some place now...
Program compiles and runs and no error is thrown, but I cannot hear a damn thing.
An idea anyone?
Kenneth:
It's a task I have to complete for school, so I can choose pnly between ALSA, Mac Core Audio and DirectSound, but my group mate is doing the ALSA interface already and I don't have access to a macintosh. So.. :-(
Program compiles and runs and no error is thrown, but I cannot hear a damn thing.
An idea anyone?
Kenneth:
It's a task I have to complete for school, so I can choose pnly between ALSA, Mac Core Audio and DirectSound, but my group mate is doing the ALSA interface already and I don't have access to a macintosh. So.. :-(
#include <cstdlib>
#include <string>
#include <iostream>
#include <Dsound.h>
using namespace std;
int main(int argc, char *argv[]){
HRESULT hr;
LPDIRECTSOUND8 lpds;
LPDIRECTSOUNDBUFFER lpdsbuffer;
LPDIRECTSOUNDBUFFER lpdsbuffer2;
LPVOID lpvWrite;
DWORD dwLength;
// Buffer Setup
DSBUFFERDESC dsbdesc;
memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
dsbdesc.dwFlags = DSBCAPS_STATIC;
// Sound Object Creation
DirectSoundCreate8(NULL, &lpds, NULL);
lpds->SetCooperativeLevel(NULL, DSSCL_PRIORITY);
lpds->Initialize(NULL);
lpds->CreateSoundBuffer(&dsbdesc, &lpdsbuffer, NULL);
// Filling my own buffer
int rate = 11025;
int chan = 2;
float *buffer = new float [rate*chan];
float *ptr = buffer;
for (int i=0;i<rate;i++){
ptr[0]=1;
ptr[1]=1;
ptr+=chan;
}
// Locking the soundbuffer and copying my buffer's data into the soundbuffer
if (DS_OK == lpdsbuffer->Lock(
0, // Offset at which to start lock.
0, // Size of lock; ignored because of flag.
&lpvWrite, // Gets address of first part of lock.
&dwLength, // Gets size of first part of lock.
NULL, // Address of wraparound not needed.
NULL, // Size of wraparound not needed.
DSBLOCK_ENTIREBUFFER)) // Flag.
{
memcpy(lpvWrite, buffer, dwLength);
lpdsbuffer->Unlock(lpvWrite, dwLength, NULL, 0);
}
// Playback
lpdsbuffer->SetCurrentPosition(0);
lpdsbuffer->Play(0,0,0);
return 0;
}
#6
Posted 31 October 2007 - 11:31 AM
Ah ok, I thought it might be a personal project. :)
The reason you are not hearing anything, is because your program exits immedialtely after the sound is started. Audio always runs in the background, in a seperate thread, so execution returns to your main() function right after the call to Play(). This is also what keeps audio from stuttering in games, even though they run with a low framerate. Putting the 'system("PAUSE")' you had earlier after the Play() call should do the trick.
The reason you are not hearing anything, is because your program exits immedialtely after the sound is started. Audio always runs in the background, in a seperate thread, so execution returns to your main() function right after the call to Play(). This is also what keeps audio from stuttering in games, even though they run with a low framerate. Putting the 'system("PAUSE")' you had earlier after the Play() call should do the trick.
"Stupid bug! You go squish now!!" - Homer Simpson
#7
Posted 07 November 2007 - 09:32 PM
Hi,
think you have do to the same homework as I
I still have some problems, which you have already solved:
so, i try to use a streaming buffer, instead of a static buffer. so i want to use a buffer with the size of 64 samples and refill it as often as needed.
so if you have tried to use a streaming buffer as well, please post your code here or help my finding the error in mine...
greetz, walter
think you have do to the same homework as I
I still have some problems, which you have already solved:
so, i try to use a streaming buffer, instead of a static buffer. so i want to use a buffer with the size of 64 samples and refill it as often as needed.
so if you have tried to use a streaming buffer as well, please post your code here or help my finding the error in mine...
greetz, walter
#include <dsound.h>
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "windows.h"
static const bool WRITE_TO_FILE = true;
static const float M_PI = 3.14159265;
static const int SAMPLE_RATE = 44100;
static const int BUFFER_SIZE = 64;
static const int CHANNELS = 2;
static const int AMPLITUDE = 1;
static const float TIME_PER_SAMPLE = 1.0f / (float) SAMPLE_RATE;
enum
{
TRIANGLE,
SQUARE,
SAWTOOTH,
SINE
};
//GLOBALS
//direct sound object
static LPDIRECTSOUND8 lpDS;
//parameter defaults
int waveform = SINE;
int frequency = 440;
float duration = 1;
float* buffer;
using namespace std;
bool InitAudio(){
if (DS_OK==DirectSoundCreate8(NULL,&lpDS,NULL)) //create direct sound object
{
HRESULT hr = lpDS->SetCooperativeLevel(GetForegroundWindow(), DSSCL_NORMAL);
if (FAILED(hr))
{
printf("SetCooperativeLevel failed!");
return (FALSE);
/*
switch(hr){
case DSERR_ALLOCATED:
printf("DSERR_ALLOCATED\n");
break;
case DSERR_INVALIDPARAM:
printf("DSERR_INVALIDPARAM\n");
break;
case DSERR_UNINITIALIZED:
printf("DSERR_UNINITIALIZED\n");
break;
case DSERR_UNSUPPORTED:
printf("DSERR_UNSUPPORTED\n");
break;
};
*/
}
return TRUE;
}
else //DSObj creation was unsuccessful
{
printf("Could Not Create Direct Sound Object");
return (FALSE);
}
}
void ShutdownAudio(){
if (lpDS)
{
IDirectSound_Release(lpDS);
}
else
{
printf("Sound was not initialized and cannot Exit!");
}
}
HRESULT CreateBasicBuffer(LPDIRECTSOUND8 lpDirectSound, LPDIRECTSOUNDBUFFER8* ppDsb8)
{
WAVEFORMATEX wfx;
DSBUFFERDESC dsbdesc;
LPDIRECTSOUNDBUFFER pDsb = NULL;
HRESULT hr;
// Set up WAV format structure.
memset(&wfx, 0, sizeof(WAVEFORMATEX));
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2;
wfx.nSamplesPerSec = 44100;
wfx.nBlockAlign = 8;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
wfx.wBitsPerSample = 32;
// Set up DSBUFFERDESC structure. // DSBCAPS_GETCURRENTPOSITION2
memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
dsbdesc.dwFlags =
DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY
| DSBCAPS_GLOBALFOCUS;
dsbdesc.dwBufferBytes = BUFFER_SIZE*CHANNELS*sizeof(float);//duration * wfx.nAvgBytesPerSec; //fix the buffer bytes! might be 64 BUFFER_SIZE//
dsbdesc.lpwfxFormat = &wfx;
// Create buffer.
hr = lpDirectSound->CreateSoundBuffer(&dsbdesc, &pDsb, NULL);
if (SUCCEEDED(hr))
{
hr = pDsb->QueryInterface(IID_IDirectSoundBuffer8, (LPVOID*)ppDsb8);
pDsb->Release();
}
return hr;
}
BOOL AppWriteDataToBuffer(
LPDIRECTSOUNDBUFFER8 lpDsb, // The buffer.
DWORD dwOffset, // Our own write cursor.
float* lpbSoundData, // Start of our data.
DWORD dwSoundBytes) // Size of block to copy.
{
LPVOID lpvPtr1;
DWORD dwBytes1;
LPVOID lpvPtr2;
DWORD dwBytes2;
HRESULT hr;
// Obtain memory address of write block. This will be in two parts
// if the block wraps around.
hr = lpDsb->Lock(dwOffset, dwSoundBytes, &lpvPtr1,
&dwBytes1, &lpvPtr2, &dwBytes2, 0);
// If the buffer was lost, restore and retry lock.
if (DSERR_BUFFERLOST == hr)
{
lpDsb->Restore();
hr = lpDsb->Lock(dwOffset, dwSoundBytes,
&lpvPtr1, &dwBytes1,
&lpvPtr2, &dwBytes2, 0);
}
if (SUCCEEDED(hr))
{
// Write to pointers.
//memcpy(lpvWrite, &buffer[0], dwLength);
CopyMemory(lpvPtr1, lpbSoundData, dwBytes1); //CopyMemory(void* dest, void * source, size_t length);
if (NULL != lpvPtr2)
{
CopyMemory(lpvPtr2, lpbSoundData+dwBytes1, dwBytes2);
}
// Release the data back to DirectSound.
hr = lpDsb->Unlock(lpvPtr1, dwBytes1, lpvPtr2, dwBytes2);
if (SUCCEEDED(hr))
{
// Success.
return TRUE;
}
}
// Lock, Unlock, or Restore failed.
return FALSE;
}
int main(int argc, char** argv) // waveform(int[0,3]) f(hz) duration(s)
{
//input params
if( 0 != argv[1] ){
waveform = atoi(argv[1]);
}
if( 0 != argv[2] ){
frequency = atoi(argv[2]);
}
if( 0 != argv[3] ){
duration = atof(argv[3]);
}
if ( !InitAudio() ) {
printf("InitAudio failed!\n");
return 1;
}
FILE *fout;
if (WRITE_TO_FILE){
fout = fopen("data.dat", "wt");
}
//create secondary buffer
LPDIRECTSOUNDBUFFER8 secondaryBuffer = 0;
CreateBasicBuffer(lpDS, &secondaryBuffer);
float time = 0;
int buffer_amount = int(ceil( (float)duration * ((float)SAMPLE_RATE / (float)BUFFER_SIZE)));
//cout << buffer_amount << "\n";
for(int i=0; i<buffer_amount;i++){
//int bufSiz = CHANNELS*duration*SAMPLE_RATE;
buffer = new float[BUFFER_SIZE*CHANNELS];
float *ptr = buffer;
for(int j=0; j<BUFFER_SIZE; j++) {
switch(waveform){
case SINE:
ptr[1] = AMPLITUDE * sinf(time * frequency * M_PI * 2.0f);
break;
case TRIANGLE:
ptr[1] = AMPLITUDE * sinf(time * frequency * M_PI * 2.0f);
break;
case SQUARE:
ptr[1] = AMPLITUDE * sinf(time * frequency * M_PI * 2.0f);
break;
case SAWTOOTH:
ptr[1] = AMPLITUDE * sinf(time * frequency * M_PI * 2.0f);
break;
};
ptr[2] = ptr[1];
if (WRITE_TO_FILE){
fprintf(fout, "%f %f\n", time, ptr[1]);
}
time += TIME_PER_SAMPLE;
ptr += CHANNELS;
}
LPDWORD playCursor = 0;
LPDWORD writeCursor = 0;
secondaryBuffer->GetCurrentPosition(playCursor, writeCursor);
//cout << playCursor << "\n";
//cout << writeCursor << "\n";
AppWriteDataToBuffer(secondaryBuffer, 0, &buffer[0], BUFFER_SIZE * CHANNELS * sizeof(float));
//buffer voll, kopiers in secondary buffer und ab die post
//while(
secondaryBuffer->Play(0, 0, DSBPLAY_LOOPING);
}
if (WRITE_TO_FILE){
fclose(fout);
}
cout << "waveform: " << waveform << " - frequency: " << frequency << " - duration: " << duration << "\n";
/*LPVOID lpvWrite;
DWORD dwLength;
//when you lock the buffer you can write into it.
secondaryBuffer->Lock(0, 0, &lpvWrite, &dwLength, 0, 0, DSBLOCK_ENTIREBUFFER);
memcpy(lpvWrite, &buffer[0], dwLength);
secondaryBuffer->Unlock(lpvWrite, dwLength, 0, 0);
secondaryBuffer->Play(0, 0, 0); //for streaming with this flag: DSBPLAY_LOOPING */
//wait for keypress to exit
char c;
cout << "press enter ...";
cin.get(c);
//close direct sound device
ShutdownAudio();
//delete the buffer
//delete buffer;
return 0;
}
#8
Posted 08 November 2007 - 08:23 AM
So, I switched to streaming buffers, too. And my program is nearly complete, BUT:
if I use streaming buffers, I need position notifications, so I can fill the first half of my 1024byte buffer when the second half is played and fill the second half of the buffer when the first half is played.
I managed to get it working for ONE position notification. however, when I set up more than one notification, the initialisation ->SetNotificationPosition fails.
Why doesn't it work with 2 NotificationPositions?! Do I need an extra SoundBuffer?
In the DX SDK there's an example solution using more than one position notification, too. It works for them, I did the same, but Initialisation fails every time I try...
if I use streaming buffers, I need position notifications, so I can fill the first half of my 1024byte buffer when the second half is played and fill the second half of the buffer when the first half is played.
I managed to get it working for ONE position notification. however, when I set up more than one notification, the initialisation ->SetNotificationPosition fails.
Why doesn't it work with 2 NotificationPositions?! Do I need an extra SoundBuffer?
In the DX SDK there's an example solution using more than one position notification, too. It works for them, I did the same, but Initialisation fails every time I try...
#include "stdafx.h"
#include <dsound.h>
#define _USE_MATH_DEFINES
#include <cmath>
#include <windows.h>
#include <string>
#include <iostream>
using namespace std;
LPDIRECTSOUND8 lpds;
LPDIRECTSOUNDBUFFER lpdsbuffer;
WAVEFORMATEX wfx;
DSBUFFERDESC dsbdesc;
HWND hwnd;
short* buffer = new short[44100 * 2];
bool playing = false;
HWND GetConsoleHwnd(void){
HWND cWindowHandle;
LPCWSTR newtitle = (LPCWSTR) L"Audio Programming - Lesson 1";
SetConsoleTitle(newtitle);
Sleep(40);
cWindowHandle=FindWindow(NULL, newtitle);
return(cWindowHandle);
}
HRESULT createSoundObject(void){
HRESULT hr;
hr = DirectSoundCreate8(NULL,&lpds,NULL);
hr = CoInitializeEx(NULL, 0);
hr = lpds->SetCooperativeLevel(hwnd,DSSCL_NORMAL);
return hr;
}
WAVEFORMATEX setWaveFormat(void){
WAVEFORMATEX wfx;
memset(&wfx, 0, sizeof(WAVEFORMATEX));
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2;
wfx.wBitsPerSample = 16;
wfx.nSamplesPerSec = 44100;
wfx.nBlockAlign = 4;
wfx.nAvgBytesPerSec = 44100 * 4;
return wfx;
}
DSBUFFERDESC setBufferDescription(){
DSBUFFERDESC dsbdesc;
memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
dsbdesc.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2;
dsbdesc.dwBufferBytes = 1024;
dsbdesc.lpwfxFormat = &wfx;
return dsbdesc;
}
HRESULT createSecondarySoundBuffer(void){
HRESULT hr = lpds->CreateSoundBuffer(&dsbdesc,&lpdsbuffer,NULL);
return hr;
}
HRESULT fillSoundBuffer(bool first){
bool firsthalf = first;
LPVOID lpvWrite;
DWORD dwLength;
HRESULT hr = lpdsbuffer->Lock(0,dsbdesc.dwBufferBytes,&lpvWrite,&dwLength,NULL,NULL,DSBLOCK_ENTIREBUFFER);
if(SUCCEEDED(hr)){
memcpy(lpvWrite, buffer, dwLength);
hr = lpdsbuffer->Unlock(lpvWrite,dwLength,NULL,NULL);
}
return hr;
}
BOOL fillBufferWithWaveForm(string form){
if(form == "sine"){
short* ptr = buffer;
unsigned short i;
float amp = 1.0f;
float tmp;
short output;
for(i=0;i<44100;i++){
tmp = amp * sinf(1000.0f * 2.0f * M_PI * ((float)i/44100.0f));
output = (short)(tmp*32767);
ptr[0] = output;
ptr[1] = output;
ptr += 2;
}
return true;
}
}
int _tmain(int argc, char* argv[])
{
HRESULT hr;
BOOL formFound = false;
string waveform = "sine";
// Rename the ConsoleWindow and retrieve its
// handle by looking up its new name in Windows
hwnd = GetConsoleHwnd();
// Create the Basic LPDIRECTSOUND8 object
hr = createSoundObject();
// Set the default wave format (hard coded)
wfx = setWaveFormat();
// Set the default buffer description (hard coded)
dsbdesc = setBufferDescription();
// Create the secondary sound buffer
hr = createSecondarySoundBuffer();
// Generate a waveform and put it into the playback array
formFound = fillBufferWithWaveForm(waveform);
// fill the secondary sound buffer entirely with the playback array data
hr = fillSoundBuffer(true);
// Start playback at position 0 and loop this sound until explicitely stopped
lpdsbuffer->SetCurrentPosition(0);
// Create Notification Handles
HANDLE NotifyEvent[2];
NotifyEvent[0] = CreateEvent(NULL,TRUE,FALSE,NULL);
NotifyEvent[1] = CreateEvent(NULL,TRUE,FALSE,NULL);
LPDIRECTSOUNDNOTIFY8 lpDsNotify;
DSBPOSITIONNOTIFY PositionNotify[2];
if (hr = lpdsbuffer->QueryInterface(IID_IDirectSoundNotify8,(LPVOID*)&lpDsNotify) == DS_OK){
PositionNotify[0].dwOffset = 512;
PositionNotify[0].hEventNotify = NotifyEvent[0];
PositionNotify[1].dwOffset = 1024;
PositionNotify[1].hEventNotify = NotifyEvent[1];
if(hr = lpDsNotify->SetNotificationPositions(2, PositionNotify) != DS_OK){
cout << hr << endl;
cout << "Error while setting up Notification Positions!" << endl;
}
else{
lpDsNotify->Release();
}
}
else{
cout << "Notification settings failed!" << endl;
}
hr = lpdsbuffer->Play(0,0,DSBPLAY_LOOPING);
printf("Buffer set up successfully! Playing back sound... \n \n");
playing = true;
while(playing){
hr = WaitForMultipleObjects(2,NotifyEvent,FALSE,INFINITE);
//cout << hr << endl;
if(hr-WAIT_OBJECT_0 == 0){
cout << "Notify bei 512!" << endl;
ResetEvent(NotifyEvent[0]);
}
else if(hr-WAIT_OBJECT_0 == 1){
cout << "Notify bei 1024!" << endl;
ResetEvent(NotifyEvent[1]);
}
}
system("PAUSE");
lpdsbuffer->Stop();
lpdsbuffer->Release();
lpds->Release();
return 0;
}
#9
Posted 08 November 2007 - 08:27 AM
oh my god, I am so stupid!!!
setting a notification at position 1024, when the buffer only holds 0-1023 MIGHT be the problem :-)
Now it works, I just need to keep an eye on the data from my data-array, so that the right position and right amount of data gets streamed to the soundbuffer.
good luck, walter!
setting a notification at position 1024, when the buffer only holds 0-1023 MIGHT be the problem :-)
Now it works, I just need to keep an eye on the data from my data-array, so that the right position and right amount of data gets streamed to the soundbuffer.
good luck, walter!
1 user(s) are reading this topic
0 members, 1 guests, 0 anonymous users











