summaryrefslogtreecommitdiff
path: root/gme/Multi_Buffer.h
blob: a39cca1a597ae9d75692e90786b3ea8762d77ead (plain)
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
// Multi-channel sound buffer interface, and basic mono and stereo buffers

// Blip_Buffer 0.4.1
#ifndef MULTI_BUFFER_H
#define MULTI_BUFFER_H

#include "blargg_common.h"
#include "Blip_Buffer.h"

// Interface to one or more Blip_Buffers mapped to one or more channels
// consisting of left, center, and right buffers.
class Multi_Buffer {
public:
	Multi_Buffer( int samples_per_frame );
	virtual ~Multi_Buffer() { }
	
	// Set the number of channels available
	virtual blargg_err_t set_channel_count( int );
	
	// Get indexed channel, from 0 to channel count - 1
	struct channel_t {
		Blip_Buffer* center;
		Blip_Buffer* left;
		Blip_Buffer* right;
	};
	enum { type_index_mask = 0xFF };
	enum { wave_type = 0x100, noise_type = 0x200, mixed_type = wave_type | noise_type };
	virtual channel_t channel( int index, int type ) = 0;
	
	// See Blip_Buffer.h
	virtual blargg_err_t set_sample_rate( long rate, int msec = blip_default_length ) = 0;
	virtual void clock_rate( long ) = 0;
	virtual void bass_freq( int ) = 0;
	virtual void clear() = 0;
	long sample_rate() const;
	
	// Length of buffer, in milliseconds
	int length() const;
	
	// See Blip_Buffer.h
	virtual void end_frame( blip_time_t ) = 0;
	
	// Number of samples per output frame (1 = mono, 2 = stereo)
	int samples_per_frame() const;
	
	// Count of changes to channel configuration. Incremented whenever
	// a change is made to any of the Blip_Buffers for any channel.
	unsigned channels_changed_count() { return channels_changed_count_; }
	
	// See Blip_Buffer.h
	virtual long read_samples( blip_sample_t*, long ) = 0;
	virtual long samples_avail() const = 0;
	
public:
	BLARGG_DISABLE_NOTHROW
protected:
	void channels_changed() { channels_changed_count_++; }
private:
	// noncopyable
	Multi_Buffer( const Multi_Buffer& );
	Multi_Buffer& operator = ( const Multi_Buffer& );
	
	unsigned channels_changed_count_;
	long sample_rate_;
	int length_;
	int const samples_per_frame_;
};

// Uses a single buffer and outputs mono samples.
class Mono_Buffer : public Multi_Buffer {
	Blip_Buffer buf;
	channel_t chan;
public:
	// Buffer used for all channels
	Blip_Buffer* center() { return &buf; }
	
public:
	Mono_Buffer();
	~Mono_Buffer();
	blargg_err_t set_sample_rate( long rate, int msec = blip_default_length );
	void clock_rate( long rate ) { buf.clock_rate( rate ); }
	void bass_freq( int freq ) { buf.bass_freq( freq ); }
	void clear() { buf.clear(); }
	long samples_avail() const { return buf.samples_avail(); }
	long read_samples( blip_sample_t* p, long s ) { return buf.read_samples( p, s ); }
	channel_t channel( int, int ) { return chan; }
	void end_frame( blip_time_t t ) { buf.end_frame( t ); }
};

// Uses three buffers (one for center) and outputs stereo sample pairs.
class Stereo_Buffer : public Multi_Buffer {
public:
	
	// Buffers used for all channels
	Blip_Buffer* center()       { return &bufs [0]; }
	Blip_Buffer* left()         { return &bufs [1]; }
	Blip_Buffer* right()        { return &bufs [2]; }
	
public:
	Stereo_Buffer();
	~Stereo_Buffer();
	blargg_err_t set_sample_rate( long, int msec = blip_default_length );
	void clock_rate( long );
	void bass_freq( int );
	void clear();
	channel_t channel( int, int ) { return chan; }
	void end_frame( blip_time_t );
	
	long samples_avail() const { return bufs [0].samples_avail() * 2; }
	long read_samples( blip_sample_t*, long );
	
private:
	enum { buf_count = 3 };
	Blip_Buffer bufs [buf_count];
	channel_t chan;
	int stereo_added;
	int was_stereo;
	
	void mix_stereo_no_center( blip_sample_t*, blargg_long );
	void mix_stereo( blip_sample_t*, blargg_long );
	void mix_mono( blip_sample_t*, blargg_long );
};

// Silent_Buffer generates no samples, useful where no sound is wanted
class Silent_Buffer : public Multi_Buffer {
	channel_t chan;
public:
	Silent_Buffer();
	blargg_err_t set_sample_rate( long rate, int msec = blip_default_length )
	{
		return Multi_Buffer::set_sample_rate( rate, msec );
	}
	void clock_rate( long ) { }
	void bass_freq( int ) { }
	void clear() { }
	channel_t channel( int, int ) { return chan; }
	void end_frame( blip_time_t ) { }
	long samples_avail() const { return 0; }
	long read_samples( blip_sample_t*, long ) { return 0; }
};


inline blargg_err_t Multi_Buffer::set_sample_rate( long rate, int msec )
{
	sample_rate_ = rate;
	length_ = msec;
	return 0;
}

inline int Multi_Buffer::samples_per_frame() const { return samples_per_frame_; }

inline long Multi_Buffer::sample_rate() const { return sample_rate_; }

inline int Multi_Buffer::length() const { return length_; }

#endif