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

    samples.h

    Sound device for sample playback.

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

#ifndef MAME_SOUND_SAMPLES_H
#define MAME_SOUND_SAMPLES_H

#pragma once


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

// device type definition
DECLARE_DEVICE_TYPE(SAMPLES, samples_device)

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

#define SAMPLES_START_CB_MEMBER(_name) void _name()

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

class samples_device :  public device_t,
						public device_sound_interface
{
public:
	typedef device_delegate<void ()> start_cb_delegate;

	// construction/destruction
	samples_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);

	// configuration helpers
	void set_channels(uint8_t channels) { m_channels = channels; }
	void set_samples_names(const char *const *names) { m_names = names; }

	// start callback helpers
	template <typename... T> void set_samples_start_callback(T &&...args) { m_samples_start_cb.set(std::forward<T>(args)...); }

	// getters
	bool playing(uint8_t channel) const;
	uint32_t base_frequency(uint8_t channel) const;

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

	// dynamic control
	void set_frequency(uint8_t channel, uint32_t frequency);
	void set_volume(uint8_t 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_t          frequency;      // frequency of the sample
		std::vector<int16_t> data;      // 16-bit signed data
	};
	static bool read_sample(emu_file &file, sample_t &sample);

	// interface
	uint8_t       m_channels;         // number of discrete audio channels needed
	const char *const *m_names;     // array of sample names

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

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

	// device_sound_interface overrides
	virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;

	// internal classes
	struct channel_t
	{
		sound_stream *  stream;
		const int16_t * source;
		int32_t         source_num;
		uint32_t        source_len;
		double          pos;
		uint32_t        basefreq;
		uint32_t        curfreq;
		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);
	bool load_samples();

	start_cb_delegate m_samples_start_cb; // optional callback

	// internal state
	std::vector<channel_t>    m_channel;
	std::vector<sample_t>     m_sample;

	// internal constants
	static constexpr uint8_t FRAC_BITS = 24;
	static constexpr uint32_t FRAC_ONE = 1 << FRAC_BITS;
	static constexpr uint32_t FRAC_MASK = FRAC_ONE - 1;
};

// iterator, since lots of people are interested in these devices
typedef device_type_iterator<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 && m_samples.m_names[0] && m_samples.m_names[0][0] == '*') ? &m_samples.m_names[0][1] : nullptr; }

	// iteration
	const char *first()
	{
		if (!m_samples.m_names || !m_samples.m_names[0])
			return nullptr;
		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])
			return nullptr;
		return m_samples.m_names[m_current++];
	}

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

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

#endif // MAME_SOUND_SAMPLES_H