summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/sound/es5506.h
blob: 3136e869ac7ba22e5219488361b432ff246bbb60 (plain) (tree)
1
2
3
4
5
6
7
8
9

                                






                                                                                                

                           
 
            
 
                          
 
                                                                    

       




                                                                      
 

                                                             
                                                                              
 
          





                                   
                                
                                     

                                
                                       
 





                                                   




















                                                                              

                                 

                                                                       

          
                                                                                                                    
 
                                 
                                             
                                                     

                                             

                                        
                                                                                                                                          
 

                                         

                                                                                                   
 



                                                              

                                                                                                                                         
 
                                                                                                                     







                                                                                                                                                        

                                                                     

                                                                                      




                                                                                                     
 
                         
                                                                             


                                                                                     

                                          
 
                                     
                                         
 



                                                                           
 
                                                                  
 
                                            
 

                                                  
 
                    
                                                                
      
 




                                                                                                    

                                                                   
                                                                                                       

  
 
                                          

       
                                                                                                  
                           
 

                                     



                                               
                                             
                                             
 


                                                 
 


                                                                                            
 
                                                                           

                                                                                            
                                                                                       
 
        












                                                                                     

  
                                          
 
 
                                          

       
                                                                                                  
 

                                      

                                               

                                 
                                             
 


                                                 



                                                                                             
 
                                                                           

                                                                                            
                                                                                       
 

                         





                                                                                               

  
                                          
 
 
                             
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/**********************************************************************************************
 *
 *   Ensoniq ES5505/6 driver
 *   by Aaron Giles
 *
 **********************************************************************************************/

#ifndef MAME_SOUND_ES5506_H
#define MAME_SOUND_ES5506_H

#pragma once

#define ES5506_MAKE_WAVS 0

class es550x_device : public device_t, public device_sound_interface
{
public:
	void set_region0(const char *region0) { m_region0 = region0; }
	void set_region1(const char *region1) { m_region1 = region1; }
	void set_region2(const char *region2) { m_region2 = region2; }
	void set_region3(const char *region3) { m_region3 = region3; }
	void set_channels(int channels) { m_channels = channels; }

	auto irq_cb() { return m_irq_cb.bind(); }
	auto read_port_cb() { return m_read_port_cb.bind(); }
	auto sample_rate_changed() { return m_sample_rate_changed_cb.bind(); }

protected:
	enum {
		LP3 = 1,
		LP4 = 2,
		LP_MASK = LP3 | LP4
	};

	// constants for volumes
	const s8 VOLUME_ACC_BIT = 20;

	// constants for address
	const s8 ADDRESS_FRAC_BIT = 11;

	// struct describing a single playing voice
	struct es550x_voice
	{
		es550x_voice() { }

		// external state
		u32      control   = 0;          // control register
		u64      freqcount = 0;          // frequency count register
		u64      start     = 0;          // start register
		u32      lvol      = 0;          // left volume register
		u64      end       = 0;          // end register
		u32      lvramp    = 0;          // left volume ramp register
		u64      accum     = 0;          // accumulator register
		u32      rvol      = 0;          // right volume register
		u32      rvramp    = 0;          // right volume ramp register
		u32      ecount    = 0;          // envelope count register
		u32      k2        = 0;          // k2 register
		u32      k2ramp    = 0;          // k2 ramp register
		u32      k1        = 0;          // k1 register
		u32      k1ramp    = 0;          // k1 ramp register
		s32      o4n1      = 0;          // filter storage O4(n-1)
		s32      o3n1      = 0;          // filter storage O3(n-1)
		s32      o3n2      = 0;          // filter storage O3(n-2)
		s32      o2n1      = 0;          // filter storage O2(n-1)
		s32      o2n2      = 0;          // filter storage O2(n-2)
		s32      o1n1      = 0;          // filter storage O1(n-1)
		u64      exbank    = 0;          // external address bank

		// internal state
		u8       index      = 0;         // index of this voice
		u8       filtcount  = 0;         // filter count
	};

	es550x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);

	// device-level overrides
	virtual void device_start() override;
	virtual void device_clock_changed() override;
	virtual void device_stop() override;
	virtual void device_reset() override;

	// sound stream update overrides
	virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;

	void update_irq_state();
	void update_internal_irq_state();
	void compute_tables(u32 total_volume_bit = 16, u32 exponent_bit = 4, u32 mantissa_bit = 8);
	void get_accum_mask(u32 address_integer = 21, u32 address_frac = 11);

	virtual inline u32 get_bank(u32 control) { return 0; }
	virtual inline u32 get_ca(u32 control) { return 0; }
	virtual inline u32 get_lp(u32 control) { return 0; }

	template<typename T, typename U> inline T lshift_signed(T val, U shift) { return (shift >= 0) ? val << shift : val >> (-shift); }
	template<typename T, typename U> inline T rshift_signed(T val, U shift) { return (shift >= 0) ? val >> shift : val << (-shift); }

	inline u64 get_volume(u32 volume) { return m_volume_lookup[rshift_signed<u32, s8>(volume, m_volume_shift)]; }

	inline u64 get_address_acc_shifted_val(u64 val, int bias = 0) { return lshift_signed<u64, s8>(val, m_address_acc_shift - bias); }
	inline u64 get_address_acc_res(u64 val, int bias = 0) { return rshift_signed<u64, s8>(val, m_address_acc_shift - bias); }
	inline u64 get_integer_addr(u64 accum, s32 bias = 0) { return ((accum + (bias << ADDRESS_FRAC_BIT)) & m_address_acc_mask) >> ADDRESS_FRAC_BIT; }

	inline s64 get_sample(s32 sample, u32 volume) { return rshift_signed<s64, s8>(sample * get_volume(volume), m_volume_acc_shift); }

	inline s32 interpolate(s32 sample1, s32 sample2, u64 accum);
	inline void apply_filters(es550x_voice *voice, s32 &sample);
	virtual inline void update_envelopes(es550x_voice *voice) {};
	virtual inline void check_for_end_forward(es550x_voice *voice, u64 &accum) {};
	virtual inline void check_for_end_reverse(es550x_voice *voice, u64 &accum) {};
	void generate_dummy(es550x_voice *voice, u16 *base, s32 *lbuffer, s32 *rbuffer, int samples);
	void generate_ulaw(es550x_voice *voice, u16 *base, s32 *lbuffer, s32 *rbuffer, int samples);
	void generate_pcm(es550x_voice *voice, u16 *base, s32 *lbuffer, s32 *rbuffer, int samples);
	inline void generate_irq(es550x_voice *voice, int v);
	virtual void generate_samples(s32 **outputs, int offset, int samples) {};

	// internal state
	sound_stream *m_stream;               /* which stream are we using */
	int           m_sample_rate;          /* current sample rate */
	u16 *         m_region_base[4];       /* pointer to the base of the region */
	u32           m_master_clock;         /* master clock frequency */
	s8            m_address_acc_shift;
	u64           m_address_acc_mask;

	s8            m_volume_shift;
	s64           m_volume_acc_shift;

	u8            m_current_page;         /* current register page */
	u8            m_active_voices;        /* number of active voices */
	u16           m_mode;                 /* MODE register */
	u8            m_irqv;                 /* IRQV register */

	es550x_voice  m_voice[32];             /* the 32 voices */

	std::unique_ptr<s32[]>    m_scratch;

	std::unique_ptr<s16[]>    m_ulaw_lookup;
	std::unique_ptr<u32[]>    m_volume_lookup;

#if ES5506_MAKE_WAVS
	void *      m_wavraw;                 /* raw waveform */
#endif

	const char * m_region0;                       /* memory region where the sample ROM lives */
	const char * m_region1;                       /* memory region where the sample ROM lives */
	const char * m_region2;                       /* memory region where the sample ROM lives */
	const char * m_region3;                       /* memory region where the sample ROM lives */
	int m_channels;                               /* number of output channels: 1 .. 6 */
	devcb_write_line m_irq_cb;  /* irq callback */
	devcb_read16 m_read_port_cb;          /* input port read */
	devcb_write32 m_sample_rate_changed_cb;          /* callback for when sample rate is changed */
};


class es5506_device : public es550x_device
{
public:
	es5506_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
	~es5506_device() {}

	DECLARE_READ8_MEMBER(read);
	DECLARE_WRITE8_MEMBER(write);
	void voice_bank_w(int voice, int bank);

protected:
	// device-level overrides
	virtual void device_start() override;
	virtual void device_reset() override;

	const s8 VOLUME_BIT_ES5506 = 16;
	const s8 ADDRESS_INTEGER_BIT_ES5506 = 21;
	const s8 ADDRESS_FRAC_BIT_ES5506 = 11;

	virtual inline u32 get_bank(u32 control) override { return (control >> 14) & 3; }
	virtual inline u32 get_ca(u32 control) override { return (control >> 10) & 7; }
	virtual inline u32 get_lp(u32 control) override { return (control >> 8) & LP_MASK; }

	virtual inline void update_envelopes(es550x_voice *voice) override;
	virtual inline void check_for_end_forward(es550x_voice *voice, u64 &accum) override;
	virtual inline void check_for_end_reverse(es550x_voice *voice, u64 &accum) override;
	virtual void generate_samples(s32 **outputs, int offset, int samples) override;

private:
	inline void reg_write_low(es550x_voice *voice, offs_t offset, u32 data);
	inline void reg_write_high(es550x_voice *voice, offs_t offset, u32 data);
	inline void reg_write_test(es550x_voice *voice, offs_t offset, u32 data);
	inline u32 reg_read_low(es550x_voice *voice, offs_t offset);
	inline u32 reg_read_high(es550x_voice *voice, offs_t offset);
	inline u32 reg_read_test(es550x_voice *voice, offs_t offset);

	// ES5506 specific registers
	u32      m_write_latch;            /* currently accumulated data for write */
	u32      m_read_latch;             /* currently accumulated data for read */
	u8       m_wst;                    /* W_ST register */
	u8       m_wend;                   /* W_END register */
	u8       m_lrend;                  /* LR_END register */
};

DECLARE_DEVICE_TYPE(ES5506, es5506_device)


class es5505_device : public es550x_device
{
public:
	es5505_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);

	DECLARE_READ16_MEMBER(read);
	DECLARE_WRITE16_MEMBER(write);
	void voice_bank_w(int voice, int bank);

protected:
	// device-level overrides
	virtual void device_start() override;

	const s8 VOLUME_BIT_ES5505 = 8;
	const s8 ADDRESS_INTEGER_BIT_ES5505 = 20;
	const s8 ADDRESS_FRAC_BIT_ES5505 = 9;

	virtual inline u32 get_lp(u32 control) override { return (control >> 10) & LP_MASK; }
	virtual inline u32 get_ca(u32 control) override { return (control >> 8) & 3; }
	virtual inline u32 get_bank(u32 control) override { return (control >> 2) & 1; }

	virtual inline void update_envelopes(es550x_voice *voice) override;
	virtual inline void check_for_end_forward(es550x_voice *voice, u64 &accum) override;
	virtual inline void check_for_end_reverse(es550x_voice *voice, u64 &accum) override;
	virtual void generate_samples(s32 **outputs, int offset, int samples) override;

private:
	// internal state
	inline void reg_write_low(es550x_voice *voice, offs_t offset, u16 data, u16 mem_mask);
	inline void reg_write_high(es550x_voice *voice, offs_t offset, u16 data, u16 mem_mask);
	inline void reg_write_test(es550x_voice *voice, offs_t offset, u16 data, u16 mem_mask);
	inline u16 reg_read_low(es550x_voice *voice, offs_t offset);
	inline u16 reg_read_high(es550x_voice *voice, offs_t offset);
	inline u16 reg_read_test(es550x_voice *voice, offs_t offset);
};

DECLARE_DEVICE_TYPE(ES5505, es5505_device)


#endif // MAME_SOUND_ES5506_H