/* FluidSynth - A Software Synthesizer * * Copyright (C) 2003 Peter Hanappe and others. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307, USA */ /* fluid_dart.c * * Driver for OS/2 DART * */ #include "fluid_adriver.h" #include "fluid_settings.h" #include "fluid_sys.h" #if DART_SUPPORT /* To avoid name conflict */ #undef VERSION #define INCL_DOS #include #define INCL_OS2MM #include #define NUM_MIX_BUFS 2 /** fluid_dart_audio_driver_t * * This structure should not be accessed directly. Use audio port * functions instead. */ typedef struct { fluid_audio_driver_t driver; fluid_synth_t* synth; int frame_size; USHORT usDeviceID; /* Amp Mixer device id */ MCI_MIX_BUFFER MixBuffers[NUM_MIX_BUFS]; /* Device buffers */ MCI_MIXSETUP_PARMS MixSetupParms; /* Mixer parameters */ MCI_BUFFER_PARMS BufferParms; /* Device buffer parms */ } fluid_dart_audio_driver_t; static fluid_dart_audio_driver_t* m_dev; static HMODULE m_hmodMDM = NULLHANDLE; static ULONG (APIENTRY *m_pfnmciSendCommand)(USHORT, USHORT, ULONG, PVOID, USHORT) = NULL; fluid_audio_driver_t* new_fluid_dart_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth); int delete_fluid_dart_audio_driver(fluid_audio_driver_t* p); void fluid_dart_audio_driver_settings(fluid_settings_t* settings); static LONG APIENTRY fluid_dart_audio_run( ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags ); /************************************************************** * * DART audio driver * */ void fluid_dart_audio_driver_settings(fluid_settings_t* settings) { fluid_settings_register_str(settings, "audio.dart.device", "default", 0, NULL, NULL); } fluid_audio_driver_t* new_fluid_dart_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth) { fluid_dart_audio_driver_t* dev; double sample_rate; int periods, period_size; UCHAR szFailedName[ 256 ]; MCI_AMP_OPEN_PARMS AmpOpenParms; int i; ULONG rc; dev = FLUID_NEW(fluid_dart_audio_driver_t); if (dev == NULL) { FLUID_LOG(FLUID_ERR, "Out of memory"); return NULL; } FLUID_MEMSET(dev, 0, sizeof(fluid_dart_audio_driver_t)); fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate); fluid_settings_getint(settings, "audio.periods", &periods); fluid_settings_getint(settings, "audio.period-size", &period_size); /* check the format */ if (!fluid_settings_str_equal(settings, "audio.sample-format", "16bits")) { FLUID_LOG(FLUID_ERR, "Unhandled sample format"); goto error_recovery; } dev->synth = synth; dev->frame_size = 2 * sizeof(short); /* Load only once */ if( m_hmodMDM == NULLHANDLE ) { rc = DosLoadModule(szFailedName, sizeof(szFailedName), "MDM.DLL", &m_hmodMDM); if (rc != 0 ) { FLUID_LOG(FLUID_ERR, "Cannot load MDM.DLL for DART due to %s", szFailedName); goto error_recovery; } rc = DosQueryProcAddr(m_hmodMDM, 1, NULL, (PFN *)&m_pfnmciSendCommand); if (rc != 0 ) { FLUID_LOG(FLUID_ERR, "Cannot find mciSendCommand() in MDM.DLL"); DosFreeModule(m_hmodMDM); m_hmodMDM = NULLHANDLE; goto error_recovery; } } /* open the mixer device */ FLUID_MEMSET(&AmpOpenParms, 0, sizeof(MCI_AMP_OPEN_PARMS)); AmpOpenParms.usDeviceID = (USHORT)0; AmpOpenParms.pszDeviceType = (PSZ)MCI_DEVTYPE_AUDIO_AMPMIX; rc = m_pfnmciSendCommand(0, MCI_OPEN, MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE, (PVOID)&AmpOpenParms, 0); if (rc != MCIERR_SUCCESS) { FLUID_LOG(FLUID_ERR, "Cannot open DART, rc = %lu", rc); goto error_recovery; } dev->usDeviceID = AmpOpenParms.usDeviceID; /* Set the m_MixSetupParms data structure to match the requirements. * This is a global that is used to setup the mixer. */ dev->MixSetupParms.ulBitsPerSample = BPS_16; dev->MixSetupParms.ulFormatTag = MCI_WAVE_FORMAT_PCM; dev->MixSetupParms.ulSamplesPerSec = sample_rate; dev->MixSetupParms.ulChannels = 2; /* Setup the mixer for playback of wave data */ dev->MixSetupParms.ulFormatMode = MCI_PLAY; dev->MixSetupParms.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO; dev->MixSetupParms.pmixEvent = fluid_dart_audio_run; rc = m_pfnmciSendCommand(dev->usDeviceID, MCI_MIXSETUP, MCI_WAIT | MCI_MIXSETUP_INIT, (PVOID)&dev->MixSetupParms, 0); if (rc != MCIERR_SUCCESS) { FLUID_LOG(FLUID_ERR, "Cannot setup DART, rc = %lu", rc); goto error_recovery; } /* Set up the m_BufferParms data structure and allocate * device buffers from the Amp-Mixer */ dev->BufferParms.ulNumBuffers = NUM_MIX_BUFS; dev->BufferParms.ulBufferSize = periods * period_size * dev->frame_size; dev->BufferParms.pBufList = dev->MixBuffers; rc = m_pfnmciSendCommand(dev->usDeviceID, MCI_BUFFER, MCI_WAIT | MCI_ALLOCATE_MEMORY, (PVOID)&dev->BufferParms, 0); if ((USHORT)rc != MCIERR_SUCCESS) { FLUID_LOG(FLUID_ERR, "Cannot allocate memory for DART, rc = %lu", rc); goto error_recovery; } /* Initialize all device buffers. */ for (i = 0; i < NUM_MIX_BUFS; i++) { FLUID_MEMSET(dev->MixBuffers[i].pBuffer, 0, dev->BufferParms.ulBufferSize); dev->MixBuffers[i].ulBufferLength = dev->BufferParms.ulBufferSize; dev->MixBuffers[i].ulFlags = 0; fluid_synth_write_s16(dev->synth, dev->MixBuffers[i].ulBufferLength / dev->frame_size, dev->MixBuffers[i].pBuffer, 0, 2, dev->MixBuffers[i].pBuffer, 1, 2 ); } /* Write buffers to kick off the amp mixer. */ dev->MixSetupParms.pmixWrite(dev->MixSetupParms.ulMixHandle, dev->MixBuffers, NUM_MIX_BUFS); m_dev = dev; return (fluid_audio_driver_t*) dev; error_recovery: delete_fluid_dart_audio_driver((fluid_audio_driver_t*) dev); return NULL; } int delete_fluid_dart_audio_driver(fluid_audio_driver_t* p) { fluid_dart_audio_driver_t* dev = (fluid_dart_audio_driver_t*) p; if (dev == NULL) { return FLUID_OK; } if (dev->usDeviceID != 0) { MCI_GENERIC_PARMS GenericParms; /* Send message to stop the audio device */ m_pfnmciSendCommand(dev->usDeviceID, MCI_STOP, MCI_WAIT, (PVOID)&GenericParms, 0); /* Deallocate device buffers */ m_pfnmciSendCommand(dev->usDeviceID, MCI_BUFFER, MCI_WAIT | MCI_DEALLOCATE_MEMORY, (PVOID)&dev->BufferParms, 0); /* Close device the mixer device */ m_pfnmciSendCommand(dev->usDeviceID, MCI_CLOSE, MCI_WAIT, (PVOID)&GenericParms, 0); } FLUID_FREE(dev); return FLUID_OK; } static LONG APIENTRY fluid_dart_audio_run( ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags ) { switch( ulFlags ) { case MIX_STREAM_ERROR | MIX_WRITE_COMPLETE: /* error occur in device */ case MIX_WRITE_COMPLETE: /* for playback */ FLUID_MEMSET(pBuffer->pBuffer, 0, pBuffer->ulBufferLength); fluid_synth_write_s16(m_dev->synth, pBuffer->ulBufferLength / m_dev->frame_size, pBuffer->pBuffer, 0, 2, pBuffer->pBuffer, 1, 2 ); m_dev->MixSetupParms.pmixWrite(m_dev->MixSetupParms.ulMixHandle, pBuffer, 1); break; } return TRUE; } #endif /* #if DART_SUPPORT */