summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/sound.h
blob: c60ac53a628f823dd3e2497e422400493a2aa759 (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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************

    sound.h

    Core sound interface functions and definitions.

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

#pragma once

#ifndef __EMU_H__
#error Dont include this file directly; include emu.h instead.
#endif

#ifndef __SOUND_H__
#define __SOUND_H__


//**************************************************************************
//  CONSTANTS
//**************************************************************************

const int STREAM_SYNC       = -1;       // special rate value indicating a one-sample-at-a-time stream
										// with actual rate defined by its input

//**************************************************************************
//  MACROS
//**************************************************************************

typedef delegate<void (sound_stream &, stream_sample_t **inputs, stream_sample_t **outputs, int samples)> stream_update_delegate;

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

// forward references
struct wav_file;


// structure describing an indexed mixer
struct mixer_input
{
	device_mixer_interface *mixer;          // owning device interface
	sound_stream *          stream;         // stream within the device
	int                     inputnum;       // input on the stream
};


// ======================> sound_stream

class sound_stream
{
	friend class sound_manager;

	typedef void (*stream_update_func)(device_t *device, sound_stream *stream, void *param, stream_sample_t **inputs, stream_sample_t **outputs, int samples);

	// stream output class
	class stream_output
	{
	public:
		// construction/destruction
		stream_output();
		stream_output &operator=(const stream_output &rhs) { assert(false); return *this; }

		// internal state
		sound_stream *      m_stream;               // owning stream
		std::vector<stream_sample_t> m_buffer;    // output buffer
		int                 m_dependents;           // number of dependents
		INT16               m_gain;                 // gain to apply to the output
	};

	// stream input class
	class stream_input
	{
	public:
		// construction/destruction
		stream_input();
		stream_input &operator=(const stream_input &rhs) { assert(false); return *this; }

		// internal state
		stream_output *     m_source;               // pointer to the sound_output for this source
		std::vector<stream_sample_t> m_resample;  // buffer for resampling to the stream's sample rate
		attoseconds_t       m_latency_attoseconds;  // latency between this stream and the input stream
		INT16               m_gain;                 // gain to apply to this input
		INT16               m_user_gain;            // user-controlled gain to apply to this input
	};

	// constants
	static const int OUTPUT_BUFFER_UPDATES      = 5;
	static const UINT32 FRAC_BITS               = 22;
	static const UINT32 FRAC_ONE                = 1 << FRAC_BITS;
	static const UINT32 FRAC_MASK               = FRAC_ONE - 1;

public:
	// construction/destruction
	sound_stream(device_t &device, int inputs, int outputs, int sample_rate, stream_update_delegate callback);

	// getters
	sound_stream *next() const { return m_next; }
	device_t &device() const { return m_device; }
	int sample_rate() const { return (m_new_sample_rate != 0) ? m_new_sample_rate : m_sample_rate; }
	attotime sample_time() const;
	attotime sample_period() const { return attotime(0, m_attoseconds_per_sample); }
	int input_count() const { return m_input.size(); }
	int output_count() const { return m_output.size(); }
	std::string input_name(int inputnum) const;
	device_t *input_source_device(int inputnum) const;
	int input_source_outputnum(int inputnum) const;
	float user_gain(int inputnum) const;
	float input_gain(int inputnum) const;
	float output_gain(int outputnum) const;

	// operations
	void set_input(int inputnum, sound_stream *input_stream, int outputnum = 0, float gain = 1.0f);
	void update();
	const stream_sample_t *output_since_last_update(int outputnum, int &numsamples);

	// timing
	void set_sample_rate(int sample_rate);
	void set_user_gain(int inputnum, float gain);
	void set_input_gain(int inputnum, float gain);
	void set_output_gain(int outputnum, float gain);

private:
	// helpers called by our friends only
	void update_with_accounting(bool second_tick);
	void apply_sample_rate_changes();

	// internal helpers
	void recompute_sample_rate_data();
	void allocate_resample_buffers();
	void allocate_output_buffers();
	void postload();
	void generate_samples(int samples);
	stream_sample_t *generate_resampled_data(stream_input &input, UINT32 numsamples);
	void sync_update(void *, INT32);

	// linking information
	device_t &          m_device;                     // owning device
	sound_stream *      m_next;                       // next stream in the chain

	// general information
	UINT32              m_sample_rate;                // sample rate of this stream
	UINT32              m_new_sample_rate;            // newly-set sample rate for the stream
	bool                m_synchronous;                // synchronous stream that runs at the rate of its input

	// timing information
	attoseconds_t       m_attoseconds_per_sample;     // number of attoseconds per sample
	INT32               m_max_samples_per_update;     // maximum samples per update
	emu_timer *         m_sync_timer;                 // update timer for synchronous streams

	// input information
	std::vector<stream_input> m_input;              // list of streams we directly depend upon
	std::vector<stream_sample_t *> m_input_array;   // array of inputs for passing to the callback

	// resample buffer information
	UINT32              m_resample_bufalloc;          // allocated size of each resample buffer

	// output information
	std::vector<stream_output> m_output;            // list of streams which directly depend upon us
	std::vector<stream_sample_t *> m_output_array;  // array of outputs for passing to the callback

	// output buffer information
	UINT32              m_output_bufalloc;            // allocated size of each output buffer
	INT32               m_output_sampindex;           // current position within each output buffer
	INT32               m_output_update_sampindex;    // position at time of last global update
	INT32               m_output_base_sampindex;      // sample at base of buffer, relative to the current emulated second

	// callback information
	stream_update_delegate  m_callback;                   // callback function
};


// ======================> sound_manager

class sound_manager
{
	friend class sound_stream;

	// reasons for muting
	static const UINT8 MUTE_REASON_PAUSE = 0x01;
	static const UINT8 MUTE_REASON_UI = 0x02;
	static const UINT8 MUTE_REASON_DEBUGGER = 0x04;
	static const UINT8 MUTE_REASON_SYSTEM = 0x08;

	// stream updates
	static const attotime STREAMS_UPDATE_ATTOTIME;

public:
	static const int STREAMS_UPDATE_FREQUENCY = 50;

	// construction/destruction
	sound_manager(running_machine &machine);
	~sound_manager();

	// getters
	running_machine &machine() const { return m_machine; }
	int attenuation() const { return m_attenuation; }
	const std::vector<std::unique_ptr<sound_stream>> &streams() const { return m_stream_list; }
	attotime last_update() const { return m_last_update; }
	attoseconds_t update_attoseconds() const { return m_update_attoseconds; }

	// stream creation
	sound_stream *stream_alloc(device_t &device, int inputs, int outputs, int sample_rate, stream_update_delegate callback = stream_update_delegate());

	// global controls
	void start_recording();
	void stop_recording();
	void set_attenuation(int attenuation);
	void ui_mute(bool turn_off = true) { mute(turn_off, MUTE_REASON_UI); }
	void debugger_mute(bool turn_off = true) { mute(turn_off, MUTE_REASON_DEBUGGER); }
	void system_mute(bool turn_off = true) { mute(turn_off, MUTE_REASON_SYSTEM); }
	void system_enable(bool turn_on = true) { mute(!turn_on, MUTE_REASON_SYSTEM); }

	// user gain controls
	bool indexed_mixer_input(int index, mixer_input &info) const;

private:
	// internal helpers
	void mute(bool mute, UINT8 reason);
	void reset();
	void pause();
	void resume();
	void config_load(config_type cfg_type, xml_data_node *parentnode);
	void config_save(config_type cfg_type, xml_data_node *parentnode);

	void update(void *ptr = nullptr, INT32 param = 0);

	// internal state
	running_machine &   m_machine;              // reference to our machine
	emu_timer *         m_update_timer;         // timer to drive periodic updates

	UINT32              m_finalmix_leftover;
	std::vector<INT16>       m_finalmix;
	std::vector<INT32>       m_leftmix;
	std::vector<INT32>       m_rightmix;

	UINT8               m_muted;
	int                 m_attenuation;
	int                 m_nosound_mode;

	wav_file *          m_wavfile;

	// streams data
	std::vector<std::unique_ptr<sound_stream>> m_stream_list;    // list of streams
	attoseconds_t       m_update_attoseconds;   // attoseconds between global updates
	attotime            m_last_update;          // last update time
};


#endif  /* __SOUND_H__ */