summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/sound/cdda.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/sound/cdda.c')
-rw-r--r--trunk/src/emu/sound/cdda.c342
1 files changed, 342 insertions, 0 deletions
diff --git a/trunk/src/emu/sound/cdda.c b/trunk/src/emu/sound/cdda.c
new file mode 100644
index 00000000000..8b4a9af1118
--- /dev/null
+++ b/trunk/src/emu/sound/cdda.c
@@ -0,0 +1,342 @@
+/*
+ CD-DA "Red Book" audio sound hardware handler
+ Relies on the actual CD logic and reading in cdrom.c.
+*/
+
+#include "emu.h"
+#include "cdrom.h"
+#include "cdda.h"
+
+typedef struct _cdda_info cdda_info;
+struct _cdda_info
+{
+ sound_stream * stream;
+ cdrom_file * disc;
+
+ INT8 audio_playing, audio_pause, audio_ended_normally;
+ UINT32 audio_lba, audio_length;
+
+ UINT8 * audio_cache;
+ UINT32 audio_samples;
+ UINT32 audio_bptr;
+};
+
+INLINE cdda_info *get_safe_token(device_t *device)
+{
+ assert(device != NULL);
+ assert(device->type() == CDDA);
+ return (cdda_info *)downcast<legacy_device_base *>(device)->token();
+}
+
+#define MAX_SECTORS ( 4 )
+
+static void get_audio_data(cdda_info *info, stream_sample_t *bufL, stream_sample_t *bufR, UINT32 samples_wanted);
+
+
+/*-------------------------------------------------
+ cdda_update - stream update callback
+-------------------------------------------------*/
+
+static STREAM_UPDATE( cdda_update )
+{
+ cdda_info *info = (cdda_info *)param;
+ get_audio_data(info, &outputs[0][0], &outputs[1][0], samples);
+}
+
+
+/*-------------------------------------------------
+ DEVICE_START( cdda ) - audio start callback
+-------------------------------------------------*/
+
+static DEVICE_START( cdda )
+{
+ //const struct CDDAinterface *intf;
+ cdda_info *info = get_safe_token(device);
+
+ /* allocate an audio cache */
+ info->audio_cache = auto_alloc_array( device->machine(), UINT8, CD_MAX_SECTOR_DATA * MAX_SECTORS );
+
+ //intf = (const struct CDDAinterface *)device->static_config();
+
+ info->stream = device->machine().sound().stream_alloc(*device, 0, 2, 44100, info, cdda_update);
+
+ device->save_item( NAME(info->audio_playing) );
+ device->save_item( NAME(info->audio_pause) );
+ device->save_item( NAME(info->audio_ended_normally) );
+ device->save_item( NAME(info->audio_lba) );
+ device->save_item( NAME(info->audio_length) );
+ device->save_pointer( NAME(info->audio_cache), CD_MAX_SECTOR_DATA * MAX_SECTORS );
+ device->save_item( NAME(info->audio_samples) );
+ device->save_item( NAME(info->audio_bptr) );
+}
+
+
+/*-------------------------------------------------
+ cdda_set_cdrom - set the CD-ROM file for the
+ given CDDA stream
+-------------------------------------------------*/
+
+void cdda_set_cdrom(device_t *device, void *file)
+{
+ cdda_info *info = get_safe_token(device);
+ info->disc = (cdrom_file *)file;
+}
+
+
+/*-------------------------------------------------
+ cdda_from_cdrom - find the CDDA stream
+ that references the given CD-ROM file
+-------------------------------------------------*/
+
+device_t *cdda_from_cdrom(running_machine &machine, void *file)
+{
+ sound_interface_iterator iter(machine.root_device());
+ for (device_sound_interface *sound = iter.first(); sound != NULL; sound = iter.next())
+ if (sound->device().type() == CDDA)
+ {
+ cdda_info *info = get_safe_token(*sound);
+ if (info->disc == file)
+ return *sound;
+ }
+
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ cdda_start_audio - begin playback of a Red
+ Book audio track
+-------------------------------------------------*/
+
+void cdda_start_audio(device_t *device, UINT32 startlba, UINT32 numblocks)
+{
+ cdda_info *info = get_safe_token(device);
+
+ info->stream->update();
+ info->audio_playing = TRUE;
+ info->audio_pause = FALSE;
+ info->audio_ended_normally = FALSE;
+ info->audio_lba = startlba;
+ info->audio_length = numblocks;
+}
+
+
+/*-------------------------------------------------
+ cdda_stop_audio - stop playback of a Red Book
+ audio track
+-------------------------------------------------*/
+
+void cdda_stop_audio(device_t *device)
+{
+ cdda_info *info = get_safe_token(device);
+
+ info->stream->update();
+ info->audio_playing = FALSE;
+ info->audio_ended_normally = TRUE;
+}
+
+
+/*-------------------------------------------------
+ cdda_pause_audio - pause/unpause playback of
+ a Red Book audio track
+-------------------------------------------------*/
+
+void cdda_pause_audio(device_t *device, int pause)
+{
+ cdda_info *info = get_safe_token(device);
+
+ info->stream->update();
+ info->audio_pause = pause;
+}
+
+
+/*-------------------------------------------------
+ cdda_get_audio_lba - returns the current LBA
+ (physical sector) during Red Book playback
+-------------------------------------------------*/
+
+UINT32 cdda_get_audio_lba(device_t *device)
+{
+ cdda_info *info = get_safe_token(device);
+
+ info->stream->update();
+ return info->audio_lba;
+}
+
+
+/*-------------------------------------------------
+ cdda_audio_active - returns Red Book audio
+ playback status
+-------------------------------------------------*/
+
+int cdda_audio_active(device_t *device)
+{
+ cdda_info *info = get_safe_token(device);
+
+ info->stream->update();
+ return info->audio_playing;
+}
+
+
+/*-------------------------------------------------
+ cdda_audio_paused - returns if Red Book
+ playback is paused
+-------------------------------------------------*/
+
+int cdda_audio_paused(device_t *device)
+{
+ cdda_info *info = get_safe_token(device);
+ return info->audio_pause;
+}
+
+
+/*-------------------------------------------------
+ cdda_audio_ended - returns if a Red Book
+ track reached it's natural end
+-------------------------------------------------*/
+
+int cdda_audio_ended(device_t *device)
+{
+ cdda_info *info = get_safe_token(device);
+ return info->audio_ended_normally;
+}
+
+
+/*-------------------------------------------------
+ get_audio_data - reads Red Book data off
+ the disc if playback is in progress and
+ converts it to 2 16-bit 44.1 kHz streams
+-------------------------------------------------*/
+
+static void get_audio_data(cdda_info *info, stream_sample_t *bufL, stream_sample_t *bufR, UINT32 samples_wanted)
+{
+ int i, sectoread, remaining;
+ INT16 *audio_cache = (INT16 *) info->audio_cache;
+
+ /* if no file, audio not playing, audio paused, or out of disc data,
+ just zero fill */
+ if (!info->disc || !info->audio_playing || info->audio_pause || (!info->audio_length && !info->audio_samples))
+ {
+ if( info->disc && info->audio_playing && !info->audio_pause && !info->audio_length )
+ {
+ info->audio_playing = FALSE;
+ info->audio_ended_normally = TRUE;
+ }
+
+ memset(bufL, 0, sizeof(stream_sample_t)*samples_wanted);
+ memset(bufR, 0, sizeof(stream_sample_t)*samples_wanted);
+ return;
+ }
+
+ /* if we've got enough samples, just feed 'em out */
+ if (samples_wanted <= info->audio_samples)
+ {
+ for (i = 0; i < samples_wanted; i++)
+ {
+ *bufL++ = audio_cache[ info->audio_bptr++ ];
+ *bufR++ = audio_cache[ info->audio_bptr++ ];
+ }
+
+ info->audio_samples -= samples_wanted;
+ return;
+ }
+
+ /* we don't have enough, so first feed what we've got */
+ for (i = 0; i < info->audio_samples; i++)
+ {
+ *bufL++ = audio_cache[ info->audio_bptr++ ];
+ *bufR++ = audio_cache[ info->audio_bptr++ ];
+ }
+
+ /* remember how much left for later */
+ remaining = samples_wanted - info->audio_samples;
+
+ /* reset the buffer and get what we can from the disc */
+ info->audio_samples = 0;
+ if (info->audio_length >= MAX_SECTORS)
+ {
+ sectoread = MAX_SECTORS;
+ }
+ else
+ {
+ sectoread = info->audio_length;
+ }
+
+ for (i = 0; i < sectoread; i++)
+ {
+ cdrom_read_data(info->disc, info->audio_lba, &info->audio_cache[CD_MAX_SECTOR_DATA*i], CD_TRACK_AUDIO);
+
+ info->audio_lba++;
+ }
+
+ info->audio_samples = (CD_MAX_SECTOR_DATA*sectoread)/4;
+ info->audio_length -= sectoread;
+
+ /* CD-DA data on the disc is big-endian, flip if we're not */
+ if (ENDIANNESS_NATIVE == ENDIANNESS_LITTLE)
+ {
+ for( i = 0; i < info->audio_samples * 2; i++ )
+ {
+ audio_cache[ i ] = BIG_ENDIANIZE_INT16( audio_cache[ i ] );
+ }
+ }
+
+ /* reset feedout ptr */
+ info->audio_bptr = 0;
+
+ /* we've got data, feed it out by calling ourselves recursively */
+ get_audio_data(info, bufL, bufR, remaining);
+}
+
+/*-------------------------------------------------
+ cdda_set_volume - sets CD-DA volume level
+ for both speakers, used for fade in/out effects
+-------------------------------------------------*/
+
+void cdda_set_volume(device_t *device,int volume)
+{
+ cdda_info *cdda = get_safe_token(device);
+
+ cdda->stream->set_output_gain(0,volume / 100.0);
+ cdda->stream->set_output_gain(1,volume / 100.0);
+}
+
+/*-------------------------------------------------
+ cdda_set_channel_volume - sets CD-DA volume level
+ for either speaker, used for fade in/out effects
+-------------------------------------------------*/
+
+void cdda_set_channel_volume(device_t *device, int channel, int volume)
+{
+ cdda_info *cdda = get_safe_token(device);
+
+ cdda->stream->set_output_gain(channel,volume / 100.0);
+}
+
+/**************************************************************************
+ * Generic get_info
+ **************************************************************************/
+
+DEVICE_GET_INFO( cdda )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(cdda_info); break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( cdda ); break;
+ case DEVINFO_FCT_STOP: /* nothing */ break;
+ case DEVINFO_FCT_RESET: /* nothing */ break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "CD/DA"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "CD Audio"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
+ }
+}
+
+
+DEFINE_LEGACY_SOUND_DEVICE(CDDA, cdda);