summaryrefslogblamecommitdiffstatshomepage
path: root/src/emu/sound/ymz770.c
blob: 135b8d6b7807050b7b7cb52a5b5484c6f958cef3 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11










                                                                            
                       



                                                          





                                                                                                           
                                                      









                                                                            

                                                                                      



                                               
                                                   
                                                                                          

         











                                                                 
                                                     
                                                         
                                                           



                                                               














                                                   


                                           
                                               
                                                   























                                                                                                                               












                                                                             
                                                                                        



                                                                                                                                                                       
                                                         



                                                                                                    




                                                                                       


                                                                                    


                                         



                                                                      
                                                                                                                           



                                                                        
                                      

                                                                    


                                                                                                   
                                                                                                                                                                        
                                                 



                                                                                                
                                         

                                                                    
                                         













                                                                                                                                                              

                                                                            
                                                                                                           

















                                                          
                                                              














                                               
                 












                                                              
                                             

                                                                              
                                                                                                                                                   





                                                                             
                                    







                                                                           
                                 













                                                                                                                                               
                                                                     
                                                                              




                                                                                       
                                                                  


                                      
 









                                                          
/***************************************************************************

    ymz770.c

    Emulation by R. Belmont
    AMM decode by Olivier Galibert

***************************************************************************/

#include "emu.h"
#include "ymz770.h"
#include "mpeg_audio.h"

// device type definition
const device_type YMZ770 = &device_creator<ymz770_device>;

//-------------------------------------------------
//  ymz770_device - constructor
//-------------------------------------------------

ymz770_device::ymz770_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
	: device_t(mconfig, YMZ770, "Yamaha YMZ770", tag, owner, clock),
		device_sound_interface(mconfig, *this)
{
}

//-------------------------------------------------
//  device_start - device-specific startup
//-------------------------------------------------
void ymz770_device::device_start()
{
	// create the stream
	m_stream = machine().sound().stream_alloc(*this, 0, 2, 16000, this);
	rom_base = device().machine().root_device().memregion(":ymz770")->base();
	rom_size = device().machine().root_device().memregion(":ymz770")->bytes() * 8;

	for (int i = 0; i < 8; i++)
	{
		channels[i].is_playing = false;
		channels[i].is_seq_playing = false;
		channels[i].decoder = new mpeg_audio(rom_base, mpeg_audio::AMM, false, 0);
	}


	save_item(NAME(cur_reg));
	for (int i = 0; i < 8; i++)
	{
		save_item(NAME(channels[i].phrase), i);
		save_item(NAME(channels[i].pan), i);
		save_item(NAME(channels[i].volume), i);
		save_item(NAME(channels[i].control), i);
		save_item(NAME(channels[i].is_playing), i);
		save_item(NAME(channels[i].last_block), i);
		save_item(NAME(channels[i].output_remaining), i);
		save_item(NAME(channels[i].output_ptr), i);
		save_item(NAME(channels[i].pptr), i);
		save_item(NAME(channels[i].sequence), i);
		save_item(NAME(channels[i].seqcontrol), i);
		save_item(NAME(channels[i].seqdelay), i);
		save_item(NAME(channels[i].is_seq_playing), i);
		save_item(NAME(channels[i].output_data), i);
	}
}


//-------------------------------------------------
//  device_reset - device-specific reset
//-------------------------------------------------

void ymz770_device::device_reset()
{
	for (int i = 0; i < 8; i++)
	{
		channels[i].phrase = 0;
		channels[i].pan = 8;
		channels[i].volume = 0;
		channels[i].control = 0;
		channels[i].sequence = 0;
		channels[i].seqcontrol = 0;
		channels[i].seqdelay = 0;
		channels[i].is_playing = false;
		channels[i].is_seq_playing = false;
	}
}

//-------------------------------------------------
//  sound_stream_update - handle update requests for
//  our sound stream
//-------------------------------------------------

void ymz770_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{
	stream_sample_t *outL, *outR;
	int i, ch;

	outL = outputs[0];
	outR = outputs[1];

	for (i = 0; i < samples; i++)
	{
		INT32 mix;

		mix = 0;

		for (ch = 0; ch < 8; ch++)
		{
			if (channels[ch].is_seq_playing)
			{
				if (channels[ch].seqdelay != 0)
				{
					channels[ch].seqdelay--;
				}
				else
				{
					int reg = *channels[ch].seqdata++;
					UINT8 data = *channels[ch].seqdata++;
					switch (reg)
					{
						case 0x0f:
							if (channels[ch].seqcontrol & 1)
							{
								UINT8 sqn = channels[ch].sequence;
								UINT32 pptr = rom_base[(4*sqn)+1+0x400]<<16 | rom_base[(4*sqn)+2+0x400]<<8 | rom_base[(4*sqn)+3+0x400];
								channels[ch].seqdata = &rom_base[pptr];
							}
							else
							{
								channels[ch].is_seq_playing = false;
							}
							break;
						case 0x0e:
							channels[ch].seqdelay = 32 - 1;
							break;
						default:
							cur_reg = reg;
							internal_reg_write(1, data);
							break;
					}
				}
			}
			if (channels[ch].is_playing)
			{
				if (channels[ch].output_remaining > 0)
				{
					mix += (channels[ch].output_data[channels[ch].output_ptr++]*2*channels[ch].volume);
					channels[ch].output_remaining--;
				}
				else
				{
				retry:
					if (channels[ch].last_block)
					{
						if (channels[ch].control & 1)
						{
								UINT8 phrase = channels[ch].phrase;
								channels[ch].pptr = 8*(rom_base[(4*phrase)+1]<<16 | rom_base[(4*phrase)+2]<<8 | rom_base[(4*phrase)+3]);
						}
						else
						{
								channels[ch].is_playing = false;
						}
					}

					if (channels[ch].is_playing)
					{
						int sample_rate, channel_count;
						if(!channels[ch].decoder->decode_buffer(channels[ch].pptr,
																rom_size,
																channels[ch].output_data,
																channels[ch].output_remaining,
																sample_rate,
																channel_count))
						{
							channels[ch].last_block = true;
							goto retry;
						}

						channels[ch].last_block = channels[ch].output_remaining < 1152;
						channels[ch].output_remaining--;
						channels[ch].output_ptr = 1;

						mix += (channels[ch].output_data[0]*2*channels[ch].volume);
					}
				}
			}
		}

		outL[i] = outR[i] = mix>>8;
	}
}

//-------------------------------------------------
//  read - read from the chip's registers and internal RAM
//-------------------------------------------------

READ8_MEMBER( ymz770_device::read )
{
	return 0;
}

void ymz770_device::internal_reg_write(int offset, UINT8 data)
{
	if (!offset)
	{
		cur_reg = data;
		return;
	}

	if (cur_reg >= 0x40 && cur_reg <= 0x5f)
	{
		cur_reg -= 0x40;

		int voice = cur_reg / 4;
		int reg = cur_reg % 4;

		switch (reg)
		{
			case 0:
				channels[voice].phrase = data;
				break;

			case 1:
				channels[voice].volume = data;
				break;

			case 2:
				channels[voice].pan = data;
				break;

			case 3:
				if (data & 6)
				{
					UINT8 phrase = channels[voice].phrase;
					channels[voice].pptr = 8*(rom_base[(4*phrase)+1]<<16 | rom_base[(4*phrase)+2]<<8 | rom_base[(4*phrase)+3]);
					channels[voice].output_remaining = 0;
					channels[voice].output_ptr = 0;
					channels[voice].last_block = false;

					channels[voice].is_playing = true;
				}
				else
				{
					channels[voice].is_playing = false;
				}

				channels[voice].control = data;
				break;
		}
	}
	else if (cur_reg >= 0x80)
	{
		int voice = (cur_reg & 0x70)>>4;
		int reg = cur_reg & 0x0f;
		switch (reg)
		{
			case 0:
				channels[voice].sequence = data;
				break;
			case 1:
				if (data & 6)
				{
					UINT8 sqn = channels[voice].sequence;
					UINT32 pptr = rom_base[(4*sqn)+1+0x400]<<16 | rom_base[(4*sqn)+2+0x400]<<8 | rom_base[(4*sqn)+3+0x400];
					channels[voice].seqdata = &rom_base[pptr];
					channels[voice].seqdelay = 0;
					channels[voice].is_seq_playing = true;
				}
				else
				{
						channels[voice].is_seq_playing = false;
				}
				channels[voice].seqcontrol = data;
				break;
		}
	}
}

//-------------------------------------------------
//  write - write to the chip's registers and internal RAM
//-------------------------------------------------

WRITE8_MEMBER( ymz770_device::write )
{
	m_stream->update();
	internal_reg_write(offset, data);
}