summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/okim9810.h
blob: dfb4cd047aa47beb6a394a26465e23dc9ef275a5 (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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// license:BSD-3-Clause
// copyright-holders:Andrew Gardner
/***************************************************************************

    okim9810.h

    OKI MSM9810 ADPCM(2) sound chip.

    Notes:
    The master clock frequency for this chip can range from 3.5MHz to 4.5Mhz.
      The typical oscillator is a 4.096Mhz crystal.

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

#ifndef MAME_SOUND_OKIM9810_H
#define MAME_SOUND_OKIM9810_H

#pragma once

#include "dirom.h"
#include "okiadpcm.h"


//**************************************************************************
//  TYPE DEFINITIONS
//**************************************************************************


// ======================> okim9810_device

class okim9810_device : public device_t,
						public device_sound_interface,
						public device_rom_interface<24>
{
public:
	// construction/destruction
	okim9810_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

	uint8_t read_status();
	void write_tmp_register(uint8_t command);
	void write_command(uint8_t command);

	uint8_t read();
	void write(uint8_t data);
	void tmp_register_w(uint8_t data);

	// serial read/write handlers
	void serial_w(int state);
	void si_w(int state);
	void sd_w(int state);
	void ud_w(int state);
	void cmd_w(int state);
	int so_r();
	int sr0_r();
	int sr1_r();
	int sr2_r();
	int sr3_r();

protected:
	enum
	{
		ADPCM_PLAYBACK = 0,
		ADPCM2_PLAYBACK = 1,
		NONLINEAR8_PLAYBACK = 2,
		STRAIGHT8_PLAYBACK = 3,
		EIGHTBIT_PLAYBACK = 2
	};

	enum
	{
		SECONDARY_FILTER = 0,
		PRIMARY_FILTER = 1,
		NO_FILTER = 2,
		NO_FILTER2 = 3
	};

	enum
	{
		OUTPUT_TO_DIRECT_DAC = 0,
		OUTPUT_TO_VOLTAGE_FOLLOWER = 1
	};

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

	// device_sound_interface overrides
	virtual void sound_stream_update_legacy(sound_stream &stream, stream_sample_t const * const *inputs, stream_sample_t * const *outputs, int samples) override;

	// device_rom_interface overrides
	virtual void rom_bank_updated() override;

	// a single voice
	class okim_voice
	{
	public:
		okim_voice();
		void generate_audio(device_rom_interface &rom,
							stream_sample_t * const *buffers,
							int samples,
							const uint8_t global_volume,
							const uint8_t filter_type);

		// computes volume scale from 3 volume numbers
		uint8_t volume_scale(const uint8_t global_volume,
							const uint8_t channel_volume,
							const uint8_t pan_volume) const;

		oki_adpcm_state m_adpcm;    // current ADPCM state
		oki_adpcm2_state m_adpcm2;  // current ADPCM2 state
		uint8_t   m_playbackAlgo;     // current playback method
		bool    m_looping;
		uint8_t   m_startFlags;
		uint8_t   m_endFlags;
		offs_t  m_base_offset;      // pointer to the base memory location
		uint32_t  m_count;            // total samples to play
		uint32_t  m_samplingFreq;     // voice sampling frequency

		bool    m_playing;          // playback state
		uint32_t  m_sample;           // current sample number

		uint8_t   m_channel_volume;   // volume index set with the CVOL command
		uint8_t   m_pan_volume_left;  // volume index set with the PAN command
		uint8_t   m_pan_volume_right; // volume index set with the PAN command

		int32_t   m_startSample;      // interpolation state - sample to interpolate from
		int32_t   m_endSample;        // interpolation state - sample to interpolate to
		uint32_t  m_interpSampleNum;  // interpolation state - fraction between start & end

		static const uint8_t s_volume_table[16];
	};

	// internal state

	sound_stream* m_stream;

	uint8_t m_TMP_register;

	uint8_t m_global_volume;      // volume index set with the OPT command
	uint8_t m_filter_type;        // interpolation filter type set with the OPT command
	uint8_t m_output_level;       // flag stating if a voltage follower is connected

	int       m_dadr;
	offs_t    m_dadr_start_offset;
	offs_t    m_dadr_end_offset;
	uint8_t   m_dadr_flags;

	int       m_serial;
	int       m_serial_read_latch;
	int       m_serial_write_latch;
	int       m_serial_bits;
	int       m_ud;
	int       m_si;
	int       m_sd;
	int       m_cmd;

	static constexpr int OKIM9810_VOICES = 8;
	okim_voice m_voice[OKIM9810_VOICES];

	static const uint32_t s_sampling_freq_div_table[16];
};


// device type definition
DECLARE_DEVICE_TYPE(OKIM9810, okim9810_device)

#endif // MAME_SOUND_OKIM9810_H