Programably make and play a sound through speakers

2020-07-18 02:51发布

问题:

I'm making a game in native vc++ (not .Net)

I'm looking for a way to play a noise (maybe 8 bit or something) through the real speakers (not internal). I know about PlaySound, but I don't want to make my EXE big. I want to program the sound.

Is there an api way (kinda like Beep() ) but that plays through the real speakers?

Thanks

回答1:

You mention that you know about PlaySound. One of the it's flags (SND_MEMORY) will allow you to play a WAVE that is already loaded into memory, i.e. a buffer that you have created yourself. As long as the buffer has the appropriate WAVE header, whatever you you put in there should play through the speakers.

The header is a 44 byte block that is fairly straight forward

struct WaveHeader
{
    DWORD chunkID;       // 0x46464952 "RIFF" in little endian
    DWORD chunkSize;     // 4 + (8 + subChunk1Size) + (8 + subChunk2Size)
    DWORD format;        // 0x45564157 "WAVE" in little endian

    DWORD subChunk1ID;   // 0x20746d66 "fmt " in little endian
    DWORD subChunk1Size; // 16 for PCM
    WORD  audioFormat;   // 1 for PCM, 3 fot EEE floating point , 7 for μ-law
    WORD  numChannels;   // 1 for mono, 2 for stereo
    DWORD sampleRate;    // 8000, 22050, 44100, etc...
    DWORD byteRate;      // sampleRate * numChannels * bitsPerSample/8
    WORD  blockAlign;    // numChannels * bitsPerSample/8
    WORD  bitsPerSample; // number of bits (8 for 8 bits, etc...)

    DWORD subChunk2ID;   // 0x61746164 "data" in little endian
    DWORD subChunk2Size; // numSamples * numChannels * bitsPerSample/8 (this is the actual data size in bytes)
};

You'd set up your buffer with something similar to:

char *myBuffer = new char[sizeof(WaveHeader) + myDataSize];

WaveHeader *header = (WaveHeader*)myBuffer;
// fill out the header...

char *data = myBuffer + sizeof(WaveHeader); //jumps to beginning of data
// fill out waveform data...

So you use it something like:

PlaySound(myBuffer, NULL, SND_MEMORY | SND_ASYNC);

I'm assuming that you're going to be using you generated sound for the lifetime of you app. If you aren't, be careful with that SND_ASYNC flag. That is, don't go freeing the buffer directly after you call PlaySound (while it is still in use).

MSDN PlaySound Docs
A page with more detail on the WAV header (OLD - not working now)

DirectX also supports playing audio from in-memory buffers and is a much more powerful API, but it maybe overkill for what you need to do :)



回答2:

While there are several possibilities on windows, one of the simplest is sndPlaySound():

  • include mmsystem.h
  • link to winmm.lib
  • ::sndPlaySound("sound.wav", SND_ASYNC|SND_NODEFAULT);
  • to stop playback: ::sndPlaySound(NULL, NULL);

Of course there are other ways like mci and direct sound which might suit your needs better if you see more clearly what you need.



回答3:

I found this: http://www.xtremevbtalk.com/showthread.php?p=829281 it could be of some use to you



回答4:

My answer to another question could be helpfull, check it out here

I talk about an easy to use opensource api (The Synthesis Toolkit) that has classes to read/write wav files, and has easy to use wrapper classes to do realtime output to different drivers (wdm, asio, jack,...)

Imho it is easier to use than the winapi functions