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

                                        
                



                    
                                                        
 
                                                              
                    
 











                                                               







                                                                      































                                                  






                                                   


















































                                                     




                                             
                                                                      

                                                                      
                                                           



                                                                     














































































































                                                        




                                                               












                                                      

  
                                                                    
 
                                                                 
                                                                             

                                                                         

                                                                         
                                                                         
                                                                             
                                                                                     
                                                                             
                                                                                 
                                                                                         


                                                                                 

         
                                                                 
                                                                     
                                                                     


                                                                             
                                                                                 


                                                                 
                                                                     

                                                                         

                                                                         
                                                                         

                                                                             
                                                                         

                                                                             


         












                                                                            
                                                                                                             
                                                                                        
                                                       

                                   











                                  
                             
 













                                                   
                       



                                                     

                                   
         
                                        
                 
                                                                                     


                                            







                                                          
 













                                        

 
 




                                                                                                                                
 
                                      
                                             
 
                             
                                                 
         

                                            


                       
                              







                                                                           

                                          
                 

                                                                   
 
                                                        
                         
                                                               
                                                            

                                                                                 
                                                     


                                                                          
                                                     







                                                                     
                                           


         
 


                                                   
 

                                              

                         
                                
                       
 
                                               
 
                                                        
                            
 


                                            

 
 





                                                         



                      
                       
 
                                                                 

                                                        
                            

                                                                      










                                                   
 


                                                 

 














                                                        



                                               
                                                          
                               

                       
                                                        
                            
 
                                             
                               


                                      
                                                                      
 








                                                        

                 
                                                             

                          

                                           
// license:BSD-3-Clause
// copyright-holders:Juergen Buchmueller
#include "emu.h"
#include "tms36xx.h"

#define VERBOSE 1

#define LOG(x) do { if (VERBOSE) logerror x; } while (0)

/* the frequencies are later adjusted by "* clock / FSCALE" */
#define FSCALE  1024

#define C(n)    (int)((FSCALE<<(n-1))*1.18921)  /* 2^(3/12) */
#define Cx(n)   (int)((FSCALE<<(n-1))*1.25992)  /* 2^(4/12) */
#define D(n)    (int)((FSCALE<<(n-1))*1.33484)  /* 2^(5/12) */
#define Dx(n)   (int)((FSCALE<<(n-1))*1.41421)  /* 2^(6/12) */
#define E(n)    (int)((FSCALE<<(n-1))*1.49831)  /* 2^(7/12) */
#define F(n)    (int)((FSCALE<<(n-1))*1.58740)  /* 2^(8/12) */
#define Fx(n)   (int)((FSCALE<<(n-1))*1.68179)  /* 2^(9/12) */
#define G(n)    (int)((FSCALE<<(n-1))*1.78180)  /* 2^(10/12) */
#define Gx(n)   (int)((FSCALE<<(n-1))*1.88775)  /* 2^(11/12) */
#define A(n)    (int)((FSCALE<<n))              /* A */
#define Ax(n)   (int)((FSCALE<<n)*1.05946)      /* 2^(1/12) */
#define B(n)    (int)((FSCALE<<n)*1.12246)      /* 2^(2/12) */

/*
 * Alarm sound?
 * It is unknown what this sound is like. Until somebody manages
 * trigger sound #1 of the Phoenix PCB sound chip I put just something
 * 'alarming' in here.
 */
static const int tune1[96*6] = {
	C(3),   0,      0,      C(2),   0,      0,
	G(3),   0,      0,      0,      0,      0,
	C(3),   0,      0,      0,      0,      0,
	G(3),   0,      0,      0,      0,      0,
	C(3),   0,      0,      0,      0,      0,
	G(3),   0,      0,      0,      0,      0,
	C(3),   0,      0,      0,      0,      0,
	G(3),   0,      0,      0,      0,      0,
	C(3),   0,      0,      C(4),   0,      0,
	G(3),   0,      0,      0,      0,      0,
	C(3),   0,      0,      0,      0,      0,
	G(3),   0,      0,      0,      0,      0,
	C(3),   0,      0,      0,      0,      0,
	G(3),   0,      0,      0,      0,      0,
	C(3),   0,      0,      0,      0,      0,
	G(3),   0,      0,      0,      0,      0,
	C(3),   0,      0,      C(2),   0,      0,
	G(3),   0,      0,      0,      0,      0,
	C(3),   0,      0,      0,      0,      0,
	G(3),   0,      0,      0,      0,      0,
	C(3),   0,      0,      0,      0,      0,
	G(3),   0,      0,      0,      0,      0,
	C(3),   0,      0,      0,      0,      0,
	G(3),   0,      0,      0,      0,      0,
	C(3),   0,      0,      C(4),   0,      0,
	G(3),   0,      0,      0,      0,      0,
	C(3),   0,      0,      0,      0,      0,
	G(3),   0,      0,      0,      0,      0,
	C(3),   0,      0,      0,      0,      0,
	G(3),   0,      0,      0,      0,      0,
	C(3),   0,      0,      0,      0,      0,
	G(3),   0,      0,      0,      0,      0,
};

/*
 * Fuer Elise, Beethoven
 * (Excuse my non-existent musical skill, Mr. B ;-)
 */
static const int tune2[96*6] = {
	D(3),   D(4),   D(5),   0,      0,      0,
	Cx(3),  Cx(4),  Cx(5),  0,      0,      0,
	D(3),   D(4),   D(5),   0,      0,      0,
	Cx(3),  Cx(4),  Cx(5),  0,      0,      0,
	D(3),   D(4),   D(5),   0,      0,      0,
	A(2),   A(3),   A(4),   0,      0,      0,
	C(3),   C(4),   C(5),   0,      0,      0,
	Ax(2),  Ax(3),  Ax(4),  0,      0,      0,
	G(2),   G(3),   G(4),   0,      0,      0,
	D(1),   D(2),   D(3),   0,      0,      0,
	G(1),   G(2),   G(3),   0,      0,      0,
	Ax(1),  Ax(2),  Ax(3),  0,      0,      0,

	D(2),   D(3),   D(4),   0,      0,      0,
	G(2),   G(3),   G(4),   0,      0,      0,
	A(2),   A(3),   A(4),   0,      0,      0,
	D(1),   D(2),   D(3),   0,      0,      0,
	A(1),   A(2),   A(3),   0,      0,      0,
	D(2),   D(3),   D(4),   0,      0,      0,
	Fx(2),  Fx(3),  Fx(4),  0,      0,      0,
	A(2),   A(3),   A(4),   0,      0,      0,
	Ax(2),  Ax(3),  Ax(4),  0,      0,      0,
	D(1),   D(2),   D(3),   0,      0,      0,
	G(1),   G(2),   G(3),   0,      0,      0,
	Ax(1),  Ax(2),  Ax(3),  0,      0,      0,

	D(3),   D(4),   D(5),   0,      0,      0,
	Cx(3),  Cx(4),  Cx(5),  0,      0,      0,
	D(3),   D(4),   D(5),   0,      0,      0,
	Cx(3),  Cx(4),  Cx(5),  0,      0,      0,
	D(3),   D(4),   D(5),   0,      0,      0,
	A(2),   A(3),   A(4),   0,      0,      0,
	C(3),   C(4),   C(5),   0,      0,      0,
	Ax(2),  Ax(3),  Ax(4),  0,      0,      0,
	G(2),   G(3),   G(4),   0,      0,      0,
	D(1),   D(2),   D(3),   0,      0,      0,
	G(1),   G(2),   G(3),   0,      0,      0,
	Ax(1),  Ax(2),  Ax(3),  0,      0,      0,

	D(2),   D(3),   D(4),   0,      0,      0,
	G(2),   G(3),   G(4),   0,      0,      0,
	A(2),   A(3),   A(4),   0,      0,      0,
	D(1),   D(2),   D(3),   0,      0,      0,
	A(1),   A(2),   A(3),   0,      0,      0,
	D(2),   D(3),   D(4),   0,      0,      0,
	Ax(2),  Ax(3),  Ax(4),  0,      0,      0,
	A(2),   A(3),   A(4),   0,      0,      0,
	0,      0,      0,      G(2),   G(3),   G(4),
	D(1),   D(2),   D(3),   0,      0,      0,
	G(1),   G(2),   G(3),   0,      0,      0,
	0,      0,      0,      0,      0,      0
};

/*
 * The theme from Phoenix, a sad little tune.
 * Gerald Coy:
 *   The starting song from Phoenix comes from an old French movie and
 *   it's called : "Jeux interdits" which means "unallowed games"  ;-)
 * Mirko Buffoni:
 *   It's called "Sogni proibiti" in Italian, by Anonymous.
 * Magic*:
 *   This song is a classical piece called "ESTUDIO" from M.A.Robira.
 */
static const int tune3[96*6] = {
	A(2),   A(3),   A(4),   D(1),    D(2),    D(3),
	0,      0,      0,      0,       0,       0,
	A(2),   A(3),   A(4),   0,       0,       0,
	0,      0,      0,      0,       0,       0,
	A(2),   A(3),   A(4),   0,       0,       0,
	0,      0,      0,      0,       0,       0,

	A(2),   A(3),   A(4),   A(1),    A(2),    A(3),
	0,      0,      0,      0,       0,       0,
	G(2),   G(3),   G(4),   0,       0,       0,
	0,      0,      0,      0,       0,       0,
	F(2),   F(3),   F(4),   0,       0,       0,
	0,      0,      0,      0,       0,       0,

	F(2),   F(3),   F(4),   F(1),    F(2),    F(3),
	0,      0,      0,      0,       0,       0,
	E(2),   E(3),   E(4),   F(1),    F(2),    F(3),
	0,      0,      0,      0,       0,       0,
	D(2),   D(3),   D(4),   F(1),    F(2),    F(3),
	0,      0,      0,      0,       0,       0,

	D(2),   D(3),   D(4),   A(1),    A(2),    A(3),
	0,      0,      0,      0,       0,       0,
	F(2),   F(3),   F(4),   0,       0,       0,
	0,      0,      0,      0,       0,       0,
	A(2),   A(3),   A(4),   0,       0,       0,
	0,      0,      0,      0,       0,       0,

	D(3),   D(4),   D(5),   D(1),    D(2),    D(3),
	0,      0,      0,      0,       0,       0,
	0,      0,      0,      D(1),    D(2),    D(3),
	0,      0,      0,      F(1),    F(2),    F(3),
	0,      0,      0,      A(1),    A(2),    A(3),
	0,      0,      0,      D(2),    D(2),    D(2),

	D(3),   D(4),   D(5),   D(1),    D(2),    D(3),
	0,      0,      0,      0,       0,       0,
	C(3),   C(4),   C(5),   0,       0,       0,
	0,      0,      0,      0,       0,       0,
	Ax(2),  Ax(3),  Ax(4),  0,       0,       0,
	0,      0,      0,      0,       0,       0,

	Ax(2),  Ax(3),  Ax(4),  Ax(1),   Ax(2),   Ax(3),
	0,      0,      0,      0,       0,       0,
	A(2),   A(3),   A(4),   0,       0,       0,
	0,      0,      0,      0,       0,       0,
	G(2),   G(3),   G(4),   0,       0,       0,
	0,      0,      0,      0,       0,       0,

	G(2),   G(3),   G(4),   G(1),    G(2),    G(3),
	0,      0,      0,      0,       0,       0,
	A(2),   A(3),   A(4),   0,       0,       0,
	0,      0,      0,      0,       0,       0,
	Ax(2),  Ax(3),  Ax(4),  0,       0,       0,
	0,      0,      0,      0,       0,       0,

	A(2),   A(3),   A(4),   A(1),    A(2),    A(3),
	0,      0,      0,      0,       0,       0,
	Ax(2),  Ax(3),  Ax(4),  0,       0,       0,
	0,      0,      0,      0,       0,       0,
	A(2),   A(3),   A(4),   0,       0,       0,
	0,      0,      0,      0,       0,       0,

	Cx(3),  Cx(4),  Cx(5),  A(1),    A(2),    A(3),
	0,      0,      0,      0,       0,       0,
	Ax(2),  Ax(3),  Ax(4),  0,       0,       0,
	0,      0,      0,      0,       0,       0,
	A(2),   A(3),   A(4),   0,       0,       0,
	0,      0,      0,      0,       0,       0,

	A(2),   A(3),   A(4),   F(1),    F(2),    F(3),
	0,      0,      0,      0,       0,       0,
	G(2),   G(3),   G(4),   0,       0,       0,
	0,      0,      0,      0,       0,       0,
	F(2),   F(3),   F(4),   0,       0,       0,
	0,      0,      0,      0,       0,       0,

	F(2),   F(3),   F(4),   D(1),    D(2),    D(3),
	0,      0,      0,      0,       0,       0,
	E(2),   E(3),   E(4),   0,       0,       0,
	0,      0,      0,      0,       0,       0,
	D(2),   D(3),   D(4),   0,       0,       0,
	0,      0,      0,      0,       0,       0,

	E(2),   E(3),   E(4),   E(1),    E(2),    E(3),
	0,      0,      0,      0,       0,       0,
	E(2),   E(3),   E(4),   0,       0,       0,
	0,      0,      0,      0,       0,       0,
	E(2),   E(3),   E(4),   0,       0,       0,
	0,      0,      0,      0,       0,       0,

	E(2),   E(3),   E(4),   Ax(1),   Ax(2),   Ax(3),
	0,      0,      0,      0,       0,       0,
	F(2),   F(3),   F(4),   0,       0,       0,
	0,      0,      0,      0,       0,       0,
	E(2),   E(3),   E(4),   F(1),    F(2),    F(3),
	0,      0,      0,      0,       0,       0,

	D(2),   D(3),   D(4),   D(1),    D(2),    D(3),
	0,      0,      0,      0,       0,       0,
	F(2),   F(3),   F(4),   A(1),    A(2),    A(3),
	0,      0,      0,      0,       0,       0,
	A(2),   A(3),   A(4),   F(1),    F(2),    F(3),
	0,      0,      0,      0,       0,       0,

	D(3),   D(4),   D(5),   D(1),    D(2),    D(3),
	0,      0,      0,      0,       0,       0,
	0,      0,      0,      0,       0,       0,
	0,      0,      0,      0,       0,       0,
	0,      0,      0,      0,       0,       0,
	0,      0,      0,      0,       0,       0
};

/* This is used to play single notes for the TMS3615/TMS3617 */
static const int tune4[13*6] = {
/*  16'     8'      5 1/3'  4'      2 2/3'  2'      */
	B(0),   B(1),   Dx(2),  B(2),   Dx(3),  B(3),
	C(1),   C(2),   E(2),   C(3),   E(3),   C(4),
	Cx(1),  Cx(2),  F(2),   Cx(3),  F(3),   Cx(4),
	D(1),   D(2),   Fx(2),  D(3),   Fx(3),  D(4),
	Dx(1),  Dx(2),  G(2),   Dx(3),  G(3),   Dx(4),
	E(1),   E(2),   Gx(2),  E(3),   Gx(3),  E(4),
	F(1),   F(2),   A(2),   F(3),   A(3),   F(4),
	Fx(1),  Fx(2),  Ax(2),  Fx(3),  Ax(3),  Fx(4),
	G(1),   G(2),   B(2),   G(3),   B(3),   G(4),
	Gx(1),  Gx(2),  C(3),   Gx(3),  C(4),   Gx(4),
	A(1),   A(2),   Cx(3),  A(3),   Cx(4),  A(4),
	Ax(1),  Ax(2),  D(3),   Ax(3),  D(4),   Ax(4),
	B(1),   B(2),   Dx(3),  B(3),   Dx(4),  B(4)
};

static const int *const tunes[] = {nullptr,tune1,tune2,tune3,tune4};

#define DECAY(voice)                                            \
	if( m_vol[voice] > TMS36XX_VMIN )                                   \
	{                                                           \
		/* decay of first voice */                              \
		m_vol_counter[voice] -= m_decay[voice];                 \
		while( m_vol_counter[voice] <= 0 )                      \
		{                                                       \
			m_vol_counter[voice] += samplerate;                 \
			if( m_vol[voice]-- <= TMS36XX_VMIN )                        \
			{                                                   \
				m_frequency[voice] = 0;                         \
				m_vol[voice] = TMS36XX_VMIN;                            \
				break;                                          \
			}                                                   \
		}                                                       \
	}

#define RESTART(voice)                                          \
	if( tunes[m_tune_num][m_tune_ofs*6+voice] )                 \
	{                                                           \
		m_frequency[m_shift+voice] =                            \
			tunes[m_tune_num][m_tune_ofs*6+voice] *             \
			(m_basefreq << m_octave) / FSCALE;                  \
		m_vol[m_shift+voice] = TMS36XX_VMAX;                            \
	}

#define TONE(voice)                                             \
	if( (m_enable & (1<<voice)) && m_frequency[voice] )         \
	{                                                           \
		/* first note */                                        \
		m_counter[voice] -= m_frequency[voice];                 \
		while( m_counter[voice] <= 0 )                          \
		{                                                       \
			m_counter[voice] += samplerate;                     \
			m_output ^= 1 << voice;                             \
		}                                                       \
		if (m_output & m_enable & (1 << voice))                 \
			sum += m_vol[voice];                                \
	}



// device type definition
const device_type TMS36XX = &device_creator<tms36xx_device>;


//**************************************************************************
//  LIVE DEVICE
//**************************************************************************

//-------------------------------------------------
//  tms36xx_device - constructor
//-------------------------------------------------

tms36xx_device::tms36xx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
	: device_t(mconfig, TMS36XX, "TMS36XX", tag, owner, clock, "tms36xx", __FILE__),
		device_sound_interface(mconfig, *this),
		m_subtype(nullptr),
		m_channel(nullptr),
		m_samplerate(0),
		m_basefreq(0),
		m_octave(0),
		m_speed(0),
		m_tune_counter(0),
		m_note_counter(0),
		m_voices(0),
		m_shift(0),
		m_output(0),
		m_enable(0),
		m_tune_num(0),
		m_tune_ofs(0),
		m_tune_max(0)
{
	memset(m_vol, 0, sizeof(int)*12);
	memset(m_vol_counter, 0, sizeof(int)*12);
	memset(m_decay, 0, sizeof(int)*12);
	memset(m_counter, 0, sizeof(int)*12);
	memset(m_frequency, 0, sizeof(int)*12);
}


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

void tms36xx_device::device_start()
{
	int enable = 0;

	m_channel = stream_alloc(0, 1, clock() * 64);
	m_samplerate = clock() * 64;
	m_basefreq = clock();

	for (int j = 0; j < 6; j++)
	{
		if (m_decay_time[j] > 0)
		{
			m_decay[j+0] = m_decay[j+6] = TMS36XX_VMAX / m_decay_time[j];
			enable |= 0x41 << j;
		}
	}
	tms3617_enable(enable);

	LOG(("TMS36xx samplerate    %d\n", m_samplerate));
	LOG(("TMS36xx basefreq      %d\n", m_basefreq));
	LOG(("TMS36xx decay         %d,%d,%d,%d,%d,%d\n",
		m_decay[0], m_decay[1], m_decay[2],
		m_decay[3], m_decay[4], m_decay[5]));
	LOG(("TMS36xx speed         %d\n", m_speed));

	save_item(NAME(m_octave));
	save_item(NAME(m_tune_counter));
	save_item(NAME(m_note_counter));
	save_item(NAME(m_voices));
	save_item(NAME(m_shift));
	save_item(NAME(m_vol));
	save_item(NAME(m_vol_counter));
	save_item(NAME(m_counter));
	save_item(NAME(m_frequency));
	save_item(NAME(m_output));
	save_item(NAME(m_enable));
	save_item(NAME(m_tune_num));
	save_item(NAME(m_tune_ofs));
	save_item(NAME(m_tune_max));
}


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

void tms36xx_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{
	int samplerate = m_samplerate;
	stream_sample_t *buffer = outputs[0];

	/* no tune played? */
	if( !tunes[m_tune_num] || m_voices == 0 )
	{
		while (--samples >= 0)
			buffer[samples] = 0;
		return;
	}

	while( samples-- > 0 )
	{
		int sum = 0;

		/* decay the twelve voices */
		DECAY( 0) DECAY( 1) DECAY( 2) DECAY( 3) DECAY( 4) DECAY( 5)
		DECAY( 6) DECAY( 7) DECAY( 8) DECAY( 9) DECAY(10) DECAY(11)

		/* musical note timing */
		m_tune_counter -= m_speed;
		if( m_tune_counter <= 0 )
		{
			int n = (-m_tune_counter / samplerate) + 1;
			m_tune_counter += n * samplerate;

			if( (m_note_counter -= n) <= 0 )
			{
				m_note_counter += TMS36XX_VMAX;
				if (m_tune_ofs < m_tune_max)
				{
					/* shift to the other 'bank' of voices */
					m_shift ^= 6;
					/* restart one 'bank' of voices */
					RESTART(0) RESTART(1) RESTART(2)
					RESTART(3) RESTART(4) RESTART(5)
					m_tune_ofs++;
				}
			}
		}

		/* update the twelve voices */
		TONE( 0) TONE( 1) TONE( 2) TONE( 3) TONE( 4) TONE( 5)
		TONE( 6) TONE( 7) TONE( 8) TONE( 9) TONE(10) TONE(11)

		*buffer++ = sum / m_voices;
	}
}


//-------------------------------------------------
//  MM6221AA interface functions
//-------------------------------------------------

void tms36xx_device::mm6221aa_tune_w(int tune)
{
	/* which tune? */
	tune &= 3;
	if( tune == m_tune_num )
		return;

	LOG(("%s tune:%X\n", m_subtype, tune));

	/* update the stream before changing the tune */
	m_channel->update();

	m_tune_num = tune;
	m_tune_ofs = 0;
	m_tune_max = 96; /* fixed for now */
}


//-------------------------------------------------
//  TMS3615/17 interface functions
//-------------------------------------------------

void tms36xx_device::tms36xx_note_w(int octave, int note)
{
	octave &= 3;
	note &= 15;

	if (note > 12)
		return;

	LOG(("%s octave:%X note:%X\n", m_subtype, octave, note));

	/* update the stream before changing the tune */
	m_channel->update();

	/* play a single note from 'tune 4', a list of the 13 tones */
	tms36xx_reset_counters();
	m_octave = octave;
	m_tune_num = 4;
	m_tune_ofs = note;
	m_tune_max = note + 1;
}


//-------------------------------------------------
//  TMS3617 interface functions
//-------------------------------------------------

void tms36xx_device::tms3617_enable_w(int enable)
{
	tms3617_enable(enable);
}


//-------------------------------------------------
//  Locals
//-------------------------------------------------

void tms36xx_device::tms36xx_reset_counters()
{
	m_tune_counter = 0;
	m_note_counter = 0;
	memset(m_vol_counter, 0, sizeof(m_vol_counter));
	memset(m_counter, 0, sizeof(m_counter));
}


void tms36xx_device::tms3617_enable(int enable)
{
	int i, bits = 0;

	/* duplicate the 6 voice enable bits */
	enable = (enable & 0x3f) | ((enable & 0x3f) << 6);
	if (enable == m_enable)
		return;

	/* update the stream before changing the tune */
	m_channel->update();

	LOG(("%s enable voices", m_subtype));
	for (i = 0; i < 6; i++)
	{
		if (enable & (1 << i))
		{
			bits += 2;  /* each voice has two instances */

			switch (i)
			{
			case 0: LOG((" 16'")); break;
			case 1: LOG((" 8'")); break;
			case 2: LOG((" 5 1/3'")); break;
			case 3: LOG((" 4'")); break;
			case 4: LOG((" 2 2/3'")); break;
			case 5: LOG((" 2'")); break;
			}
		}
	}
	/* set the enable mask and number of active voices */
	m_enable = enable;
	m_voices = bits;
	LOG(("%s\n", bits ? "" : " none"));
}