257 lines
6.2 KiB
C
257 lines
6.2 KiB
C
|
#include <stdio.h>
|
||
|
#include <signal.h>
|
||
|
#include <mme/mme_api.h>
|
||
|
#include "mmc_buffers.h"
|
||
|
#include "mmc_cmdlin.h"
|
||
|
#include "mmc_memory.h"
|
||
|
#include "mmc_wave_format.h"
|
||
|
#include "mmc_wave_file.h"
|
||
|
#include "mmc_wave.h"
|
||
|
|
||
|
#define BUFFER_PAD 4
|
||
|
|
||
|
#define DEFAULT_NCHANNELS 1
|
||
|
#define DEFAULT_ENCODING WAVE_FORMAT_MULAW
|
||
|
#define DEFAULT_SAMPLESIZE 8
|
||
|
#define DEFAULT_SAMPLERATE 8000
|
||
|
|
||
|
#define DIV_ROUND_UP_(n,d) ((n + d - 1) / d)
|
||
|
#define ROUND_UP_(n,d) (DIV_ROUND_UP_(n,d) * d)
|
||
|
|
||
|
enum mmov_state
|
||
|
{
|
||
|
MMOV_START,
|
||
|
MMOV_PLAY,
|
||
|
MMOV_WAITING,
|
||
|
MMOV_CLOSE
|
||
|
};
|
||
|
|
||
|
#define NUM_DATA 32
|
||
|
struct mmov_soundformat
|
||
|
{
|
||
|
WAVEFORMATEX wave;
|
||
|
char extra_data[ NUM_DATA ];
|
||
|
};
|
||
|
|
||
|
static int Verbose;
|
||
|
static mmcWaveFileState_t wavefilestatus = mmcWaveFileStateInitialValue;
|
||
|
static mmcBufferList_t mmov_buffer = mmcBufferListInitialValue;
|
||
|
static enum mmov_state play_state;
|
||
|
|
||
|
static void mmov_cleanup( )
|
||
|
{
|
||
|
if (mmov_buffer.b)
|
||
|
{
|
||
|
mmcBuffersFree (&mmov_buffer);
|
||
|
}
|
||
|
mmcFreeAll ();
|
||
|
{
|
||
|
mmcWaveInFileClose (&wavefilestatus);
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
static void mmov_driver (HANDLE hWaveOut,
|
||
|
UINT wMsg,
|
||
|
DWORD dwInstance,
|
||
|
LPARAM lParam1,
|
||
|
LPARAM lParam2)
|
||
|
{
|
||
|
switch (wMsg)
|
||
|
{
|
||
|
case WOM_OPEN:
|
||
|
play_state = MMOV_PLAY;
|
||
|
break;
|
||
|
case WOM_CLOSE:
|
||
|
play_state = MMOV_CLOSE;
|
||
|
break;
|
||
|
|
||
|
case WOM_DONE:
|
||
|
{
|
||
|
int buffer_index = mmcWaveOutGotData (&mmov_buffer, lParam1);
|
||
|
mmcBuffer_p bp = &mmov_buffer.b[buffer_index];
|
||
|
mmcBufferSetStatus (&mmov_buffer, buffer_index, Empty,
|
||
|
mmov_buffer.nbytes);
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
mmcVerboseDisplay(Verbose, "Unknown index %d", wMsg);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void play_sound_mmov( char* FileName , int verbose )
|
||
|
{
|
||
|
HWAVEOUT hwaveout;
|
||
|
MMRESULT status;
|
||
|
int mask1;
|
||
|
int allDone;
|
||
|
|
||
|
static int uDeviceId = WAVE_MAPPER;
|
||
|
static int AdpcmBitsPerSample = 16;
|
||
|
static int AdpcmSamplesPerBlock = 0;
|
||
|
static int sizeBuffers = 0;
|
||
|
static int msBuffers = 0;
|
||
|
static int numBuffers = 4;
|
||
|
static struct mmov_soundformat sound_format =
|
||
|
{
|
||
|
{
|
||
|
DEFAULT_ENCODING,
|
||
|
DEFAULT_NCHANNELS,
|
||
|
DEFAULT_SAMPLERATE,
|
||
|
0,
|
||
|
0,
|
||
|
DEFAULT_SAMPLESIZE,
|
||
|
NUM_DATA
|
||
|
}, {
|
||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||
|
0, 0, 0, 0, 0, 0, 0, 0
|
||
|
}
|
||
|
};
|
||
|
|
||
|
Verbose = verbose;
|
||
|
play_state = MMOV_START;
|
||
|
|
||
|
/* Open the Wave In file */
|
||
|
if (mmcWaveInFileOpen (FileName, &sound_format.wave, &wavefilestatus) != 0)
|
||
|
{
|
||
|
mmcVerboseDisplay(Verbose,"Error opening input file");
|
||
|
mmov_cleanup();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( sound_format.wave.wFormatTag == WAVE_FORMAT_PCM)
|
||
|
mmcVerboseDisplay(Verbose,"PCM file");
|
||
|
else if ( sound_format.wave.wFormatTag == WAVE_FORMAT_MULAW)
|
||
|
mmcVerboseDisplay(Verbose,"mu-law file");
|
||
|
else if ( sound_format.wave.wFormatTag == WAVE_FORMAT_IMA_ADPCM)
|
||
|
mmcVerboseDisplay(Verbose,"IMA file");
|
||
|
else
|
||
|
mmcVerboseDisplay(Verbose,"Unknown sound format %d",
|
||
|
sound_format.wave.wFormatTag);
|
||
|
mmcVerboseDisplay(Verbose,"Channels = %d ", sound_format.wave.nChannels );
|
||
|
mmcVerboseDisplay(Verbose,"Sample rate = %d",
|
||
|
sound_format.wave.nSamplesPerSec);
|
||
|
mmcVerboseDisplay(Verbose,
|
||
|
"Sample size = %d", sound_format.wave.wBitsPerSample );
|
||
|
|
||
|
if( sound_format.wave.nChannels == 0)
|
||
|
sound_format.wave.nChannels = DEFAULT_NCHANNELS;
|
||
|
if( sound_format.wave.nSamplesPerSec == 0)
|
||
|
sound_format.wave.nSamplesPerSec = DEFAULT_SAMPLERATE;
|
||
|
if( sound_format.wave.wBitsPerSample == 0)
|
||
|
sound_format.wave.wBitsPerSample = DEFAULT_SAMPLESIZE;
|
||
|
|
||
|
if ( sound_format.wave.wFormatTag == WAVE_FORMAT_IMA_ADPCM ) {
|
||
|
AdpcmSamplesPerBlock = *(Uint16 *)(&sound_format.extra_data[0]);
|
||
|
}
|
||
|
|
||
|
if ( ( sound_format.wave.wFormatTag == WAVE_FORMAT_PCM) ||
|
||
|
( sound_format.wave.wFormatTag == WAVE_FORMAT_MULAW) ) {
|
||
|
mask1 = WAVE_FORMAT_FIX_BLOCK_ALIGN | WAVE_FORMAT_FIX_AVG_BPS;
|
||
|
mmcWaveFormatFix((LPPCMWAVEFORMAT)(&sound_format), mask1 );
|
||
|
}
|
||
|
|
||
|
if ( sound_format.wave.wFormatTag == WAVE_FORMAT_IMA_ADPCM) {
|
||
|
sizeBuffers = sound_format.wave.nBlockAlign;
|
||
|
msBuffers = sizeBuffers * 1000 /
|
||
|
(DIV_ROUND_UP_(AdpcmBitsPerSample,8) *
|
||
|
sound_format.wave.nSamplesPerSec *
|
||
|
sound_format.wave.nChannels);
|
||
|
|
||
|
|
||
|
} else {
|
||
|
if (!msBuffers && !sizeBuffers)
|
||
|
msBuffers = 1000/numBuffers;
|
||
|
|
||
|
if (msBuffers)
|
||
|
sizeBuffers =
|
||
|
ROUND_UP_(DIV_ROUND_UP_(msBuffers *
|
||
|
DIV_ROUND_UP_( sound_format.wave.wBitsPerSample,
|
||
|
8) *
|
||
|
sound_format.wave.nSamplesPerSec *
|
||
|
sound_format.wave.nChannels,1000), BUFFER_PAD);
|
||
|
else
|
||
|
{
|
||
|
sizeBuffers = ROUND_UP_(sizeBuffers, BUFFER_PAD);
|
||
|
msBuffers = sizeBuffers * 1000 /
|
||
|
(DIV_ROUND_UP_( sound_format.wave.wBitsPerSample,8) *
|
||
|
sound_format.wave.nSamplesPerSec *
|
||
|
sound_format.wave.nChannels);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
mmcVerboseDisplay(Verbose, "Buffer size = %d bytes or %d milliseconds",
|
||
|
sizeBuffers, msBuffers);
|
||
|
|
||
|
hwaveout = NULL;
|
||
|
|
||
|
status = mmcWaveOutOpen(&sound_format.wave, uDeviceId, &mmov_driver ,
|
||
|
WAVE_OPEN_SHAREABLE, &hwaveout);
|
||
|
|
||
|
if (status != MMSYSERR_NOERROR)
|
||
|
{
|
||
|
mmov_cleanup();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (mmcBuffersCreate (&mmov_buffer, numBuffers, sizeBuffers, BUFFER_PAD)
|
||
|
!= MMSYSERR_NOERROR)
|
||
|
{
|
||
|
mmov_cleanup();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (;;)
|
||
|
{
|
||
|
switch ( play_state )
|
||
|
{
|
||
|
case MMOV_START:
|
||
|
break;
|
||
|
|
||
|
case MMOV_PLAY:
|
||
|
status = mmcWaveOutQueueBufferAll (hwaveout, &mmov_buffer, Verbose,
|
||
|
&wavefilestatus, &allDone);
|
||
|
if (allDone)
|
||
|
play_state = MMOV_WAITING;
|
||
|
else
|
||
|
{
|
||
|
if (status != MMSYSERR_NOERROR)
|
||
|
{
|
||
|
mmov_cleanup();
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case MMOV_WAITING:
|
||
|
if ((mmcBufferFind(&mmov_buffer,Filling) != mmcBufferNone) ||
|
||
|
(mmcBufferFind(&mmov_buffer,Full) != mmcBufferNone) ||
|
||
|
(mmcBufferFind(&mmov_buffer,Playing) != mmcBufferNone))
|
||
|
break;
|
||
|
play_state = MMOV_CLOSE;
|
||
|
|
||
|
case MMOV_CLOSE:
|
||
|
status = mmcWaveOutClose (hwaveout, &mmov_buffer);
|
||
|
if (status != MMSYSERR_NOERROR)
|
||
|
{
|
||
|
mmov_cleanup();
|
||
|
return;
|
||
|
}
|
||
|
mmov_cleanup();
|
||
|
return;
|
||
|
|
||
|
default:
|
||
|
mmcVerboseDisplay(Verbose,"Unknown play_state %d", play_state);
|
||
|
mmov_cleanup();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
mmeWaitForCallbacks (); /* block so we don't hog 100% of the CPU */
|
||
|
mmeProcessCallbacks ();
|
||
|
}
|
||
|
}
|