| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188 |
- /*
- ** Command & Conquer Generals(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program 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 General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /********************************************************************* Code **
- ** **
- ** Westwood Studios Pacific. **
- ** **
- ** Confidential Information **
- ** Copyright (C) 1998 - All Rights Reserved **
- ** **
- ******************************************************************************
- ** **
- ** Project: WAUDIO Library **
- ** **
- ** Module: Audio (AUD_) **
- ** **
- ** Version: $ID$ **
- ** **
- ** File name: wn32/dsound/r2/drv_dsnd.c **
- ** **
- ** Created by: 06/26/96 TR **
- ** **
- ** Description: Audio device driver for Win'95 Direct Sound **
- ** **
- ** **
- ** audioLoad : load system **
- ** audioUnload : unload system **
- ** audioOpen : open a unit **
- ** audioClose : close a unit **
- ** **
- ** audioOpenChannel : open an audio channel **
- ** audioCloseChannel : close an audio channel **
- ** audioStart : satrt a sample **
- ** audioStop : stop a sample **
- ** audioPause : pause a sample **
- ** audioResume : resume a sample **
- ** audioCheck : check if a sample is playing **
- ** audioUpdate : update sample attributes **
- ** audioQueueIt : queue up sample to play next **
- ** AUD_command : driver specific command **
- *****************************************************************************/
- #include <wpaudio/altypes.h> /* Always include this header first. */
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
- #pragma warning ( disable: 4706 )
- #pragma warning(disable:4201)
- #include <mmsystem.h>
- //
- // Colin: I'm taking the INITGUID stuff out here because we are now linking
- // the main RTS.exe to dxguid.lib, having this defined here causes duplicate
- // symbols when linking
- //
- // #define INITGUID // see comment above
- #include <dsound.h>
- // #undef INITGUID // see comment above
- #include <windows.h>
- #include "asimp3\mss.h"
- #include "asimp3\mp3dec.h"
- #include <wpaudio/profiler.h>
- #include <wpaudio/device.h>
- #include <wpaudio/channel.h>
- #include <wpaudio/thread.h>
- #include <wpaudio/win32.h>
- /*****************************************************************************
- ** Includes **
- *****************************************************************************/
- #include <wpaudio/driver.h> /* prototypes for driver code */
- /*****************************************************************************
- ** Externals **
- *****************************************************************************/
- /*****************************************************************************
- ** Defines **
- *****************************************************************************/
- #define vAUD_DRV_MAX_CHANNELS 100 /* this is arbitrary */
- #define vAUD_DRV_POLL_INTERVAL (SECONDS(1)/30) /* this frequency will determine the buffer sizes */
- #define vAUD_DRV_OVER_SAMPLE 8
- #define vAUD_DRV_FRAMES 4 // this must be at least 2
- #define vAUD_DRV_LAG_FRAMES 0 // follow behind play frame by this many frames
- #define vAUD_DRV_DBHALF -1000 // -10dB
- /*****************************************************************************
- ** Private Types **
- *****************************************************************************/
- #define STATE_READ_BLOCK 0
- #define STATE_WRITE_BLOCK 1
- #define STATE_DECODE_BLOCK 2
- #define STATE_INIT_BLOCK 3
- typedef struct
- {
- int previousValue;
- int index;
- } IMA_DATA;
- typedef struct
- {
- int idelta;
- short iCoef[2];
- } MS_DATA;
- typedef struct
- {
- ASISTREAM *asi;
- int in_pos; // start of data in in buffer
- } MP3_DATA;
- typedef int (CB_DECODE) ( struct AudioDriverChannelTag *);
- typedef struct _transfer
- {
- int state; // current state
- int next_state; //
- uint8 *in; // input buffer
- int in_bytes; // bytes to read
- int in_bytes_left; // bytes left to read
- int in_size; // current size of input buffer
- int in_size_needed; // required size of input buffer
- uint8 *out; // output buffer
- int out_bytes; // bytes to write
- int out_bytes_left; // bytes left to write
- int out_size; // current size of output buffer
- int out_size_needed; // required size of output buffer
- int channels; // number of channels
- int pending; // there is buffered data that still needs servicing
- int block_size;
- CB_DECODE *decode; // code to decode block
- IMA_DATA ima[2];
- MS_DATA ms[2];
- MP3_DATA mp3;
- } TRANSFER;
- typedef int (CB_TRANSFER) ( struct AudioDriverChannelTag *, uint8 *dst, int *dst_bytes, uint8 *src , int *src_bytes );
- typedef struct AudioDriverChannelTag
- {
- AudioChannel *chan; /* WCORE channel we belong to */
- volatile uint flags;
- /* play */
- volatile int pcm_pos; /* pcm playback position relative to the end of the sample */
- volatile uint frame; /* current frame position of play back */
- volatile TimeStamp last_poll; /* time of last poll */
- volatile TimeStamp poll_interval; /* time between polls */
- /* source data */
- volatile uint8 *src_start; /* start of source data */
- volatile int src_size; /* size of source (bytes) */
- /* transfer */
- volatile uint8 *src_pos; /* source sample data read pos*/
- volatile int src_left; /* number of bytes of source left */
- volatile ulong dst_pos; /* current write posistion in buffer */
- volatile ulong write_pos; /* current write posistion in buffer according to DS */
- volatile int dst_left; /* bytes left to write befor wrap round */
- volatile int silence_left; /* bytes of silence left to fill */
- int min_fill; /* debug */
- /* buffer */
- AudioFormat format; /* current buffer format */
- LPDIRECTSOUNDBUFFER dsbuf; /* Direct sound buffer interface */
- int buf_size; /* size of active area in bytes*/
- int frame_bytes; /* frame size in bytes */
-
- CB_TRANSFER *transfer; /* code to read sample data */
- TRANSFER transfer_data;
- volatile int next_frame_called;
- volatile int service_count;
- volatile int frames_played;
- volatile int original_frame;
- volatile int original_dst_pos;
- } AUD_DRV_CHAN;
- /*****************************************************************************
- ** Private Data **
- *****************************************************************************/
- static AUD_Thread *thread = NULL;
- static Lock drv_ref;
- #ifdef _DEBUG
- int mixer_skip = 0;
- #endif
- static AudioDriver _AUD_driver =
- {
- NULL, /* use for extended data */
- audioOpenChannel,
- audioCloseChannel,
- audioStart,
- audioStop,
- audioPause,
- audioResume,
- audioCheck,
- audioUpdate,
- audioQueueIt,
- audioLock,
- audioUnlock
- };
- static AudioSystemMaster _AUD_system_master =
- {
- "Direct Sound Driver V2.0",
- 0x0, /* reserved, do not change ! */
- mAUDIO_SYS_PROP_NONE,
- AUDIO_SYSTEM_MASTER_INIT_STATE, // do not change this !
- AUDIO_STAMP_SYSTEM_MASTER, // struct id, do not change this !
- audioLoad,
- audioUnload,
- audioOpen,
- audioClose,
- &_AUD_driver
- };
- /* direct sound */
- LPDIRECTSOUND AUD_sound_object = NULL;
- LPDIRECTSOUNDBUFFER AUD_primary_buffer = NULL;
- // Table was generated with the function 1000*LOG2(n/100) where n is the range 0..100
- // 0 = no volume, 100 = full volume, and the range is linear ( 50 is half volume).
- // LOG2() is log to the base 2
- static int AUD_log_table[101] ={ //1....2.....3......4....5......6.....7....8.....9......0
- -10000,-6644,-5644,-5059,-4644,-4322,-4059,-3837,-3644,-3474,
- -3322,-3184,-3059,-2943,-2837,-2737,-2644,-2556,-2474,-2396,
- -2322,-2252,-2184,-2120,-2059,-2000,-1943,-1889,-1837,-1786,
- -1737,-1690,-1644,-1599,-1556,-1515,-1474,-1434,-1396,-1358,
- -1322,-1286,-1252,-1218,-1184,-1152,-1120,-1089,-1059,-1029,
- -1000, -971, -943, -916, -889, -862, -837, -811, -786, -761,
- -737, -713, -690, -667, -644, -621, -599, -578, -556, -535,
- -515, -494, -474, -454, -434, -415, -396, -377, -358, -340,
- -322, -304, -286, -269, -252, -234, -218, -201, -184, -168,
- -152, -136, -120, -105, -89, -74, -59, -44, -29, -14,
- 0
- };
- /*****************************************************************************
- ** Public Data **
- *****************************************************************************/
- AudioSystemMaster *AudioSystemDSD = &_AUD_system_master;
- /*****************************************************************************
- ** Private Prototypes **
- *****************************************************************************/
- static void AUD_pcm_service ( AudioChannel *chan );
- static void AUD_init_buffer ( AUD_DRV_CHAN *ci );
- static int AUD_create_pcm_buffer ( AUD_DRV_CHAN *ci, AudioFormat *format );
- static void AUD_destroy_pcm_buffer ( AUD_DRV_CHAN *ci );
- static void AUD_set_buffer_src ( AUD_DRV_CHAN *ci );
- static void AUD_new_buffer_src ( AUD_DRV_CHAN *ci );
- static int AUD_fill_buffer ( AUD_DRV_CHAN *ci, int bytes );
- static void AUD_update_buffer ( AUD_DRV_CHAN *ci );
- static void AUD_reset_buffer ( AUD_DRV_CHAN *ci );
- static void AUD_channel_stop ( AudioChannel *chan );
- static uint AUD_get_current_frame ( AUD_DRV_CHAN *ci );
- static void AUD_set_wave_format ( WAVEFORMATEX *pcmwf, AudioFormat *format );
- static int AUD_same_format ( AudioFormat *format1, AudioFormat *format2 );
- static AUD_ThreadCB AUD_service_device;
- static int AUD_service_device ( AudioDevice *dev );
- static int AUD_restore_primary ( void );
- static int AUD_restore_buffer ( AUD_DRV_CHAN *ci );
- static CB_TRANSFER PCM_transfer;
- static CB_DECODE IMA_decode_block;
- static CB_DECODE MS_decode_block;
- //static int AUD_set_dev_format ( AudioDevice *dev, AudioFormat *format );
- /*****************************************************************************
- ** Private Functions **
- *****************************************************************************/
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static void transfer_init ( TRANSFER *trans )
- {
- memset ( trans, 0, sizeof (TRANSFER));
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static void transfer_deinit ( TRANSFER *trans )
- {
- if ( trans->in )
- {
- free ( trans->in );
- trans->in = NULL;
- trans->in_size = 0;
- }
- if ( trans->out )
- {
- free ( trans->out );
- trans->out = NULL;
- trans->out_size = 0;
- }
- if ( trans->mp3.asi )
- {
- ASI_stream_close ( (HASISTREAM) trans->mp3.asi );
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int NULL_transfer ( AUD_DRV_CHAN *, uint8 *, int *, uint8 *, int *)
- {
- return FALSE;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int PCM_transfer ( AUD_DRV_CHAN *, uint8 *dst, int *dst_bytes, uint8 *src, int *src_bytes )
- {
- int transfer;
- if ( (transfer = *dst_bytes ) > *src_bytes )
- {
- transfer = *src_bytes;
- }
- if ( transfer )
- {
- memcpy ( dst, src, transfer );
- *dst_bytes = transfer;
- *src_bytes = transfer;
- }
- return TRUE;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int ADPCM_transfer ( AUD_DRV_CHAN *ci, uint8 *dst, int *dst_bytes, uint8 *src, int *src_bytes )
- {
- int sbytes = 0;
- int dbytes = 0;
- int stransfered = 0;
- int dtransfered = 0;
- int bytes;
- int done = FALSE;
- TRANSFER *data = &ci->transfer_data;
- if ( !data->out || !data->in )
- {
- return FALSE;
- }
- if ( src_bytes )
- {
- sbytes = *src_bytes;
- }
- if ( dst_bytes )
- {
- dbytes = *dst_bytes;
- }
- while ( !done )
- {
- switch ( data->state )
- {
- case STATE_READ_BLOCK:
- {
- if ( !data->in_bytes_left || src == NULL)
- {
- // have read in the src
- data->state = data->next_state;
- data->in_bytes_left = 0;
- break;
- }
- // ok, read in as much as we can
- if ( (bytes = data->in_bytes_left ) > sbytes )
- {
- bytes = sbytes;
- }
- if ( bytes == 0 )
- {
- // no more data to read at this time
- done = TRUE;
- break;
- }
- memcpy ( &data->in[ data->in_bytes - data->in_bytes_left], src, bytes );
- src += bytes;
- stransfered+= bytes;
- sbytes -= bytes;
- data->in_bytes_left -= bytes;
- data->pending = TRUE;
- break;
- }
- case STATE_WRITE_BLOCK:
- {
- if ( !data->out_bytes_left )
- {
- // have written out to dst
- data->state = data->next_state;
- data->pending = FALSE;
- break;
- }
- // ok, write out as much as we can
- if ( (bytes = data->out_bytes_left ) > dbytes )
- {
- bytes = dbytes;
- }
- if ( bytes == 0 )
- {
- // no more data to write at this time
- done = TRUE;
- break;
- }
- memcpy ( dst, &data->out[ data->out_bytes - data->out_bytes_left], bytes );
- dst += bytes;
- dtransfered+= bytes;
- dbytes -= bytes;
- data->out_bytes_left -= bytes;
- break;
- }
- case STATE_DECODE_BLOCK:
- {
- if ( !data->decode ( ci ) )
- {
- return FALSE;
- }
- data->state = STATE_WRITE_BLOCK;
- data->out_bytes_left = data->out_bytes;
- data->next_state = STATE_INIT_BLOCK;
- break;
- }
- case STATE_INIT_BLOCK:
- {
- if ( src != NULL )
- {
- data->in_bytes = data->block_size;
- data->in_bytes_left = data->block_size;
- data->state = STATE_READ_BLOCK;
- data->next_state = STATE_DECODE_BLOCK;
- }
- else
- {
- done = TRUE;
- }
- break;
- }
- }
- }
- if ( src_bytes )
- {
- *src_bytes = stransfered;
- }
- if ( dst_bytes )
- {
- *dst_bytes = dtransfered;
- }
- return TRUE;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static S32 AILCALLBACK fetch_CB ( U32 user, void FAR *dest, S32 bytes, S32 offset)
- {
- TRANSFER *data = (TRANSFER *) user ;
- if ( bytes)
- {
- if ( bytes > data->in_bytes_left )
- {
- bytes = data->in_bytes_left;
- }
- memcpy ( dest, &data->in[data->mp3.in_pos], bytes);
- data->mp3.in_pos += bytes;
- data->in_bytes_left -= bytes;
- }
- return bytes;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int MP3_transfer ( AUD_DRV_CHAN *ci, uint8 *dst, int *dst_bytes, uint8 *src, int *src_bytes )
- {
- int sbytes = 0;
- int dbytes = 0;
- int stransfered = 0;
- int dtransfered = 0;
- int bytes;
- //int done = FALSE;
- TRANSFER *data = &ci->transfer_data;
- if ( !data->in )
- {
- return FALSE;
- }
- if ( src_bytes )
- {
- sbytes = *src_bytes;
- }
- if ( dst_bytes )
- {
- dbytes = *dst_bytes;
- *dst_bytes = 0;
- }
- // make sure existing in data is at the start of the buffer
- if ( data->in_bytes_left && data->mp3.in_pos > 0 )
- {
- //copy the data down to the start of the buffer
- memcpy ( data->in, &data->in[data->mp3.in_pos], data->in_bytes_left );
- }
- data->mp3.in_pos = 0;
- // make sure the in buffer is full
- if ( data->in_bytes_left < data->in_size_needed && src )
- {
- // ok, read in as much as we can
- if ( (bytes = data->in_size_needed - data->in_bytes_left ) > sbytes )
- {
- bytes = sbytes;
- }
- if ( bytes == 0 )
- {
- // no more data to read at this time
- return TRUE;
- }
- memcpy ( &data->in[ data->in_bytes_left], src, bytes );
- src += bytes;
- stransfered+= bytes;
- sbytes -= bytes;
- data->in_bytes_left += bytes;
- data->pending = TRUE;
- if ( data->in_bytes_left < data->in_size_needed )
- {
- return TRUE; // not enough data to continue
- }
- }
- if ( !data->mp3.asi )
- {
- // start MP3 streamer
- if ( ! ( data->mp3.asi = (ASISTREAM *) ASI_stream_open ( (U32) data, fetch_CB, 0 )))
- {
- // bad MP3 stream
- return FALSE;
- }
- }
- // decode more of the stream
- if ( dbytes > 16*1024)
- {
- dbytes = 16*1024;
- }
- dtransfered = ASI_stream_process ( (HASISTREAM) data->mp3.asi, dst, dbytes );
- data->pending = data->in_bytes_left || (data->mp3.asi->output_cursor < data->mp3.asi->frame_size);
- if ( src_bytes )
- {
- *src_bytes = stransfered;
- }
- if ( dst_bytes )
- {
- *dst_bytes = dtransfered;
- }
- return dtransfered>0;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int AUD_service_device ( AUD_Thread *thread, void *data )
- {
- AudioChannel *chan;
- AudioSearch sh;
- AudioDevice *dev = (AudioDevice*) data;
- if ( !dev )
- {
- return TRUE;
- }
- #ifdef _DEBUG
- if ( mixer_skip )
- {
- mixer_skip--;
- if ( mixer_skip < 0 )
- {
- mixer_skip = 0;
- }
- return TRUE;
- }
- #endif
- if ( NotLocked ( &dev->channelAccess) )
- {
- TimeStamp now = AudioGetTime () ;
- AudioServicePerform ( &dev->mixerUpdate, now );
- chan = AudioDeviceFirstChannel ( dev, &sh );
- while ( chan )
- {
- if ( chan->Control.Status & mAUDIO_CTRL_PLAYING )
- {
- if ( audioCheck ( chan ))
- {
- chan->drvData->poll_interval = now - chan->drvData->last_poll;
- chan->drvData->last_poll = now;
- AUD_update_buffer ( chan->drvData );
- }
- else
- {
- AUD_channel_stop ( chan );
- }
- }
- chan = AudioDeviceNextChannel ( &sh );
- }
- AudioDeviceService ( dev );
- return TRUE;
- }
- return FALSE;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int AUD_same_format ( AudioFormat *f1, AudioFormat *f2 )
- {
- return ( f1->Channels == f2->Channels
- && f1->Rate == f2->Rate
- && f1->SampleWidth == f2->SampleWidth );
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- void AUD_set_wave_format ( WAVEFORMATEX *pcmwf, AudioFormat *format )
- {
- memset ( pcmwf, 0, sizeof(WAVEFORMATEX) );
- pcmwf->wFormatTag = WAVE_FORMAT_PCM;
- pcmwf->nChannels = (unsigned short ) format->Channels;
- pcmwf->nSamplesPerSec = format->Rate;
- pcmwf->nBlockAlign = (unsigned short ) format->Channels*format->SampleWidth;
- pcmwf->nAvgBytesPerSec = pcmwf->nSamplesPerSec * pcmwf->nBlockAlign;
- pcmwf->wBitsPerSample = (unsigned short ) format->SampleWidth<<3;
- pcmwf->cbSize = 0;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int AUD_create_pcm_buffer ( AUD_DRV_CHAN *ci, AudioFormat *format )
- {
- DSBUFFERDESC desc;
- WAVEFORMATEX pcmwf;
- DBG_Function ("DSND2:AUD_create_pcm_buffer");
- AudioChannelSetFormat ( ci->chan, format );
- if ( ci->dsbuf )
- {
- if ( AUD_same_format ( &ci->format, format ) )
- {
- ci->chan->drv_format_changed = FALSE;
- /* we already have a buffer of the required format */
- return NO_ERROR;
- }
- ci->chan->drv_format_changed = TRUE;
- }
- /* we need to recreate the buffer */
- AUD_destroy_pcm_buffer ( ci );
- // Set up wave format structure.
- AUD_set_wave_format ( &pcmwf, format );
- ci->format = *format;
- // Set up DSBUFFERDESC structure.
- memset ( &desc, 0, sizeof(DSBUFFERDESC) );
- desc.dwSize = sizeof(DSBUFFERDESC);
- desc.dwFlags = (DSBCAPS_CTRLVOLUME |DSBCAPS_CTRLPAN|DSBCAPS_CTRLFREQUENCY) ; // Need default controls vol, pan, pitch
- /* now we work out the size that the buffer needs to be. This is based on the polling interval and
- the number of frames.
- A frame size is the that size that when played back will take X polling intervals ( over sampling). This ensures that
- the polling code will not miss any frames. A frame is also the minimum update size.
- frame size = ((bytes per second) * (poll interval per second) * over sample
- */
- ci->frame_bytes = ((pcmwf.nAvgBytesPerSec * (vAUD_DRV_POLL_INTERVAL/10) )/(TIMER_HZ/10)) * vAUD_DRV_OVER_SAMPLE;
- ci->frame_bytes = ((ci->frame_bytes+1024-1)/1024) * 1024;
- // DBGPRINTF (("Sound frame size = %d bytes\n", ci->frame_bytes ));
- desc.dwBufferBytes = vAUD_DRV_FRAMES * ci->frame_bytes;
- desc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf;
- // Create buffer.
- if ( AUD_sound_object->CreateSoundBuffer ( &desc, &ci->dsbuf, NULL) != DS_OK)
- {
- ci->dsbuf = NULL ;
- return ERROR_CODE_FAIL;
- }
- #ifdef _DEBUG
- DSBCAPS caps = {0};
- caps.dwSize = sizeof(caps);
- if ( ci->dsbuf->GetCaps ( &caps ) != DS_OK )
- {
- msg_assert ( FALSE, ("Error trying to get caps of secondary buffer"));
- }
- msg_assert ( caps.dwBufferBytes == desc.dwBufferBytes , ("Error: Asked for buffer of %d bytes, but got %d bytes", desc.dwBufferBytes, caps.dwBufferBytes ));
- #endif
- ci->buf_size = desc.dwBufferBytes;
- // DBGPRINTF (("Sound buffer size = %d bytes\n", ci->buf_size ));
- return vNO_ERROR;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static void AUD_destroy_pcm_buffer ( AUD_DRV_CHAN *ci )
- {
- if ( ci->dsbuf )
- {
- ci->dsbuf->Release ();
- ci->dsbuf = NULL;
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int AUD_restore_primary ( void )
- {
- if ( AUD_primary_buffer->Restore ( ) == DS_OK )
- {
- return TRUE;
- }
- return FALSE;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int AUD_restore_buffer ( AUD_DRV_CHAN *ci )
- {
- if ( ci->dsbuf->Restore () == DS_OK )
- {
- AUD_init_buffer ( ci );
- return TRUE;
- }
- return FALSE;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static uint AUD_get_current_frame ( AUD_DRV_CHAN *ci )
- {
- ulong pos;
- ci->dsbuf->GetCurrentPosition ( &pos, (ulong*) &ci->write_pos );
- return pos / ci->frame_bytes;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static void AUD_init_buffer ( AUD_DRV_CHAN *ci )
- {
- ci->src_left = 0;
- ci->pcm_pos = 0;
- ci->silence_left = ci->frame_bytes*4;
- ci->dsbuf->SetCurrentPosition ( 0 );
- ci->frame = AUD_get_current_frame ( ci );
- ci->last_poll = AudioGetTime ( );
- ci->min_fill = ci->buf_size;
- ci->dsbuf->GetCurrentPosition ( (ulong*) &ci->dst_pos, (ulong*) &ci->write_pos );
- ci->dst_left = ci->buf_size - ci->dst_pos;
- ci->service_count = 0;
- ci->original_frame = ci->frame;
- ci->frames_played = 0;
- ci->original_dst_pos = ci->dst_pos;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static void AUD_reset_buffer ( AUD_DRV_CHAN *ci )
- {
- ci->dst_pos = 0;
- ci->dst_left = ci->buf_size;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static void AUD_set_buffer_src ( AUD_DRV_CHAN *ci )
- {
- ci->next_frame_called = FALSE;
- ci->src_pos = (uint8 *) ci->chan->frameData;
- ci->src_start = (uint8 *) ci->chan->frameData;
- ci->src_left = ci->src_size = ci->chan->bytesInFrame;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static void AUD_new_buffer_src ( AUD_DRV_CHAN *ci )
- {
- AudioSample *sample = ci->chan->sample;
- AudioFormat *format;
- TRANSFER *data = &ci->transfer_data;
- if ( !sample )
- {
- return;
- }
- if ( !( format = ci->chan->sample->Format ) )
- {
- format = &ci->chan->Device->DefaultFormat;
- }
- #ifdef _DEBUG
- msg_assert ( AUD_same_format ( &ci->format, format ), ("Sample \"%s\" has incompatible format with the previous sample.\nCannot seamlessly merge samples of differing playback parameters!!", ci->chan->sample_name));
- #endif //_DEBUG
- data->out_bytes_left = 0;
- data->in_bytes_left = 0;
- data->in_bytes = 0;
- data->state = STATE_INIT_BLOCK;
- data->in_size_needed = 0;
- data->out_size_needed = 0;
- data->channels = format->Channels;
- data->pending = FALSE;
- if ( data->mp3.asi )
- {
- ASI_stream_close ( (HASISTREAM) data->mp3.asi );
- }
- data->mp3.asi = NULL;
- switch ( format->Compression )
- {
- case AUDIO_COMPRESS_NONE :
- ci->transfer = PCM_transfer;
- break;
- case AUDIO_COMPRESS_IMA_ADPCM:
- ci->transfer = ADPCM_transfer;
- data->decode = IMA_decode_block;
- data->block_size = format->cdata.adpcm.BlockSize;
- data->in_size_needed = data->block_size;
- data->out_size_needed = (data->block_size+32)*4;
- break;
- case AUDIO_COMPRESS_MS_ADPCM:
- ci->transfer = ADPCM_transfer;
- data->decode = MS_decode_block;
- data->block_size = format->cdata.adpcm.BlockSize;
- data->in_size_needed = data->block_size;
- data->out_size_needed = (data->block_size+32)*4;
- break;
- case AUDIO_COMPRESS_MP3:
- ci->transfer = MP3_transfer;
- data->in_size_needed = STREAM_BUFSIZE + 1024;
- data->mp3.in_pos = 0;
- data->in_bytes = data->in_size_needed;
- break;
- #ifdef _DEBUG
- default:
- ci->transfer = NULL_transfer;
- msg_assert ( FALSE , ("Unknown compression format"));
- break;
- #endif
- }
- if ( data->in_size < data->in_size_needed )
- {
- if ( data->in )
- {
- free ( data->in );
- }
- data->in = (uint8*) malloc ( data->in_size_needed );
- msg_assert ( data->in, ("Failed to create new in buffer"));
- if ( !data->in )
- {
- data->in_size = 0;
- }
- else
- {
- data->in_size = data->in_size_needed;
- }
- }
- if ( data->out_size < data->out_size_needed )
- {
- if ( data->out )
- {
- free ( data->out );
- }
- data->out = (uint8*) malloc ( data->out_size_needed );
- msg_assert ( data->out, ("Failed to create new out buffer"));
- if ( !data->out )
- {
- data->out_size = 0;
- }
- else
- {
- data->out_size = data->out_size_needed;
- }
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int AUD_lock_buffer ( AUD_DRV_CHAN *ci, ulong pos, ulong transfer, uint8 **dst, ulong *bytes1, uint8 **dst2, ulong *bytes2 )
- {
- int retval;
- int retry_count = 3;
- retry:
- if ( (retval = ci->dsbuf->Lock ( pos, transfer, (void **) dst, bytes1, (void **)dst2, bytes2, 0)) != DS_OK )
- {
- if ( retval = DSERR_BUFFERLOST )
- {
- if ( !AUD_restore_buffer ( ci ) )
- {
- DBGPRINTF (("Failed to restore buffer\n"));
- return FALSE;
- }
- DBGPRINTF (("Restored buffer\n"));
- if ( retry_count-- )
- {
- goto retry;
- }
- }
- DBGPRINTF (("Failed to lock buffer\n"));
- return FALSE;
- }
- return TRUE;
- }
- static int AUD_fill_buffer ( AUD_DRV_CHAN *ci, int total_bytes )
- {
- ulong transfer, bytes_transfer;
- ulong bytes;
- uint8 *lpos1 = NULL,*lpos2=NULL;
- ulong lbytes1 = 0,lbytes2 = 0;
- uint8 *dst;
- int locked =FALSE;
- int result = FALSE;
- DBG_Function ("DSND2:AUD_fill_buffer");
- while ( total_bytes > 0 )
- {
- /* check for buffer wrap roun */
- if ( ci->dst_left <= 0)
- {
- AUD_reset_buffer ( ci );
- }
- bytes_transfer = 0;
- /* check for buffer overflow and adjust transfer accordingly */
- if ( (bytes = (ulong) total_bytes) > (ulong ) ci->dst_left )
- {
- bytes = ci->dst_left;
- }
- if ( locked )
- {
- ci->dsbuf->Unlock ( lpos1, lbytes1, lpos2, lbytes2 );
- locked = FALSE;
- }
- if ( !AUD_lock_buffer ( ci, ci->dst_pos, bytes, &lpos1, &lbytes1, &lpos2, &lbytes2) )
- {
- goto done;
- }
- locked = TRUE;
- if ( (lpos2 != NULL) || (lbytes1 != bytes) || (lbytes2 != 0))
- {
- DBGPRINTF (("Buffer management out by %d bytes\n", lbytes2));
- goto done;
- }
- dst = lpos1;
- while ( bytes )
- {
- transfer = bytes;
- /* is there any source data left */
- if ( ci->src_left == 0 )
- {
- /* call up to higher level to see if more source is going to be supplied */
- ci->src_left = -1; /* unless the call back adds new source we assume no more data */
- if ( !ci->next_frame_called )
- {
- ci->chan->drvCBNextFrame ( ci->chan );
- ci->next_frame_called = TRUE;
- }
- if ( !ci->chan->bytesInFrame )
- {
- // no more data for this sample
- if ( !ci->transfer_data.pending)
- {
- ci->chan->drvCBNextSample ( ci->chan );
- if ( ci->chan->bytesInFrame )
- {
- // we have a new sample
- AUD_new_buffer_src ( ci );
- }
- }
- }
- if ( ci->chan->bytesInFrame )
- {
- AUD_set_buffer_src ( ci );
- }
- if ( ci->src_left == 0 )
- {
- ci->src_left = -1;
- }
- }
- if ( ci->src_left <= 0 && !ci->transfer_data.pending )
- {
- if ( ci->chan->current_format.SampleWidth == 2)
- {
- memset ( dst, 0x0000, transfer );
- }
- else
- {
- memset ( dst, 0x80, transfer );
- }
- ci->silence_left -= transfer ;
- }
- else
- {
- int src_bytes;
- if ( (src_bytes = ci->src_left) <= 0 )
- {
- // flush buffered transfer
- if ( !ci->transfer ( ci, dst, (int*) &transfer, NULL, NULL ) )
- {
- goto done;
- }
- src_bytes = 0;
- ci->src_left = 0; // try to read more source
- }
- else
- {
- if ( !ci->transfer ( ci, dst, (int*) &transfer, (uint8 *)ci->src_pos, &src_bytes ) )
- {
- goto done;
- }
- }
- ci->src_pos+= src_bytes;
- ci->src_left -= src_bytes;
- ci->pcm_pos += transfer;
- }
- dst += transfer;
- ci->dst_pos += transfer;
- ci->dst_left -= transfer;
- bytes -= transfer;
- bytes_transfer += transfer;
- }
- total_bytes -= bytes_transfer;
- }
- result = TRUE;
- done:
- if ( locked )
- {
- ci->dsbuf->Unlock ( lpos1, lbytes1, lpos2, lbytes2 );
- locked = FALSE;
- }
- return result;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static void AUD_update_buffer ( AUD_DRV_CHAN *ci )
- {
- uint frame;
- int dif;
- int filled;
- frame = AUD_get_current_frame ( ci );
- if ( ( dif = (frame - ci->frame )))
- {
- /* pcm address has moved on */
- if ( dif < 0 )
- {
- /* pcm has wraped round to start of buffer */
- dif = frame + (vAUD_DRV_FRAMES - ci->frame);
- }
- if ( (dif -= vAUD_DRV_LAG_FRAMES ) > 0 )
- {
- if ( (ci->frame += dif) >= vAUD_DRV_FRAMES)
- {
- ci->frame %= vAUD_DRV_FRAMES;
- }
- ci->frames_played += dif;
- dif = dif * ci->frame_bytes;
- filled = AUD_fill_buffer ( ci, dif );
- if ( ci->min_fill > dif )
- {
- ci->min_fill = dif;
- }
- if ( (ci->pcm_pos -= dif) <=0 || !filled )
- {
- ci->dsbuf->Stop();
- }
- }
- }
- ci->service_count++;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static void AUD_channel_stop ( AudioChannel *chan )
- {
- AUD_DRV_CHAN *ci;
- ci = (AUD_DRV_CHAN *) chan->drvData;
- /* put stop call here */
- if ( ci->dsbuf )
- {
- ci->dsbuf->Stop();
- }
- if ( chan->drvCBSampleDone )
- {
- chan->drvCBSampleDone ( chan );
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int audioLoad ( AudioSystem *system )
- {
- int result;
- ASI_startup();
- result = DirectSoundCreate(NULL, &AUD_sound_object, NULL);
- if (result != DS_OK)
- {
- //Print_Sound_Error(Fetch_String(TXT_DSOUND_NO_COOP) );
- return ERROR_CODE_FAIL;
- }
- assert ( AUD_sound_object );
- result = AUD_sound_object->SetCooperativeLevel( AudioGetWindowsHandle () , DSSCL_PRIORITY);
- system->numUnits = 1; /* tell WCORE that there is only 1 audio unit */
- if ( !thread )
- {
- LockInit ( &drv_ref );
- if (!(thread = AUD_ThreadCreate ( "Audio Service Thread", AUD_THREAD_PRI_REALTIME, AUD_service_device )) )
- {
- return ERROR_CODE_FAIL;
- }
- LockAcquire ( &drv_ref );
- AUD_ThreadSetInterval ( thread, vAUD_DRV_POLL_INTERVAL );
- }
- else
- {
- LockAcquire ( &drv_ref );
- }
- return vNO_ERROR;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static void audioUnload ( AudioSystem * )
- {
- /* put in code to uninitialize audio system */
- if ( AUD_sound_object )
- {
- AUD_sound_object->Release();
- AUD_sound_object = NULL ;
- }
- if ( thread )
- {
- LockRelease ( &drv_ref );
- if ( NotLocked ( &drv_ref ))
- {
- AUD_ThreadDestroy ( thread );
- thread = NULL;
- }
- }
- ASI_shutdown ();
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int audioOpen ( AudioDevice *dev )
- {
- /* put in code to instance a device */
- dev->maxChannels = vAUD_DRV_MAX_CHANNELS;
- AudioServiceSetInterval ( &dev->mixerUpdate, vAUD_DRV_POLL_INTERVAL );
- AudioServiceSetMustServiceInterval ( &dev->mixerUpdate, vAUD_DRV_POLL_INTERVAL * vAUD_DRV_OVER_SAMPLE * vAUD_DRV_FRAMES );
- AudioServiceSetResetInterval ( &dev->mixerUpdate, vAUD_DRV_POLL_INTERVAL * vAUD_DRV_OVER_SAMPLE * vAUD_DRV_FRAMES * 3 );
- AUD_ThreadSetData ( thread, dev);
- /* start the primary buffer playing */
- {
- DSBUFFERDESC dsbdesc;
- WAVEFORMATEX pcmwf;
- AUD_set_wave_format ( &pcmwf, &dev->DefaultFormat );
- memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); // Zero it out.
- dsbdesc.dwSize = sizeof(DSBUFFERDESC);
- dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
- dsbdesc.dwBufferBytes = 0;
- if ( AUD_sound_object->CreateSoundBuffer ( &dsbdesc, &AUD_primary_buffer, NULL) != DS_OK )
- {
- AUD_primary_buffer = NULL;
- return ERROR_CODE_FAIL;
- }
- if ( AUD_primary_buffer->SetFormat ( &pcmwf ) != DS_OK )
- {
- DBGPRINTF (("Unable to set the desired primary format\n"));
- }
- DSCAPS caps = {0};
- caps.dwSize = sizeof( caps );
- AUD_sound_object->GetCaps ( &caps );
- if (caps.dwFlags & DSCAPS_EMULDRIVER)
- {
- //msg_assert ( FALSE, ("Audio Emulation"));
- }
- AUD_primary_buffer->Play ( 0, 0, DSBPLAY_LOOPING );
- }
- dev->frames = vAUD_DRV_FRAMES;
- dev->over_sample = vAUD_DRV_OVER_SAMPLE;
- dev->frame_lag = vAUD_DRV_LAG_FRAMES;
- return vNO_ERROR;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static void audioClose ( AudioDevice * )
- {
- /* put in code to close up a device */
- AUD_ThreadSetData ( thread, NULL );
- if ( AUD_primary_buffer )
- {
- AUD_primary_buffer->Stop ();
- AUD_primary_buffer->Release ();
- AUD_primary_buffer = NULL;
- }
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int audioOpenChannel ( AudioChannel *chan )
- {
- AUD_DRV_CHAN *ci;
- DBG_Function ("DSND2:audioOpenChannel");
- /* put in code to instance a channel */
- MEM_ALLOC_STRUCT ( ci, AUD_DRV_CHAN, vMEM_ANY|mMEM_INTERNAL );
- chan->drvData = ci;
- ci->chan = chan;
- chan->time_min_frame = vAUD_DRV_POLL_INTERVAL * vAUD_DRV_OVER_SAMPLE;
- chan->time_buffer = vAUD_DRV_FRAMES * chan->time_min_frame;
- transfer_init ( &ci->transfer_data );
- AudioChannelSetFormat ( ci->chan, &ci->chan->Device->DefaultFormat ); /* initially create sound buffer with default format */
- return vNO_ERROR;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int audioCloseChannel ( AudioChannel *chan )
- {
- AUD_DRV_CHAN *ci;
- DBG_Function ("DSND2:audioCloseChannel");
- /* put in code to close a channel*/
- if ( (ci = chan->drvData) )
- {
- transfer_deinit ( &ci->transfer_data );
- AUD_destroy_pcm_buffer ( ci );
- MEM_Free ( ci );
- chan->drvData = NULL;
- }
- return vNO_ERROR;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int audioStart ( AudioChannel *chan )
- {
- AUD_DRV_CHAN *ci;
- AudioFormat *format;
- AudioSample *sample;
- DBG_Function ("DSND2:audioStart");
- DBG_ASSERT ( !audioCheck ( chan ));
- ci = chan->drvData;
- sample = chan->sample;
- if ( !( format = sample->Format ) )
- {
- format = &chan->Device->DefaultFormat;
- }
- /* recreate buffer if format changed */
- if ( AUD_create_pcm_buffer ( ci, format ) != vNO_ERROR)
- {
- DBGPRINTF (("Failed to create playback buffer\n"));
- return ERROR_CODE_FAIL;
- }
- AUD_init_buffer ( ci ); /* initialise buffer for play back */
- AUD_new_buffer_src ( ci );
- AUD_set_buffer_src ( ci ); /* attach source to buffer */
- if ( !AUD_fill_buffer ( ci, ci->buf_size )) /* pre-fill buffer to max */
- {
- DBGPRINTF (( "Failed to prefill buffer\n"));
- return ERROR_CODE_FAIL;
- }
- /* update buffer attributes */
- audioUpdate ( chan );
- /* start playing */
- if ( ci->dsbuf->Play ( 0, 0, DSBPLAY_LOOPING ) != DS_OK) /* must do looping or things will go horribly wrong */
- {
- DBGPRINTF (("Failed to start playback\n"));
- return ERROR_CODE_FAIL;
- }
- DBG_ASSERT ( audioCheck ( chan ));
- return vNO_ERROR;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int audioStop ( AudioChannel *chan )
- {
- if ( chan->Control.Status & (mAUDIO_CTRL_ACTIVE) )
- {
- AUD_channel_stop ( chan );
- }
- return vNO_ERROR;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int audioPause ( AudioChannel *chan )
- {
- AUD_DRV_CHAN *ci = chan->drvData;
- if ( ci->dsbuf )
- {
- ci->dsbuf->Stop ();
- }
- return vNO_ERROR;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int audioResume ( AudioChannel *chan )
- {
- AUD_DRV_CHAN *ci = chan->drvData;
- if ( ci->dsbuf )
- {
- if ( ci->dsbuf->Play ( 0, 0, DSBPLAY_LOOPING ) == DS_OK) /* must do looping or things will go horribly wrong */
- {
- return vNO_ERROR;
- }
- }
- return ERROR_CODE_FAIL;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int audioCheck ( AudioChannel *chan )
- {
- AUD_DRV_CHAN *ci = chan->drvData;
- DWORD status;
- if ( ci->dsbuf && (ci->dsbuf->GetStatus ( &status ) == DS_OK) )
- {
- if ( status & (DSBSTATUS_PLAYING|DSBSTATUS_LOOPING) == (DSBSTATUS_PLAYING|DSBSTATUS_LOOPING) )
- {
- return TRUE;
- }
- else
- {
- return FALSE;
- }
- }
- return FALSE;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int audioUpdate ( AudioChannel *chan )
- {
- AUD_DRV_CHAN *ci;
- int vol;
- int pitch;
- HRESULT stat;
- ci = chan->drvData;
- vol = AudioLevelApply ( &chan->attribs.VolumeLevel, 100 );
- ci->dsbuf->SetVolume ( AUD_log_table[vol]);
- #if 1
- {
- int pos;
- pos = AudioLevelApply ( &chan->attribs.PanPosition, 200 ) - 100;
- if ( pos < 0 )
- {
- stat = ci->dsbuf->SetPan ( AUD_log_table[100+pos]);
- }
- else
- {
- stat = ci->dsbuf->SetPan ( -AUD_log_table[100-pos]);
- }
- }
- #endif
- pitch = AudioAttribsCalcPitch ( &chan->attribs, ci->chan->current_format.Rate );
- ci->dsbuf->SetFrequency ( pitch);
- return vNO_ERROR;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int audioQueueIt ( AudioChannel *)
- {
- return ERROR_CODE_FAIL;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int audioLock ( AudioChannel *)
- {
- AUD_ThreadBeginCriticalSection ( thread );
- return vNO_ERROR;
- }
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- static int audioUnlock ( AudioChannel *)
- {
- AUD_ThreadEndCriticalSection ( thread );
- return vNO_ERROR;
- }
- /* command functions */
- #if 0
- static int AUD_set_dev_format ( AudioDevice *, AudioFormat *format )
- {
- WAVEFORMATEX wf;
- int err = ERROR_CODE_FAIL;
- if ( AUD_primary_buffer )
- {
- // Set up wave format structure.
- AUD_primary_buffer->Stop ();
- AUD_set_wave_format ( &wf, format );
- if ( AUD_primary_buffer->SetFormat ( &wf ) == DS_OK )
- {
- err = vNO_ERROR;
- }
- AUD_primary_buffer->Play ( 0, 0, DSBPLAY_LOOPING );
- }
- return err;
- }
- #endif
- /*****************************************************************************
- ** Public Functions **
- *****************************************************************************/
- /* :NOTICE:
- There are no public functions in a driver. If you have any then you are doing
- something wrong. -Tr
- */
- void *GetDirectSoundObject ( void )
- {
- return (void *) AUD_sound_object;
- }
- void *GetPrimaryBuffer ( void )
- {
- return (void *) AUD_primary_buffer ;
- }
- void AudioLoseFocus ( void )
- {
- if ( AUD_primary_buffer )
- {
- AUD_primary_buffer->Stop ();
- }
- }
- void AudioRegainFocus ( void )
- {
- if ( AUD_primary_buffer )
- {
- DWORD status;
- AUD_primary_buffer->GetStatus ( &status );
- if ( (status & DSBSTATUS_BUFFERLOST) )
- {
- AUD_restore_primary ( );
- }
- if ( !(status & DSBSTATUS_PLAYING) )
- {
- AUD_primary_buffer->Play ( 0, 0, DSBPLAY_LOOPING );
- }
- }
- }
- /* debug function. Not part of API */
- #ifdef _DEBUG
- void AudioCauseMixerDelay ( void )
- {
- mixer_skip = (vAUD_DRV_OVER_SAMPLE * vAUD_DRV_FRAMES -1) * 2;
- }
- #include <stdio.h>
- void AudioDeviceDumpDXSNDDriver ( AudioDevice *dev, void (*print) ( const char *) )
- {
- char string[200];
- AudioChannel *chan;
- AudioSearch sh;
- DBG_Function ("AudioDeviceDumpChannels");
- DBG_ASSERT_TYPE ( dev, AudioDevice );
- LockAcquire ( &dev->channelAccess);
- sprintf ( string, " \nDXSND Channels\n");
- print ( string );
- chan = AudioDeviceFirstChannel ( dev, &sh );
- while (chan)
- {
- sprintf ( string, "Channel 0x%0x, F=%6d, P=%d, I=%04d, T=%6d, B=%6d\n",
- chan,
- chan->drvData->frame_bytes,
- chan->drvData->frame,
- chan->drvData->poll_interval,
- chan->drvData->min_fill,
- chan->drvData->buf_size
- );
- print ( string );
- chan = AudioDeviceNextChannel( &sh );
- }
- LockRelease ( &dev->channelAccess);
- }
- #endif
- // IMA ADPCM Support
- /*
- *
- * Lookup tables for IMA ADPCM format
- *
- */
- static int imaIndexAdjustTable[16] = {
- -1, -1, -1, -1, /* +0 - +3, decrease the step size */
- 2, 4, 6, 8, /* +4 - +7, increase the step size */
- -1, -1, -1, -1, /* -0 - -3, decrease the step size */
- 2, 4, 6, 8, /* -4 - -7, increase the step size */
- };
- static int imaStepSizeTable[89] = {
- 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34,
- 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143,
- 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494,
- 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552,
- 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026,
- 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442,
- 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623,
- 27086, 29794, 32767
- };
- /******************************************************************/
- /* */
- /* */
- /******************************************************************/
- /****************************************************************************/
- /* IMA ADPCM Support Functions Section */
- /****************************************************************************/
- /*
- *
- * MsAdpcmDecode - Decode a given sample and update state tables
- *
- */
- static short ImaAdpcmDecode( uint8 deltaCode, IMA_DATA *state )
- {
- /* Get the current step size */
- int step;
- int difference;
- step = imaStepSizeTable[state->index];
- /* Construct the difference by scaling the current step size */
- /* This is approximately: difference = (deltaCode+.5)*step/4 */
- difference = step>>3;
- if ( deltaCode & 1 ) difference += step>>2;
- if ( deltaCode & 2 ) difference += step>>1;
- if ( deltaCode & 4 ) difference += step;
- if ( deltaCode & 8 ) difference = -difference;
- /* Build the new sample */
- state->previousValue += difference;
- if (state->previousValue > 32767) state->previousValue = 32767;
- else if (state->previousValue < -32768) state->previousValue = -32768;
- /* Update the step for the next sample */
- state->index += imaIndexAdjustTable[deltaCode];
- if (state->index < 0) state->index = 0;
- else if (state->index > 88) state->index = 88;
- return (short) state->previousValue;
- }
- static int IMA_decode_block ( AUD_DRV_CHAN *ci )
- {
- int i,j;
- TRANSFER *data = &ci->transfer_data;
- int bytes = data->in_bytes - data->in_bytes_left;
- uint8 *in = data->in;
- // set up output
- data->out_bytes = 0;
- ushort *out = (ushort *) data->out;
- if ( bytes < data->channels*4 )
- {
- return FALSE;
- }
- for ( i=0; i < data->channels; i++)
- {
- data->ima[i].previousValue = (int) (in[1] <<8) + (int) in[0];
- if (data->ima[i].previousValue & 0x8000)
- data->ima[i].previousValue -= 0x10000;
- if ((data->ima[i].index = in[2]) > 88)
- {
- msg_assert(FALSE, ("IMA ADPCM Format Error (bad index value) in wav file %s",ci->chan->sample_name));
- return FALSE;
- }
- if (in[3])
- {
- msg_assert (FALSE, ("IMA ADPCM Format Error (synchronization error) in wav file %s ", ci->chan->sample_name));
- return FALSE;
- }
- in+=4;
- bytes -=4;
- *out++ = (unsigned short ) data->ima[i].previousValue;
- data->out_bytes += 2;
- }
- if ( data->channels == 1 )
- {
- // 99.99% of the samples being played are mono
- while ( bytes > 0 )
- {
- ushort *out = (ushort *) &data->out[data->out_bytes];
- j = 4;
- while ( j-- )
- {
- uint8 b = *in++;
- *out++ = (ushort ) ImaAdpcmDecode(b & 0x0f,&data->ima[0]);
- *out++ = (ushort ) ImaAdpcmDecode((b>>4) & 0x0f,&data->ima[0]);
- }
- data->out_bytes += 16;
- bytes -= 4;
- }
- }
- else
- {
- while ( bytes > 0 )
- {
- for ( i = 0; i < data->channels ; i++)
- {
- short *out = (short *) &data->out[data->out_bytes+(i<<1)];
- for (j=0;j<4;j++)
- {
- uint8 b = *in++;
- *out = ImaAdpcmDecode(b & 0x0f,&data->ima[i]);
- out += data->channels;
- *out = ImaAdpcmDecode((b>>4) & 0x0f,&data->ima[i]);
- out += data->channels;
- }
- }
- data->out_bytes += data->channels<<4;
- bytes -= data->channels<<2;
- }
- }
- if ( bytes != 0 )
- {
- msg_assert ( FALSE, ("bad block"));
- return FALSE;
- }
- return TRUE;
- }
- /****************************************************************************/
- /* Microsoft ADPCM Support Functions Section */
- /****************************************************************************/
- static const int adaptionTable[] = {
- 230, 230, 230, 230, 307, 409, 512, 614,
- 768, 614, 512, 409, 307, 230, 230, 230
- };
- static short MSAdpcmDecode( unsigned char nibble, MS_DATA *ms, int sample1, int sample2)
- {
- int newsample;
- int predsample;
- predsample = ((sample1 * ms->iCoef[0]) + ( sample2 * ms->iCoef[1]))>>8;
- newsample = predsample + (ms->idelta * (nibble - ((nibble&0x08) << 1)));
- ms->idelta = (ms->idelta * adaptionTable[nibble])>>8;
- if ( ms->idelta < 16 )
- {
- ms->idelta = 16;
- }
- if (newsample > 0x7fff)
- {
- newsample = 0x7fff;
- }
- else if (newsample < -0x8000)
- {
- newsample = -0x8000;
- }
- return (short) newsample;
- }
- static int MS_decode_block ( AUD_DRV_CHAN *ci )
- {
- int i;
- TRANSFER *data = &ci->transfer_data;
- int bytes = data->in_bytes - data->in_bytes_left;
- uint8 *in = data->in;
- unsigned char bpredictor;
- int hsize = data->channels*(1+2+2+2);
- int channels = data->channels;
- int hi,lo;
-
- // set up output
- data->out_bytes = 0;
- short *out = (short *) data->out;
- if ( (bytes -= hsize) < 0 )
- {
- return FALSE;
- }
- for ( i=0; i < channels; i++)
- {
- bpredictor = *in++;
- if (bpredictor >= 7) {
- msg_assert(FALSE, ("MS-ADPCM bpredictor out of range"));
- return FALSE;
- }
- data->ms[i].iCoef[0] = MSADPCM_StdCoef[bpredictor][0];
- data->ms[i].iCoef[1] = MSADPCM_StdCoef[bpredictor][1];
- }
- for ( i=0; i < channels; i++)
- {
- lo = *in++;
- hi = *in++;
- data->ms[i].idelta = (hi<<8) | lo;
- }
- for ( i=0; i < channels; i++)
- {
- lo = *in++;
- hi = *in++;
- out[channels+i] = (hi<<8) | lo;
- }
- for ( i=0; i < channels; i++)
- {
- lo = *in++;
- hi = *in++;
- out[i] = (hi<<8) | lo;
- }
- /* already have 1st 2 samples from block-header */
- out += 2*data->channels;
- data->out_bytes += 4*data->channels;
- if ( channels == 1 )
- {
- unsigned char byte;
- while ( bytes )
- {
- byte = *in++;
- *out++ = MSAdpcmDecode(byte >> 4, &data->ms[0], out[-1], out[-2]);
- *out++ = MSAdpcmDecode(byte&0x0f, &data->ms[0], out[-1], out[-2]);
- bytes--;
- data->out_bytes += 4;
- }
- }
- else
- {
- int chan = 0;
- unsigned char byte;
- int channels2 = 2*channels;
- int out_bytes = 4*channels;
- while ( bytes )
- {
- byte = *in++;
- *out++ = MSAdpcmDecode(byte >> 4, &data->ms[chan], out[-channels], out[-channels2]);
- if (++chan == channels )
- {
- chan = 0;
- }
- *out++ = MSAdpcmDecode(byte&0x0f, &data->ms[chan], out[-channels], out[-channels2]);
- if (++chan == channels)
- {
- chan = 0;
- }
- bytes--;
- data->out_bytes += out_bytes;;
- }
- }
- return TRUE;
- }
- // Stubs
- DXDEC void FAR * AILCALL AIL_mem_alloc_lock(U32 size)
- {
- return AudioMemAlloc ( size );
- }
- DXDEC void AILCALL AIL_mem_free_lock (void FAR *ptr)
- {
- AudioMemFree ( ptr );
- }
- DXDEC U32 AILCALL AIL_MMX_available (void)
- {
- return 0;
- }
|