Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libgambatte/src/sound/channel4.cpp
2 views
1
/***************************************************************************
2
* Copyright (C) 2007 by Sindre AamÄs *
3
* [email protected] *
4
* *
5
* This program is free software; you can redistribute it and/or modify *
6
* it under the terms of the GNU General Public License version 2 as *
7
* published by the Free Software Foundation. *
8
* *
9
* This program is distributed in the hope that it will be useful, *
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12
* GNU General Public License version 2 for more details. *
13
* *
14
* You should have received a copy of the GNU General Public License *
15
* version 2 along with this program; if not, write to the *
16
* Free Software Foundation, Inc., *
17
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
18
***************************************************************************/
19
#include "channel4.h"
20
#include "../savestate.h"
21
#include <algorithm>
22
23
static unsigned long toPeriod(const unsigned nr3) {
24
unsigned s = (nr3 >> 4) + 3;
25
unsigned r = nr3 & 7;
26
27
if (!r) {
28
r = 1;
29
--s;
30
}
31
32
return r << s;
33
}
34
35
namespace gambatte {
36
37
Channel4::Lfsr::Lfsr() :
38
backupCounter(COUNTER_DISABLED),
39
reg(0x7FFF),
40
nr3(0),
41
master(false)
42
{}
43
44
void Channel4::Lfsr::updateBackupCounter(const unsigned long cc) {
45
/*if (backupCounter <= cc) {
46
const unsigned long period = toPeriod(nr3);
47
backupCounter = cc - (cc - backupCounter) % period + period;
48
}*/
49
50
if (backupCounter <= cc) {
51
const unsigned long period = toPeriod(nr3);
52
unsigned long periods = (cc - backupCounter) / period + 1;
53
54
backupCounter += periods * period;
55
56
if (master && nr3 < 0xE0) {
57
if (nr3 & 8) {
58
while (periods > 6) {
59
const unsigned xored = (reg << 1 ^ reg) & 0x7E;
60
reg = (reg >> 6 & ~0x7E) | xored | xored << 8;
61
periods -= 6;
62
}
63
64
const unsigned xored = ((reg ^ reg >> 1) << (7 - periods)) & 0x7F;
65
reg = (reg >> periods & ~(0x80 - (0x80 >> periods))) | xored | xored << 8;
66
} else {
67
while (periods > 15) {
68
reg = reg ^ reg >> 1;
69
periods -= 15;
70
}
71
72
reg = reg >> periods | (((reg ^ reg >> 1) << (15 - periods)) & 0x7FFF);
73
}
74
}
75
}
76
}
77
78
void Channel4::Lfsr::reviveCounter(const unsigned long cc) {
79
updateBackupCounter(cc);
80
counter = backupCounter;
81
}
82
83
/*static const unsigned char nextStateDistance[0x40] = {
84
6, 1, 1, 2, 2, 1, 1, 3,
85
3, 1, 1, 2, 2, 1, 1, 4,
86
4, 1, 1, 2, 2, 1, 1, 3,
87
3, 1, 1, 2, 2, 1, 1, 5,
88
5, 1, 1, 2, 2, 1, 1, 3,
89
3, 1, 1, 2, 2, 1, 1, 4,
90
4, 1, 1, 2, 2, 1, 1, 3,
91
3, 1, 1, 2, 2, 1, 1, 6,
92
};*/
93
94
inline void Channel4::Lfsr::event() {
95
if (nr3 < 0xE0) {
96
const unsigned shifted = reg >> 1;
97
const unsigned xored = (reg ^ shifted) & 1;
98
99
reg = shifted | xored << 14;
100
101
if (nr3 & 8)
102
reg = (reg & ~0x40) | xored << 6;
103
}
104
105
counter += toPeriod(nr3);
106
backupCounter = counter;
107
108
109
/*if (nr3 < 0xE0) {
110
const unsigned periods = nextStateDistance[reg & 0x3F];
111
const unsigned xored = ((reg ^ reg >> 1) << (7 - periods)) & 0x7F;
112
113
reg = reg >> periods | xored << 8;
114
115
if (nr3 & 8)
116
reg = reg & ~(0x80 - (0x80 >> periods)) | xored;
117
}
118
119
const unsigned long period = toPeriod(nr3);
120
backupCounter = counter + period;
121
counter += period * nextStateDistance[reg & 0x3F];*/
122
}
123
124
void Channel4::Lfsr::nr3Change(const unsigned newNr3, const unsigned long cc) {
125
updateBackupCounter(cc);
126
nr3 = newNr3;
127
128
// if (counter != COUNTER_DISABLED)
129
// counter = backupCounter + toPeriod(nr3) * (nextStateDistance[reg & 0x3F] - 1);
130
}
131
132
void Channel4::Lfsr::nr4Init(unsigned long cc) {
133
disableMaster();
134
updateBackupCounter(cc);
135
master = true;
136
backupCounter += 4;
137
counter = backupCounter;
138
// counter = backupCounter + toPeriod(nr3) * (nextStateDistance[reg & 0x3F] - 1);
139
}
140
141
void Channel4::Lfsr::reset(const unsigned long cc) {
142
nr3 = 0;
143
disableMaster();
144
backupCounter = cc + toPeriod(nr3);
145
}
146
147
void Channel4::Lfsr::resetCounters(const unsigned long oldCc) {
148
updateBackupCounter(oldCc);
149
backupCounter -= COUNTER_MAX;
150
SoundUnit::resetCounters(oldCc);
151
}
152
153
void Channel4::Lfsr::loadState(const SaveState &state) {
154
counter = backupCounter = std::max(state.spu.ch4.lfsr.counter, state.spu.cycleCounter);
155
reg = state.spu.ch4.lfsr.reg;
156
master = state.spu.ch4.master;
157
nr3 = state.mem.ioamhram.get()[0x122];
158
}
159
160
template<bool isReader>
161
void Channel4::Lfsr::SyncState(NewState *ns)
162
{
163
NSS(counter);
164
NSS(backupCounter);
165
NSS(reg);
166
NSS(nr3);
167
NSS(master);
168
}
169
170
Channel4::Channel4() :
171
staticOutputTest(*this, lfsr),
172
disableMaster(master, lfsr),
173
lengthCounter(disableMaster, 0x3F),
174
envelopeUnit(staticOutputTest),
175
cycleCounter(0),
176
soMask(0),
177
prevOut(0),
178
nr4(0),
179
master(false)
180
{
181
setEvent();
182
}
183
184
void Channel4::setEvent() {
185
// nextEventUnit = &lfsr;
186
// if (envelopeUnit.getCounter() < nextEventUnit->getCounter())
187
nextEventUnit = &envelopeUnit;
188
if (lengthCounter.getCounter() < nextEventUnit->getCounter())
189
nextEventUnit = &lengthCounter;
190
}
191
192
void Channel4::setNr1(const unsigned data) {
193
lengthCounter.nr1Change(data, nr4, cycleCounter);
194
195
setEvent();
196
}
197
198
void Channel4::setNr2(const unsigned data) {
199
if (envelopeUnit.nr2Change(data))
200
disableMaster();
201
else
202
staticOutputTest(cycleCounter);
203
204
setEvent();
205
}
206
207
void Channel4::setNr4(const unsigned data) {
208
lengthCounter.nr4Change(nr4, data, cycleCounter);
209
210
nr4 = data;
211
212
if (data & 0x80) { //init-bit
213
nr4 &= 0x7F;
214
215
master = !envelopeUnit.nr4Init(cycleCounter);
216
217
if (master)
218
lfsr.nr4Init(cycleCounter);
219
220
staticOutputTest(cycleCounter);
221
}
222
223
setEvent();
224
}
225
226
void Channel4::setSo(const unsigned long soMask) {
227
this->soMask = soMask;
228
staticOutputTest(cycleCounter);
229
setEvent();
230
}
231
232
void Channel4::reset() {
233
cycleCounter = 0x1000 | (cycleCounter & 0xFFF); // cycleCounter >> 12 & 7 represents the frame sequencer position.
234
235
// lengthCounter.reset();
236
lfsr.reset(cycleCounter);
237
envelopeUnit.reset();
238
239
setEvent();
240
}
241
242
void Channel4::init(const bool cgb) {
243
lengthCounter.init(cgb);
244
}
245
246
void Channel4::loadState(const SaveState &state) {
247
lfsr.loadState(state);
248
envelopeUnit.loadState(state.spu.ch4.env, state.mem.ioamhram.get()[0x121], state.spu.cycleCounter);
249
lengthCounter.loadState(state.spu.ch4.lcounter, state.spu.cycleCounter);
250
251
cycleCounter = state.spu.cycleCounter;
252
nr4 = state.spu.ch4.nr4;
253
master = state.spu.ch4.master;
254
}
255
256
void Channel4::update(uint_least32_t *buf, const unsigned long soBaseVol, unsigned long cycles) {
257
const unsigned long outBase = envelopeUnit.dacIsOn() ? soBaseVol & soMask : 0;
258
const unsigned long outLow = outBase * (0 - 15ul);
259
const unsigned long endCycles = cycleCounter + cycles;
260
261
for (;;) {
262
const unsigned long outHigh = /*master ? */outBase * (envelopeUnit.getVolume() * 2 - 15ul)/* : outLow*/;
263
const unsigned long nextMajorEvent = nextEventUnit->getCounter() < endCycles ? nextEventUnit->getCounter() : endCycles;
264
unsigned long out = lfsr.isHighState() ? outHigh : outLow;
265
266
while (lfsr.getCounter() <= nextMajorEvent) {
267
*buf += out - prevOut;
268
prevOut = out;
269
buf += lfsr.getCounter() - cycleCounter;
270
cycleCounter = lfsr.getCounter();
271
272
lfsr.event();
273
out = lfsr.isHighState() ? outHigh : outLow;
274
}
275
276
if (cycleCounter < nextMajorEvent) {
277
*buf += out - prevOut;
278
prevOut = out;
279
buf += nextMajorEvent - cycleCounter;
280
cycleCounter = nextMajorEvent;
281
}
282
283
if (nextEventUnit->getCounter() == nextMajorEvent) {
284
nextEventUnit->event();
285
setEvent();
286
} else
287
break;
288
}
289
290
if (cycleCounter & SoundUnit::COUNTER_MAX) {
291
lengthCounter.resetCounters(cycleCounter);
292
lfsr.resetCounters(cycleCounter);
293
envelopeUnit.resetCounters(cycleCounter);
294
295
cycleCounter -= SoundUnit::COUNTER_MAX;
296
}
297
}
298
299
SYNCFUNC(Channel4)
300
{
301
SSS(lengthCounter);
302
SSS(envelopeUnit);
303
SSS(lfsr);
304
305
EBS(nextEventUnit, 0);
306
EVS(nextEventUnit, &lfsr, 1);
307
EVS(nextEventUnit, &envelopeUnit, 2);
308
EVS(nextEventUnit, &lengthCounter, 3);
309
EES(nextEventUnit, NULL);
310
311
NSS(cycleCounter);
312
NSS(soMask);
313
NSS(prevOut);
314
315
NSS(nr4);
316
NSS(master);
317
}
318
319
}
320
321