summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/audio/mea8000.h
blob: 5d09ee938c9644ce7a6d5e16d7a88b43d9c6b948 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// license:BSD-3-Clause
// copyright-holders:Antoine Mine
/**********************************************************************

  Copyright (C) Antoine Mine' 2006

  Philips MEA 8000 emulation.

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

#ifndef __MEA8000_H__
#define __MEA8000_H__

#include "sound/dac.h"

#define MCFG_MEA8000_DAC(_tag) \
	mea8000_device::static_set_dac_tag(*device, "^" _tag);

#define MCFG_MEA8000_REQ_CALLBACK(_write) \
	devcb = &mea8000_device::set_reqwr_callback(*device, DEVCB_##_write);

/* table amplitude [-QUANT,QUANT] */
#define QUANT 512

/* filter coefficients from frequencies */
#define TABLE_LEN 3600

/* noise generator table */
#define NOISE_LEN 8192


/* finite machine state controling frames */
enum mea8000_state
{
	MEA8000_STOPPED,    /* nothing to do, timer disabled */
	MEA8000_WAIT_FIRST, /* received pitch, wait for first full trame, timer disabled */
	MEA8000_STARTED,    /* playing a frame, timer on */
	MEA8000_SLOWING     /* repeating last frame with decreasing amplitude, timer on */
};

ALLOW_SAVE_TYPE( mea8000_state );


struct filter_t
{
#ifdef FLOAT_MODE
	double fm, last_fm;         /* frequency, in Hz */
	double bw, last_bw;         /* band-width, in Hz */
	double output, last_output; /* filter state */
#else
	UINT16 fm, last_fm;
	UINT16 bw, last_bw;
	INT32  output, last_output;
#endif
};

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

	static void static_set_dac_tag(device_t &device, const char *tag) { downcast<mea8000_device &>(device).m_dac.set_tag(tag); }
	template<class _Object> static devcb_base &set_req_wr_callback(device_t &device, _Object object) { return downcast<mea8000_device &>(device).m_write_req.set_callback(object); }

	DECLARE_READ8_MEMBER(read);
	DECLARE_WRITE8_MEMBER(write);

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

private:
	// internal state

	int accept_byte();
	void update_req();
	void init_tables();
#ifndef FLOAT_MODE /* UINT16 version */
	int interp(UINT16 org, UINT16 dst);
	int filter_step(int i, int input);
	int noise_gen();
	int freq_gen();
	int compute_sample();
#else /* float version */
	double interp(double org, double dst);
	double filter_step(int i, double input);
	double noise_gen();
	double freq_gen();
	double compute_sample();
#endif

	void shift_frame();
	void decode_frame();
	void start_frame();
	void stop_frame();

	TIMER_CALLBACK_MEMBER(timer_expire);

	devcb_write8 m_write_req;

	required_device<dac_device> m_dac;

	/* state */
	mea8000_state m_state; /* current state */

	UINT8 m_buf[4]; /* store 4 consecutive data to form a frame info */
	UINT8 m_bufpos; /* new byte to write in frame info buffer */

	UINT8 m_cont; /* if no data 0=stop 1=repeat last frame */
	UINT8 m_roe;  /* enable req output, now unimplemented */

	UINT16 m_framelength;  /* in samples */
	UINT16 m_framepos;     /* in samples */
	UINT16 m_framelog;     /* log2 of framelength */

	INT16 m_lastsample, m_sample; /* output samples are interpolated */

	UINT32 m_phi; /* absolute phase for frequency / noise generator */

	filter_t m_f[4]; /* filters */

	UINT16 m_last_ampl, m_ampl;    /* amplitude * 1000 */
	UINT16 m_last_pitch, m_pitch;  /* pitch of sawtooth signal, in Hz */
	UINT8  m_noise;

	emu_timer *m_timer;

	int m_cos_table[TABLE_LEN];  /* fm => cos coefficient */
	int m_exp_table[TABLE_LEN];  /* bw => exp coefficient */
	int m_exp2_table[TABLE_LEN]; /* bw => 2*exp coefficient */
	int m_noise_table[NOISE_LEN];

};

extern const device_type MEA8000;


#endif