1
2 /*
3 * REminiscence - Flashback interpreter
4 * Copyright (C) 2005-2019 Gregory Montoir (cyx@users.sourceforge.net)
5 */
6
7 #include "mixer.h"
8 #include "systemstub.h"
9 #include "util.h"
10
Mixer(FileSystem * fs,SystemStub * stub)11 Mixer::Mixer(FileSystem *fs, SystemStub *stub)
12 : _stub(stub), _musicType(MT_NONE), _cpc(this, fs), _mod(this, fs), _ogg(this, fs), _sfx(this) {
13 _musicTrack = -1;
14 _backgroundMusicType = MT_NONE;
15 }
16
init()17 void Mixer::init() {
18 memset(_channels, 0, sizeof(_channels));
19 _premixHook = 0;
20 _stub->startAudio(Mixer::mixCallback, this);
21 }
22
free()23 void Mixer::free() {
24 setPremixHook(0, 0);
25 stopAll();
26 _stub->stopAudio();
27 }
28
setPremixHook(PremixHook premixHook,void * userData)29 void Mixer::setPremixHook(PremixHook premixHook, void *userData) {
30 debug(DBG_SND, "Mixer::setPremixHook()");
31 LockAudioStack las(_stub);
32 _premixHook = premixHook;
33 _premixHookData = userData;
34 }
35
play(const uint8_t * data,uint32_t len,uint16_t freq,uint8_t volume)36 void Mixer::play(const uint8_t *data, uint32_t len, uint16_t freq, uint8_t volume) {
37 debug(DBG_SND, "Mixer::play(%d, %d)", freq, volume);
38 LockAudioStack las(_stub);
39 MixerChannel *ch = 0;
40 for (int i = 0; i < NUM_CHANNELS; ++i) {
41 MixerChannel *cur = &_channels[i];
42 if (cur->active) {
43 if (cur->chunk.data == data) {
44 cur->chunkPos = 0;
45 cur->volume = volume;
46 return;
47 }
48 } else {
49 ch = cur;
50 break;
51 }
52 }
53 if (ch) {
54 ch->active = true;
55 ch->volume = volume;
56 ch->chunk.data = data;
57 ch->chunk.len = len;
58 ch->chunkPos = 0;
59 ch->chunkInc = (freq << FRAC_BITS) / _stub->getOutputSampleRate();
60 }
61 }
62
isPlaying(const uint8_t * data) const63 bool Mixer::isPlaying(const uint8_t *data) const {
64 debug(DBG_SND, "Mixer::isPlaying");
65 LockAudioStack las(_stub);
66 for (int i = 0; i < NUM_CHANNELS; ++i) {
67 const MixerChannel *ch = &_channels[i];
68 if (ch->active && ch->chunk.data == data) {
69 return true;
70 }
71 }
72 return false;
73 }
74
getSampleRate() const75 uint32_t Mixer::getSampleRate() const {
76 return _stub->getOutputSampleRate();
77 }
78
stopAll()79 void Mixer::stopAll() {
80 debug(DBG_SND, "Mixer::stopAll()");
81 LockAudioStack las(_stub);
82 for (uint8_t i = 0; i < NUM_CHANNELS; ++i) {
83 _channels[i].active = false;
84 }
85 }
86
isMusicSfx(int num)87 static bool isMusicSfx(int num) {
88 return (num >= 68 && num <= 75);
89 }
90
playMusic(int num)91 void Mixer::playMusic(int num) {
92 debug(DBG_SND, "Mixer::playMusic(%d)", num);
93 int trackNum = -1;
94 if (num == 1) { // menu screen
95 trackNum = 2;
96 } else if (num > MUSIC_TRACK) {
97 trackNum = num - MUSIC_TRACK;
98 }
99 if (trackNum != -1 && trackNum != _musicTrack) {
100 if (_ogg.playTrack(trackNum)) {
101 _backgroundMusicType = _musicType = MT_OGG;
102 _musicTrack = trackNum;
103 return;
104 }
105 if (_cpc.playTrack(trackNum)) {
106 _backgroundMusicType = _musicType = MT_CPC;
107 _musicTrack = trackNum;
108 return;
109 }
110 }
111 if ((_musicType == MT_OGG || _musicType == MT_CPC) && isMusicSfx(num)) { // do not play level action music with background music
112 return;
113 }
114 if (isMusicSfx(num)) { // level action sequence
115 _sfx.play(num);
116 if (_sfx._playing) {
117 _musicType = MT_SFX;
118 }
119 } else { // cutscene
120 _mod.play(num);
121 if (_mod._playing) {
122 _musicType = MT_MOD;
123 }
124 }
125 }
126
stopMusic()127 void Mixer::stopMusic() {
128 debug(DBG_SND, "Mixer::stopMusic()");
129 switch (_musicType) {
130 case MT_NONE:
131 break;
132 case MT_MOD:
133 _mod.stop();
134 break;
135 case MT_OGG:
136 _ogg.pauseTrack();
137 break;
138 case MT_SFX:
139 _sfx.stop();
140 break;
141 case MT_CPC:
142 _cpc.pauseTrack();
143 break;
144 }
145 _musicType = MT_NONE;
146 if (_musicTrack != -1) {
147 switch (_backgroundMusicType) {
148 case MT_OGG:
149 _ogg.resumeTrack();
150 _musicType = MT_OGG;
151 break;
152 case MT_CPC:
153 _cpc.resumeTrack();
154 _musicType = MT_CPC;
155 break;
156 default:
157 break;
158 }
159 }
160 }
161
162 static const bool kUseNr = false;
163
nr(int16_t * buf,int len)164 static void nr(int16_t *buf, int len) {
165 static int prev = 0;
166 for (int i = 0; i < len; ++i) {
167 const int vnr = buf[i] >> 1;
168 buf[i] = vnr + prev;
169 prev = vnr;
170 }
171 }
172
mix(int16_t * out,int len)173 void Mixer::mix(int16_t *out, int len) {
174 if (_premixHook) {
175 if (!_premixHook(_premixHookData, out, len)) {
176 _premixHook = 0;
177 _premixHookData = 0;
178 }
179 }
180 for (uint8_t i = 0; i < NUM_CHANNELS; ++i) {
181 MixerChannel *ch = &_channels[i];
182 if (ch->active) {
183 for (int pos = 0; pos < len; ++pos) {
184 if ((ch->chunkPos >> FRAC_BITS) >= (ch->chunk.len - 1)) {
185 ch->active = false;
186 break;
187 }
188 const int sample = ch->chunk.getPCM(ch->chunkPos >> FRAC_BITS) * ch->volume / Mixer::MAX_VOLUME;
189 out[pos] = ADDC_S16(out[pos], S8_to_S16(sample));
190 ch->chunkPos += ch->chunkInc;
191 }
192 }
193 }
194 if (kUseNr) {
195 nr(out, len);
196 }
197 }
198
mixCallback(void * param,int16_t * buf,int len)199 void Mixer::mixCallback(void *param, int16_t *buf, int len) {
200 ((Mixer *)param)->mix(buf, len);
201 }
202