home *** CD-ROM | disk | FTP | other *** search
- /* mmpm_audio.c */
-
- /* modified by Raymond Garcia for Multimedia OS/2 11/93, 12/93 */
- /* note that much of the code used is plucked and pruned from CLOCK from IBM */
-
-
- /* based on soundblaster_audio.c */
-
- /* modified by David Nichols for this PM MOD player */
-
- /* MODIFIED BY Michael Fulbright (MSF) to work with os/2 device driver */
-
- /* $Author: steve $
- * $Id: soundblaster_audio.c,v 1.1 1992/06/24 06:24:17 steve Exp steve $
- * $Revision: 1.1 $
- * $Log: soundblaster_audio.c,v $
- * Revision 1.1 1992/06/24 06:24:17 steve
- * Initial revision
- */
-
- #define INCL_DOS
-
- #include <os2.h>
- #include <stdio.h>
- #include <stdlib.h>
-
- #define INCL_OS2MM /* Required for MCI & MMIO headers */
- #include "os2me.h"
-
- #include "defs.h"
-
-
- typedef struct pls
- {
- ULONG ulCommand;
- ULONG ulOperandOne;
- ULONG ulOperandTwo;
- ULONG ulOperandThree;
- } PLAY_LIST_STRUCTURE_T;
-
- #define MCI_ERROR_STRING_LENGTH 128
-
-
-
-
-
-
- #define NUMBER_OF_BUFFERS 4
-
- #define MSG_NOTIFICATION 1130
- #define MSG_BUFFERS_COMPLETE 1140
- #define MSG_BUFFER0_EMPTIED 1131
- #define MSG_BUFFER1_EMPTIED 1132
- #define MSG_BUFFER2_EMPTIED 1133
- #define MSG_BUFFER3_EMPTIED 1134
-
-
- HWND host; /* this is the window graceful enough to accept messages
- for us and pass them our way. (dialog box) */
-
- int playing = 0;
-
-
- MCI_OPEN_PARMS mciOpenParameters; /* Open structure. */
-
-
- unsigned char *Buffer[ NUMBER_OF_BUFFERS ];
- unsigned long BufferSize;
-
-
-
- unsigned current_buffer = 0;
- unsigned full_buffers = 0x00; /* NUMBER_OF_BUFFERS bits flagging full */
- /* 1 << buffer_number */
- /* these are manipulated by message handler (clear) */
- /* and by flush_buffer (set) */
- #define ALL_BUFFERS_FULL 0x0F /* 00001111 */
-
- unsigned char *buffer; /* points to Buffer[current_buffer] */
- unsigned buf_index = 0; /* index within that buffer to add data */
-
-
- HEV aBufferHasBeenFreed; /* event triggered via message to dialog */
-
-
-
-
- #define NUMBER_OF_COMMANDS 12
-
- /* the following playlist uses the NUMBER_OF_BUFFERS buffers as a circular buffer */
-
- PLAY_LIST_STRUCTURE_T apltPlayList[ 1 ][ NUMBER_OF_COMMANDS ] =
- {
- {
- /* 0 */ { DATA_OPERATION, 0,0,0 }, /* buffer 0 */
- /* 1 */ { MESSAGE_OPERATION, 0,MSG_BUFFER2_EMPTIED,0 },
- /* 2 */ { DATA_OPERATION, 0,0,0 },
- /* 3 */ { MESSAGE_OPERATION, 0,MSG_BUFFER3_EMPTIED,0 },
- /* 4 */ { DATA_OPERATION, 0,0,0 },
- /* 5 */ { MESSAGE_OPERATION, 0,MSG_BUFFER0_EMPTIED,0 },
- /* 6 */ { DATA_OPERATION, 0,0,0 },
- /* 7 */ { MESSAGE_OPERATION, 0,MSG_BUFFER1_EMPTIED,0 },
- /* 8 */ { BRANCH_OPERATION, 0, 0, 0 }, /* branch back to loop */
- /* 9 */ { MESSAGE_OPERATION, 0,MSG_BUFFERS_COMPLETE,0 },
- /* 10 */ { EXIT_OPERATION, 0,0,0 }
- }
- };
-
- #define PlayListData(bufnum) (apltPlayList[0][(bufnum)*2])
-
-
-
-
-
- void ReportMMError()
- {
- ULONG mciRC;
- static CHAR acErrorStringBuffer[ MCI_ERROR_STRING_LENGTH ];
-
-
- mciRC =
- mciGetErrorString(
- mciRC,
- (PSZ)&acErrorStringBuffer[ 0 ],
- (USHORT) MCI_ERROR_STRING_LENGTH );
-
- /*
- * Make sure that the retrieving of the error string was successfull.
- */
- if ( mciRC != MCIERR_SUCCESS )
- strcpy( acErrorStringBuffer, "unknown error");
-
- /*
- * Show the error string that was retrieved by the mciGetErrorString
- * MMPM/2 API.
- */
- WinMessageBox(
- HWND_DESKTOP, /* Parent handle. */
- HWND_DESKTOP, /* Owner handle of the message box. */
- acErrorStringBuffer, /* String to show in the message box. */
- (PSZ)"Open Waveform Audio Device Error",
- 911, /* Message Box Id. */
- MB_OK | MB_INFORMATION ); /* The style of the message box. */
-
- }
-
-
-
-
-
- /* this function is exported to the main dialog window procedure,
- such that the user dialog passes multimedia (MM_) messages to us */
-
- MRESULT resetBuffer( int n )
- {
- ULONG scratch;
- /* erase buffer full flag */
- full_buffers &= ~( 1 << n );
- /* signal event */
- DosPostEventSem( aBufferHasBeenFreed ); /* start the other process */
- DosResetEventSem( aBufferHasBeenFreed, &scratch ); /* and reset the semaphore */
- return 0;
- }
-
-
-
- /* the following function has to be called by the host dialog window
- when an MM_MCINOTIFY message appears in the queue */
- MRESULT EXPENTRY MM_MCINOTIFY_Handle( USHORT msg, MPARAM mp1, MPARAM mp2 )
- {
-
- switch( (long)mp2 )
- {
- case MSG_BUFFER0_EMPTIED :
- return resetBuffer( 0 );
-
- case MSG_BUFFER1_EMPTIED :
- return resetBuffer( 1 );
-
- case MSG_BUFFER2_EMPTIED :
- return resetBuffer( 2 );
-
- case MSG_BUFFER3_EMPTIED :
- return resetBuffer( 3 );
- }
-
- return 0;
- }
-
-
-
-
- void restoreparams()
- {
- /* restore audio device to original state */
- }
-
-
-
-
-
- /* 256th of primary/secondary source for that side. */
- static int primary, secondary;
-
- void set_mix (int percent)
- {
- percent *= 256;
- percent /= 100;
- primary = percent;
- secondary = 512 - percent;
- }
-
-
- void next_buffer();
-
- void output_samples (int left, int right)
- {
- if (pref.stereo)
- {
- buffer[buf_index++] = (((left * primary + right * secondary) / 256) + (1 << 15)) >> 8;
- buffer[buf_index++] = (((right * primary + left * secondary) / 256) + (1 << 15)) >> 8;
- }
- else buffer[buf_index++] = (left + right + (1 << 15)) >> 8;
-
- if (buf_index>=BufferSize) next_buffer();
- }
-
-
-
- void startPlaying()
- {
- ULONG mciRC;
-
-
- mciRC = mciSendCommand(
- mciOpenParameters.usDeviceID, /* Device to play the chimes. */
- MCI_PLAY, /* MCI message. */
- MCI_NOTIFY, /* Flags for the MCI message. */
- (PVOID) &mciOpenParameters, /* Parameters for the message. */
- MSG_NOTIFICATION ); /* Parameter for notify message. */
-
- if (mciRC) ReportMMError();
-
- /* DosBeep( 880, 10 ); /* ############# */
-
- playing = 1;
- }
-
-
-
- void stopPlaying()
- {
- ULONG mciRC;
- mciRC =
- mciSendCommand(
- mciOpenParameters.usDeviceID, /* Device to play the chimes. */
- MCI_STOP, /* MCI message. */
- MCI_NOTIFY, /* Flags for the MCI message. */
- (PVOID) &mciOpenParameters, /* Parameters for the message. */
- MSG_NOTIFICATION ); /* Parameter for notify message. */
-
- if (mciRC) ReportMMError();
-
- playing = 0;
- }
-
-
- void flush_buffer()
- {
- /* output buffer to card - done automatically by playlist */
-
- }
-
-
- void next_buffer (void)
- {
-
- /* set correspondent length in playlist to match buf_index */
- PlayListData( current_buffer ).ulOperandTwo =
- (ULONG)buf_index;
- PlayListData( current_buffer ).ulOperandThree = 0;
- /* none of buffer has been played */
-
- /* reset the loop counter in the playlist for infinite looping */
- /* USING BRANCH NOT LOOP */
- /* apltPlayList[0][0].ulOperandThree = 0; */
-
-
- /* set current buffer as busy so we don't overwrite it */
- full_buffers |= (1 << current_buffer);
-
-
- /* increment to next buffer */
- current_buffer = (current_buffer + 1) % NUMBER_OF_BUFFERS;
- buffer = Buffer[current_buffer];
- buf_index = 0;
-
- if (!playing && full_buffers==ALL_BUFFERS_FULL) startPlaying();
-
- /* what? the next buffer isn't empty?
- go to a wait state on the event semaphore */
- while ( (1<<current_buffer) & full_buffers )
- {
- DosWaitEventSem( aBufferHasBeenFreed, 5000L ); /* SEM_INDEFINITE_WAIT ); */
- /* DosBeep( 440, 10 ); /* limit wait to 5 second increments */
- }
-
- /* DosBeep( 880, 2 ); */
- PlayListData( current_buffer ).ulOperandThree = 0;
- /* none of this buffer has been played either */
-
- full_buffers |= (1 << current_buffer);
-
- }
-
-
-
-
-
- void openDevice()
- {
- ULONG ulOpenFlags = MCI_WAIT | MCI_OPEN_PLAYLIST | MCI_OPEN_TYPE_ID;
- /* MCI_OPEN_SHAREABLE; */
- ULONG mciRC; /* MCI generic return code variable. */
-
-
- /*
- * Open the correct waveform device for the chimes with the MCI_OPEN
- * message to MCI.
- */
- mciOpenParameters.pszDeviceType = (PSZ)
- MAKEULONG ( MCI_DEVTYPE_WAVEFORM_AUDIO, 1 );
-
- /*
- * The address of the buffer containing the chime waveform file.
- */
- mciOpenParameters.pszElementName =
- (PSZ)&apltPlayList[ 0 ][ 0 ];
-
- /*
- * Initialize the MCI_OPEN_PARMS data structure with host
- * as callback handle for MM_MCIPASSDEVICE, then issue the MCI_OPEN
- * command with the mciSendCommand function. No alias is used.
- */
- mciOpenParameters.hwndCallback = host;
- mciOpenParameters.pszAlias = (CHAR) NULL;
-
- /*
- * Open the waveform file in the playlist mode.
- */
- mciRC =
- mciSendCommand(
- 0, /* We don't know the device yet. */
- MCI_OPEN, /* MCI message. */
- ulOpenFlags, /* Flags for the MCI message. */
- (PVOID) &mciOpenParameters, /* Parameters for the message. */
- 0 ); /* Parameter for notify message. */
-
- if ( mciRC != 0 )
- {
- ReportMMError();
- }
-
- }
-
-
-
- void flush_DMA_buffers();
-
- void setupPlayList( unsigned short DMAbuffersize )
- {
- int i=0;
- /* DMAbuffersize = 32; /* 931219 */
-
- BufferSize = DMAbuffersize * 1024L;
-
- for( ; i<NUMBER_OF_BUFFERS; i++ )
- {
- Buffer[i] = malloc( BufferSize );
- PlayListData( i ).ulOperandOne = (ULONG)Buffer[i];
- PlayListData( i ).ulOperandTwo = (ULONG)BufferSize;
- PlayListData( i ).ulOperandThree = 0;
- }
-
- flush_DMA_buffers();
- }
-
-
- int setupSampleRate( int frequency )
- {
- MCI_WAVE_SET_PARMS mwspWaveFormParameters; /* Waveform parameters. */
- ULONG ulRC; /* Return code. */
-
- /*
- * Fill the structure with zeros.
- */
- memset( &mwspWaveFormParameters, /* Object to fill with zeros. */
- 0, /* Value to place in object. */
- sizeof( mwspWaveFormParameters ) ); /* How many zeros's to use. */
-
- /*
- * Set structure values for the MCI_SET.
- */
- mwspWaveFormParameters.ulSamplesPerSec =
- (ULONG)frequency;
- mwspWaveFormParameters.usBitsPerSample =
- 8; /* for now. 16 later. then who knows. */
- mwspWaveFormParameters.usChannels =
- pref.stereo? 2 : 1;
- mwspWaveFormParameters.ulAudio =
- MCI_SET_AUDIO_ALL;
-
- /*
- * Set the number of channels.
- */
- ulRC =
- mciSendCommand(
- mciOpenParameters.usDeviceID,
- MCI_SET,
- MCI_WAIT | MCI_WAVE_SET_CHANNELS,
- (PVOID) &mwspWaveFormParameters,
- 0 );
-
- if (ulRC) ReportMMError();
-
- /*
- * Set the samples per second for the waveform file.
- */
- ulRC =
- mciSendCommand(
- mciOpenParameters.usDeviceID,
- MCI_SET,
- MCI_WAIT | MCI_WAVE_SET_SAMPLESPERSEC,
- (PVOID) &mwspWaveFormParameters,
- 0 );
-
- if (ulRC) ReportMMError();
-
- /*
- * Set the bits per second for the waveform file.
- */
- ulRC =
- mciSendCommand(
- mciOpenParameters.usDeviceID,
- MCI_SET,
- MCI_WAIT | MCI_WAVE_SET_BITSPERSAMPLE,
- (PVOID) &mwspWaveFormParameters,
- 0 );
-
- if (ulRC) ReportMMError();
-
- return frequency;
- }
-
-
- void createSemaphore()
- {
- DosCreateEventSem(
- (PSZ) NULL, /* No semaphore Name. Do not share. */
- &aBufferHasBeenFreed, /* Semaphore Handle. */
- (ULONG) NULL, /* Creation attributes. */
- (BOOL32) FALSE ); /* State of semaphore. */
-
- if (!aBufferHasBeenFreed)
- WinMessageBox(
- HWND_DESKTOP, /* Parent handle. */
- HWND_DESKTOP, /* Owner handle of the message box. */
- (PSZ)"unable to open event semaphore", /* String to show in the message box. */
- (PSZ)"Error",
- 911, /* Message Box Id. */
- MB_OK | MB_INFORMATION ); /* The style of the message box. */
- }
-
-
- int open_audio(int frequency, unsigned short DMAbuffersize)
- {
- /* DMAbuffersize is in kilobytes */
-
- createSemaphore();
- setupPlayList( DMAbuffersize );
- openDevice( );
- return setupSampleRate( frequency );
- }
-
-
-
- void waitForFinished()
- {
- if (!playing) return;
-
- if (buf_index) { /* throw out any ending sound */
- next_buffer();
- full_buffers &= ~(1 << current_buffer); /* leave this empty */
- }
-
- while ( full_buffers )
- {
- DosWaitEventSem( aBufferHasBeenFreed, 5000L ); /* SEM_INDEFINITE_WAIT ); */
- /* DosBeep( 440, 10 ); /* limit wait to 5 second increments */
- }
- }
-
- void flush_DMA_buffers()
- {
- /* now tell device driver to flush out internal buffers, abort-style */
-
- /* in other words, stop and reset the playlist */
- if (playing) waitForFinished(), stopPlaying();
-
- current_buffer = 0;
- buffer = Buffer[0];
- full_buffers = 1; /* set this one so we don't overwrite */
- buf_index = 0;
- }
-
-
- void close_audio (void)
- {
- ULONG ulRC;
- if (playing) stopPlaying();
-
- ulRC = mciSendCommand(
- mciOpenParameters.usDeviceID, /* Device to play the chimes. */
- MCI_CLOSE, /* MCI message. */
- MCI_WAIT, /* Flags for the MCI message. */
- (ULONG) NULL, /* Parameters for the message. */
- (ULONG) NULL ); /* Parameter for notify message. */
- if (ulRC) ReportMMError();
- }
-
-
-
-
-
-
-
-
- /* the following function has to be spliced into WM_INITDLG handling : */
- void MM_Set_Host( HWND hwnd )
- {
- host = hwnd;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- #if 0
-
- int fixparams = 0;
- int filterout;
- int filterin;
- int filterhi;
-
- /* 256th of primary/secondary source for that side. */
- static int primary, secondary;
-
- void restoreparams()
- {
-
- /* restore audio device to original state */
-
- }
-
- void set_mix (int percent)
- {
- percent *= 256;
- percent /= 100;
- primary = percent;
- secondary = 512 - percent;
- }
-
- int open_audio(int frequency, unsigned short DMAbuffersize)
- {
- /* DMAbuffersize is in kilobytes */
-
- trackerror(1, "Error opening audio device SBDSP$", FATAL_ERROR);
-
- /* pref.stereo? can we open stereo? */
-
- if (status !=0) pref.stereo=FALSE;
-
-
-
- if (pref.stereo) frequency *= 2; /* XXX Stereo takes twice the speed */
- /* do we need twice frequency for MMOS2? */
-
- if (frequency == 0) frequency = -1; /* read current frequency from driver */
-
- /* buffer = malloc (sizeof (SAMPLE) * frequency); /* Stereo makes x2 */
- /* buf_index = 0; */
-
- if (pref.stereo) return (frequency / 2);
- else return (frequency);
- }
-
- void output_samples (int left, int right)
- {
- if (pref.stereo)
- {
- buffer[buf_index++] = (((left * primary + right * secondary) / 256) + (1 << 15)) >> 8;
- buffer[buf_index++] = (((right * primary + left * secondary) / 256) + (1 << 15)) >> 8;
- }
- else buffer[buf_index++] = (left + right + (1 << 15)) >> 8;
- }
-
- void flush_buffer (void)
- {
- ULONG numread, status;
-
- status = DosWrite(hAudio, buffer, buf_index, &numread);
- if (status != 0)
- {
- char buf[80];
-
- sprintf(buf, "Error writing to audio device: %d, tried to write: %d, wrote: %d", status, buf_index, numread);
- trackerror (1, buf, FATAL_ERROR);
- }
- if (numread != buf_index)
- {
- char buf[80];
-
- sprintf(buf, "DosWrite mismatch, buf_index: %d, numread: %d", buf_index, numread);
- trackerror(1, buf, NONFATAL_ERROR);
- }
- buf_index = 0;
- }
-
- void flush_DMA_buffers()
- {
- ULONG status, datlen, parlen;
-
- /* now tell device driver to flush out internal buffers */
- parlen=0;
- datlen=0;
- status=DosDevIOCtl(hAudio, DSP_CAT, DSP_IOCTL_FLUSH,
- NULL, 0, &parlen, NULL, 0, &datlen);
- if (status != 0)
- {
- char buf[80];
-
- sprintf(buf, "Error flushing DMA buffers: %d", status);
- trackerror(1, buf, NONFATAL_ERROR);
- }
- }
-
- void close_audio (void)
- {
- DosClose(hAudio);
- }
-
-
- #endif