summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/sound/cdda.cpp
blob: 1b2d766493ef60e0d0ad42b0c878c9cc2075cfed (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                                    




                                                         
                

                 

                         
 


                                                   
 
                                                                                                                             
 
                                                                

                                                   

 


                                                   
 
                                
 
                                     
                                                                                       
 
                                                                        







                                   
                         





                                                  
                                                                              

                                           







                                                   
                                       
 
                                    







                                                   
                                                                    
 
                           


                                       


                                   







                                                   
                              
 
                           

                                      







                                                   
                                        
 

                              







                                                   
                                     
 

                           







                                                   
                               
 

                               







                                                   
                               
 
                             







                                                   
                              
 
                           
                                      








                                                   
                                                                                                       
 
              
                                                               
 
                                  
         


                                                                                                          
                 

                                                                                            

                                                              




                                                                                

                 

                                              
                 
                                                  

                 


                                                                  

                                                                                                               
                 
 

                                           
 






                                                      
 


                                                                                                                           
 

                                              
 

                                                                         
 

                                               
                 
         

 
                                                   



                                                       
                                                    
 
                                       

 
                                                      
 
                                                                                                         



                                                    
 
 
// license:BSD-3-Clause
// copyright-holders:Aaron Giles,smf
/*
    CD-DA "Red Book" audio sound hardware handler
    Relies on the actual CD logic and reading in cdrom.c.
*/

#include "emu.h"
#include "cdda.h"

#define MAX_SECTORS ( 4 )


//-------------------------------------------------
//  sound_stream_update - handle a stream update
//-------------------------------------------------

void cdda_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{
	get_audio_data(&outputs[0][0], &outputs[1][0], samples);
	m_audio_volume[0] = int16_t(outputs[0][0]);
	m_audio_volume[1] = int16_t(outputs[1][0]);
}

//-------------------------------------------------
//  device_start - device-specific startup
//-------------------------------------------------

void cdda_device::device_start()
{
	/* allocate an audio cache */
	m_audio_cache = std::make_unique<uint8_t[]>(CD_MAX_SECTOR_DATA * MAX_SECTORS );

	m_stream = machine().sound().stream_alloc(*this, 0, 2, clock());

	m_audio_playing = 0;
	m_audio_pause = 0;
	m_audio_ended_normally = 0;
	m_audio_lba = 0;
	m_audio_length = 0;
	m_audio_samples = 0;
	m_audio_bptr = 0;
	m_disc = nullptr;

	save_item( NAME(m_audio_playing) );
	save_item( NAME(m_audio_pause) );
	save_item( NAME(m_audio_ended_normally) );
	save_item( NAME(m_audio_lba) );
	save_item( NAME(m_audio_length) );
	save_pointer( NAME(m_audio_cache), CD_MAX_SECTOR_DATA * MAX_SECTORS );
	save_item( NAME(m_audio_samples) );
	save_item( NAME(m_audio_bptr) );
}


/*-------------------------------------------------
    cdda_set_cdrom - set the CD-ROM file for the
    given CDDA stream
-------------------------------------------------*/

void cdda_device::set_cdrom(void *file)
{
	m_disc = (cdrom_file *)file;
}


/*-------------------------------------------------
    cdda_start_audio - begin playback of a Red
    Book audio track
-------------------------------------------------*/

void cdda_device::start_audio(uint32_t startlba, uint32_t numblocks)
{
	m_stream->update();
	m_audio_playing = true;
	m_audio_pause = false;
	m_audio_ended_normally = false;
	m_audio_lba = startlba;
	m_audio_length = numblocks;
	m_audio_samples = 0;
}


/*-------------------------------------------------
    cdda_stop_audio - stop playback of a Red Book
    audio track
-------------------------------------------------*/

void cdda_device::stop_audio()
{
	m_stream->update();
	m_audio_playing = false;
	m_audio_ended_normally = true;
}


/*-------------------------------------------------
    cdda_pause_audio - pause/unpause playback of
    a Red Book audio track
-------------------------------------------------*/

void cdda_device::pause_audio(int pause)
{
	m_stream->update();
	m_audio_pause = pause;
}


/*-------------------------------------------------
    cdda_get_audio_lba - returns the current LBA
    (physical sector) during Red Book playback
-------------------------------------------------*/

uint32_t cdda_device::get_audio_lba()
{
	m_stream->update();
	return m_audio_lba;
}


/*-------------------------------------------------
    cdda_audio_active - returns Red Book audio
    playback status
-------------------------------------------------*/

int cdda_device::audio_active()
{
	m_stream->update();
	return m_audio_playing;
}


/*-------------------------------------------------
    cdda_audio_paused - returns if Red Book
    playback is paused
-------------------------------------------------*/

int cdda_device::audio_paused()
{
	return m_audio_pause;
}


/*-------------------------------------------------
    cdda_audio_ended - returns if a Red Book
    track reached it's natural end
-------------------------------------------------*/

int cdda_device::audio_ended()
{
	m_stream->update();
	return m_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
-------------------------------------------------*/

void cdda_device::get_audio_data(stream_sample_t *bufL, stream_sample_t *bufR, uint32_t samples_wanted)
{
	int i;
	int16_t *audio_cache = (int16_t *) m_audio_cache.get();

	while (samples_wanted > 0)
	{
		/* if no file, audio not playing, audio paused, or out of disc data,
		   just zero fill */
		if (!m_disc || !m_audio_playing || m_audio_pause || (!m_audio_length && !m_audio_samples))
		{
			if( m_disc && m_audio_playing && !m_audio_pause && !m_audio_length )
			{
				m_audio_playing = false;
				m_audio_ended_normally = true;
			}

			memset(bufL, 0, sizeof(stream_sample_t)*samples_wanted);
			memset(bufR, 0, sizeof(stream_sample_t)*samples_wanted);
			return;
		}

		int samples = samples_wanted;
		if (samples > m_audio_samples)
		{
			samples = m_audio_samples;
		}

		for (i = 0; i < samples; i++)
		{
			/* CD-DA data on the disc is big-endian */
			*bufL++ = (int16_t) big_endianize_int16( audio_cache[ m_audio_bptr ] ); m_audio_bptr++;
			*bufR++ = (int16_t) big_endianize_int16( audio_cache[ m_audio_bptr ] ); m_audio_bptr++;
		}

		samples_wanted -= samples;
		m_audio_samples -= samples;

		if (m_audio_samples == 0)
		{
			int sectors = m_audio_length;
			if (sectors > MAX_SECTORS)
			{
				sectors = MAX_SECTORS;
			}

			for (i = 0; i < sectors; i++)
			{
				cdrom_read_data(m_disc, m_audio_lba, &m_audio_cache[CD_MAX_SECTOR_DATA*i], CD_TRACK_AUDIO);

				m_audio_lba++;
			}

			m_audio_samples = (CD_MAX_SECTOR_DATA*sectors)/4;
			m_audio_length -= sectors;

			/* reset feedout ptr */
			m_audio_bptr = 0;
		}
	}
}

/*-------------------------------------------------
    cdda_get_channel_volume - sets CD-DA volume level
    for either speaker, used for volume control display
-------------------------------------------------*/

int16_t cdda_device::get_channel_volume(int channel)
{
	return m_audio_volume[channel];
}

DEFINE_DEVICE_TYPE(CDDA, cdda_device, "cdda", "CD/DA")

cdda_device::cdda_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, CDDA, tag, owner, clock)
	, device_sound_interface(mconfig, *this)
	, m_disc(nullptr)
	, m_stream(nullptr)
{
}