summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/sound/dmadac.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/sound/dmadac.c')
-rw-r--r--src/emu/sound/dmadac.c272
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;
+ }
+}
+