summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/sound/samples.h
blob: cb436329a0e546c8f0b48549644dd62f71191ee3 (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
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************

    samples.h

    Sound device for sample playback.

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

#pragma once

#ifndef __SAMPLES_H__
#define __SAMPLES_H__


//**************************************************************************
//  INTERFACE CONFIGURATION MACROS
//**************************************************************************

#define MCFG_SAMPLES_CHANNELS(_channels) \
	samples_device::static_set_channels(*device, _channels);

#define MCFG_SAMPLES_NAMES(_names) \
	samples_device::static_set_samples_names(*device, _names);

typedef device_delegate<void ()> samples_start_cb_delegate;

#define SAMPLES_START_CB_MEMBER(_name) void _name()

#define MCFG_SAMPLES_START_CB(_class, _method) \
	samples_device::set_samples_start_callback(*device, samples_start_cb_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner)));

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

// ======================> samples_device

class samples_device :  public device_t,
						public device_sound_interface
{
public:
	// construction/destruction
	samples_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);

	// static configuration helpers
	static void static_set_channels(device_t &device, UINT8 channels) { downcast<samples_device &>(device).m_channels = channels; }
	static void static_set_samples_names(device_t &device, const char *const *names) { downcast<samples_device &>(device).m_names = names; }
	static void set_samples_start_callback(device_t &device, samples_start_cb_delegate callback) { downcast<samples_device &>(device).m_samples_start_cb = callback; }

	// getters
	bool playing(UINT8 channel) const;
	UINT32 base_frequency(UINT8 channel) const;

	// start/stop helpers
	void start(UINT8 channel, UINT32 samplenum, bool loop = false);
	void start_raw(UINT8 channel, const INT16 *sampledata, UINT32 samples, UINT32 frequency, bool loop = false);
	void pause(UINT8 channel, bool pause = true);
	void stop(UINT8 channel);
	void stop_all();

	// dynamic control
	void set_frequency(UINT8 channel, UINT32 frequency);
	void set_volume(UINT8 channel, float volume);

	// helpers
	struct sample_t
	{
		// shouldn't need a copy, but in case it happens, catch it here
		sample_t &operator=(const sample_t &rhs) { assert(false); return *this; }

		UINT32          frequency;      // frequency of the sample
		dynamic_array<INT16> data;      // 16-bit signed data
	};
	static bool read_sample(emu_file &file, sample_t &sample);

	// interface
	UINT8       m_channels;         // number of discrete audio channels needed
	const char *const *m_names;     // array of sample names
	samples_start_cb_delegate m_samples_start_cb; // optional callback

protected:
	// subclasses can do it this way
	samples_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);

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

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

private:
	// internal classes
	struct channel_t
	{
		sound_stream *  stream;
		const INT16 *   source;
		INT32           source_length;
		INT32           source_num;
		UINT32          pos;
		UINT32          frac;
		UINT32          step;
		UINT32          basefreq;
		bool            loop;
		bool            paused;
	};

	// internal helpers
	static bool read_wav_sample(emu_file &file, sample_t &sample);
	static bool read_flac_sample(emu_file &file, sample_t &sample);
	void load_samples();

	// internal state
	dynamic_array<channel_t>    m_channel;
	dynamic_array<sample_t>     m_sample;

	// internal constants
	static const UINT8 FRAC_BITS = 24;
	static const UINT32 FRAC_ONE = 1 << FRAC_BITS;
	static const UINT32 FRAC_MASK = FRAC_ONE - 1;
};

// iterator, since lots of people are interested in these devices
typedef device_type_iterator<&device_creator<samples_device>, samples_device> samples_device_iterator;


// ======================> samples_iterator

class samples_iterator
{
public:
	// construction/destruction
	samples_iterator(samples_device &device)
		: m_samples(device),
			m_current(-1) { }

	// getters
	const char *altbasename() const { return (m_samples.m_names != NULL && m_samples.m_names[0] != NULL && m_samples.m_names[0][0] == '*') ? &m_samples.m_names[0][1] : NULL; }

	// iteration
	const char *first()
	{
		if (m_samples.m_names == NULL || m_samples.m_names[0] == NULL)
			return NULL;
		m_current = 0;
		if (m_samples.m_names[0][0] == '*')
			m_current++;
		return m_samples.m_names[m_current++];
	}

	const char *next()
	{
		if (m_current == -1 || m_samples.m_names[m_current] == NULL)
			return NULL;
		return m_samples.m_names[m_current++];
	}

	// counting
	int count()
	{
		int save = m_current;
		int result = 0;
		for (const char *scan = first(); scan != NULL; scan = next())
			result++;
		m_current = save;
		return result;
	}

private:
	// internal state
	samples_device &m_samples;
	int                     m_current;
};



//**************************************************************************
//  GLOBAL VARIABLES
//**************************************************************************

// device type definition
extern const device_type SAMPLES;


#endif