diff options
Diffstat (limited to 'src/emu/sound/dmadac.c')
-rw-r--r-- | src/emu/sound/dmadac.c | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/src/emu/sound/dmadac.c b/src/emu/sound/dmadac.c new file mode 100644 index 00000000000..0fcf8a9ef50 --- /dev/null +++ b/src/emu/sound/dmadac.c @@ -0,0 +1,272 @@ +/*************************************************************************** + + DMA-driven DAC driver + by Aaron Giles + +***************************************************************************/ + +#include "sndintrf.h" +#include "streams.h" +#include "dmadac.h" + + + +/************************************* + * + * Debugging + * + *************************************/ + +#define VERBOSE 0 + +#if VERBOSE +#define LOG(x) logerror x +#else +#define LOG(x) +#endif + + + +/************************************* + * + * Constants + * + *************************************/ + +#define DEFAULT_SAMPLE_RATE (44100) + +#define BUFFER_SIZE 32768 + + + +/************************************* + * + * Types + * + *************************************/ + +struct dmadac_channel_data +{ + /* sound stream and buffers */ + sound_stream * channel; + INT16 * buffer; + UINT32 bufin; + UINT32 bufout; + + /* per-channel parameters */ + INT16 volume; + UINT8 enabled; + double frequency; +}; + + + +/************************************* + * + * Stream callback + * + *************************************/ + +static void dmadac_update(void *param, stream_sample_t **inputs, stream_sample_t **_buffer, int length) +{ + struct dmadac_channel_data *ch = param; + stream_sample_t *output = _buffer[0]; + INT16 *source = ch->buffer; + UINT32 curout = ch->bufout; + UINT32 curin = ch->bufin; + int volume = ch->volume; + + /* feed as much as we can */ + while (curout != curin && length-- > 0) + *output++ = (source[curout++ % BUFFER_SIZE] * volume) >> 8; + + /* fill the rest with silence */ + while (length-- > 0) + *output++ = 0; + + /* save the new output pointer */ + ch->bufout = curout % BUFFER_SIZE; +} + + + +/************************************* + * + * Sound hardware init + * + *************************************/ + +static void *dmadac_start(int sndindex, int clock, const void *config) +{ + struct dmadac_channel_data *info; + + info = auto_malloc(sizeof(*info)); + memset(info, 0, sizeof(*info)); + + /* allocate a clear a buffer */ + info->buffer = auto_malloc(sizeof(info->buffer[0]) * BUFFER_SIZE); + memset(info->buffer, 0, sizeof(info->buffer[0]) * BUFFER_SIZE); + + /* reset the state */ + info->volume = 0x100; + + /* allocate a stream channel */ + info->channel = stream_create(0, 1, DEFAULT_SAMPLE_RATE, info, dmadac_update); + + /* register with the save state system */ + state_save_register_item("dmadac", sndindex, info->bufin); + state_save_register_item("dmadac", sndindex, info->bufout); + state_save_register_item("dmadac", sndindex, info->volume); + state_save_register_item("dmadac", sndindex, info->enabled); + state_save_register_item("dmadac", sndindex, info->frequency); + state_save_register_item_pointer("dmadac", sndindex, info->buffer, BUFFER_SIZE); + + return info; +} + + + +/************************************* + * + * Primary transfer routine + * + *************************************/ + +void dmadac_transfer(UINT8 first_channel, UINT8 num_channels, offs_t channel_spacing, offs_t frame_spacing, offs_t total_frames, INT16 *data) +{ + int i, j; + + /* flush out as much data as we can */ + for (i = 0; i < num_channels; i++) + { + struct dmadac_channel_data *info = sndti_token(SOUND_DMADAC, first_channel + i); + stream_update(info->channel); + } + + /* loop over all channels and accumulate the data */ + for (i = 0; i < num_channels; i++) + { + struct dmadac_channel_data *ch = sndti_token(SOUND_DMADAC, first_channel + i); + if (ch->enabled) + { + int maxin = (ch->bufout + BUFFER_SIZE - 1) % BUFFER_SIZE; + INT16 *src = data + i * channel_spacing; + int curin = ch->bufin; + + /* copy the data */ + for (j = 0; j < total_frames && curin != maxin; j++) + { + ch->buffer[curin++ % BUFFER_SIZE] = *src; + src += frame_spacing; + } + ch->bufin = curin; + + /* log overruns */ + if (j != total_frames) + logerror("dmadac_transfer: buffer overrun (short %d frames)\n", total_frames - j); + } + } + + LOG(("dmadac_transfer - %d samples, %d effective, %d in buffer\n", total_frames, (int)(total_frames * (double)DEFAULT_SAMPLE_RATE / dmadac[first_channel].frequency), dmadac[first_channel].curinpos - dmadac[first_channel].curoutpos)); +} + + + +/************************************* + * + * Enable/disable DMA channel(s) + * + *************************************/ + +void dmadac_enable(UINT8 first_channel, UINT8 num_channels, UINT8 enable) +{ + int i; + + /* flush out as much data as we can */ + for (i = 0; i < num_channels; i++) + { + struct dmadac_channel_data *info = sndti_token(SOUND_DMADAC, first_channel + i); + stream_update(info->channel); + info->enabled = enable; + if (!enable) + info->bufin = info->bufout = 0; + } +} + + + +/************************************* + * + * Set the frequency on DMA channel(s) + * + *************************************/ + +void dmadac_set_frequency(UINT8 first_channel, UINT8 num_channels, double frequency) +{ + int i; + + /* set the sample rate on each channel */ + for (i = 0; i < num_channels; i++) + { + struct dmadac_channel_data *info = sndti_token(SOUND_DMADAC, first_channel + i); + stream_set_sample_rate(info->channel, frequency); + } +} + + + +/************************************* + * + * Set the volume on DMA channel(s) + * + *************************************/ + +void dmadac_set_volume(UINT8 first_channel, UINT8 num_channels, UINT16 volume) +{ + int i; + + /* flush out as much data as we can */ + for (i = 0; i < num_channels; i++) + { + struct dmadac_channel_data *info = sndti_token(SOUND_DMADAC, first_channel + i); + stream_update(info->channel); + info->volume = volume; + } +} + + + +/************************************************************************** + * Generic get_info + **************************************************************************/ + +static void dmadac_set_info(void *token, UINT32 state, sndinfo *info) +{ + switch (state) + { + /* no parameters to set */ + } +} + + +void dmadac_get_info(void *token, UINT32 state, sndinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case SNDINFO_PTR_SET_INFO: info->set_info = dmadac_set_info; break; + case SNDINFO_PTR_START: info->start = dmadac_start; break; + case SNDINFO_PTR_STOP: /* nothing */ break; + case SNDINFO_PTR_RESET: /* nothing */ break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case SNDINFO_STR_NAME: info->s = "DMA-driven DAC"; break; + case SNDINFO_STR_CORE_FAMILY: info->s = "DAC"; break; + case SNDINFO_STR_CORE_VERSION: info->s = "1.0"; break; + case SNDINFO_STR_CORE_FILE: info->s = __FILE__; break; + case SNDINFO_STR_CORE_CREDITS: info->s = "Copyright (c) 2004, The MAME Team"; break; + } +} + |