Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libgambatte/src/sound/channel1.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 "channel1.h"
20
#include "../savestate.h"
21
#include <algorithm>
22
23
24
namespace gambatte {
25
26
Channel1::SweepUnit::SweepUnit(MasterDisabler &disabler, DutyUnit &dutyUnit) :
27
disableMaster(disabler),
28
dutyUnit(dutyUnit),
29
shadow(0),
30
nr0(0),
31
negging(false)
32
{}
33
34
unsigned Channel1::SweepUnit::calcFreq() {
35
unsigned freq = shadow >> (nr0 & 0x07);
36
37
if (nr0 & 0x08) {
38
freq = shadow - freq;
39
negging = true;
40
} else
41
freq = shadow + freq;
42
43
if (freq & 2048)
44
disableMaster();
45
46
return freq;
47
}
48
49
void Channel1::SweepUnit::event() {
50
const unsigned long period = nr0 >> 4 & 0x07;
51
52
if (period) {
53
const unsigned freq = calcFreq();
54
55
if (!(freq & 2048) && (nr0 & 0x07)) {
56
shadow = freq;
57
dutyUnit.setFreq(freq, counter);
58
calcFreq();
59
}
60
61
counter += period << 14;
62
} else
63
counter += 8ul << 14;
64
}
65
66
void Channel1::SweepUnit::nr0Change(const unsigned newNr0) {
67
if (negging && !(newNr0 & 0x08))
68
disableMaster();
69
70
nr0 = newNr0;
71
}
72
73
void Channel1::SweepUnit::nr4Init(const unsigned long cc) {
74
negging = false;
75
shadow = dutyUnit.getFreq();
76
77
const unsigned period = nr0 >> 4 & 0x07;
78
const unsigned shift = nr0 & 0x07;
79
80
if (period | shift)
81
counter = ((cc >> 14) + (period ? period : 8)) << 14;
82
else
83
counter = COUNTER_DISABLED;
84
85
if (shift)
86
calcFreq();
87
}
88
89
void Channel1::SweepUnit::reset() {
90
counter = COUNTER_DISABLED;
91
}
92
93
void Channel1::SweepUnit::loadState(const SaveState &state) {
94
counter = std::max(state.spu.ch1.sweep.counter, state.spu.cycleCounter);
95
shadow = state.spu.ch1.sweep.shadow;
96
nr0 = state.spu.ch1.sweep.nr0;
97
negging = state.spu.ch1.sweep.negging;
98
}
99
100
template<bool isReader>
101
void Channel1::SweepUnit::SyncState(NewState *ns)
102
{
103
NSS(counter);
104
NSS(shadow);
105
NSS(nr0);
106
NSS(negging);
107
}
108
109
Channel1::Channel1() :
110
staticOutputTest(*this, dutyUnit),
111
disableMaster(master, dutyUnit),
112
lengthCounter(disableMaster, 0x3F),
113
envelopeUnit(staticOutputTest),
114
sweepUnit(disableMaster, dutyUnit),
115
cycleCounter(0),
116
soMask(0),
117
prevOut(0),
118
nr4(0),
119
master(false)
120
{
121
setEvent();
122
}
123
124
void Channel1::setEvent() {
125
// nextEventUnit = &dutyUnit;
126
// if (sweepUnit.getCounter() < nextEventUnit->getCounter())
127
nextEventUnit = &sweepUnit;
128
if (envelopeUnit.getCounter() < nextEventUnit->getCounter())
129
nextEventUnit = &envelopeUnit;
130
if (lengthCounter.getCounter() < nextEventUnit->getCounter())
131
nextEventUnit = &lengthCounter;
132
}
133
134
void Channel1::setNr0(const unsigned data) {
135
sweepUnit.nr0Change(data);
136
setEvent();
137
}
138
139
void Channel1::setNr1(const unsigned data) {
140
lengthCounter.nr1Change(data, nr4, cycleCounter);
141
dutyUnit.nr1Change(data, cycleCounter);
142
143
setEvent();
144
}
145
146
void Channel1::setNr2(const unsigned data) {
147
if (envelopeUnit.nr2Change(data))
148
disableMaster();
149
else
150
staticOutputTest(cycleCounter);
151
152
setEvent();
153
}
154
155
void Channel1::setNr3(const unsigned data) {
156
dutyUnit.nr3Change(data, cycleCounter);
157
setEvent();
158
}
159
160
void Channel1::setNr4(const unsigned data) {
161
lengthCounter.nr4Change(nr4, data, cycleCounter);
162
163
nr4 = data;
164
165
dutyUnit.nr4Change(data, cycleCounter);
166
167
if (data & 0x80) { //init-bit
168
nr4 &= 0x7F;
169
master = !envelopeUnit.nr4Init(cycleCounter);
170
sweepUnit.nr4Init(cycleCounter);
171
staticOutputTest(cycleCounter);
172
}
173
174
setEvent();
175
}
176
177
void Channel1::setSo(const unsigned long soMask) {
178
this->soMask = soMask;
179
staticOutputTest(cycleCounter);
180
setEvent();
181
}
182
183
void Channel1::reset() {
184
cycleCounter = 0x1000 | (cycleCounter & 0xFFF); // cycleCounter >> 12 & 7 represents the frame sequencer position.
185
186
// lengthCounter.reset();
187
dutyUnit.reset();
188
envelopeUnit.reset();
189
sweepUnit.reset();
190
191
setEvent();
192
}
193
194
void Channel1::init(const bool cgb) {
195
lengthCounter.init(cgb);
196
}
197
198
void Channel1::loadState(const SaveState &state) {
199
sweepUnit.loadState(state);
200
dutyUnit.loadState(state.spu.ch1.duty, state.mem.ioamhram.get()[0x111], state.spu.ch1.nr4, state.spu.cycleCounter);
201
envelopeUnit.loadState(state.spu.ch1.env, state.mem.ioamhram.get()[0x112], state.spu.cycleCounter);
202
lengthCounter.loadState(state.spu.ch1.lcounter, state.spu.cycleCounter);
203
204
cycleCounter = state.spu.cycleCounter;
205
nr4 = state.spu.ch1.nr4;
206
master = state.spu.ch1.master;
207
}
208
209
void Channel1::update(uint_least32_t *buf, const unsigned long soBaseVol, unsigned long cycles) {
210
const unsigned long outBase = envelopeUnit.dacIsOn() ? soBaseVol & soMask : 0;
211
const unsigned long outLow = outBase * (0 - 15ul);
212
const unsigned long endCycles = cycleCounter + cycles;
213
214
for (;;) {
215
const unsigned long outHigh = master ? outBase * (envelopeUnit.getVolume() * 2 - 15ul) : outLow;
216
const unsigned long nextMajorEvent = nextEventUnit->getCounter() < endCycles ? nextEventUnit->getCounter() : endCycles;
217
unsigned long out = dutyUnit.isHighState() ? outHigh : outLow;
218
219
while (dutyUnit.getCounter() <= nextMajorEvent) {
220
*buf = out - prevOut;
221
prevOut = out;
222
buf += dutyUnit.getCounter() - cycleCounter;
223
cycleCounter = dutyUnit.getCounter();
224
225
dutyUnit.event();
226
out = dutyUnit.isHighState() ? outHigh : outLow;
227
}
228
229
if (cycleCounter < nextMajorEvent) {
230
*buf = out - prevOut;
231
prevOut = out;
232
buf += nextMajorEvent - cycleCounter;
233
cycleCounter = nextMajorEvent;
234
}
235
236
if (nextEventUnit->getCounter() == nextMajorEvent) {
237
nextEventUnit->event();
238
setEvent();
239
} else
240
break;
241
}
242
243
if (cycleCounter & SoundUnit::COUNTER_MAX) {
244
dutyUnit.resetCounters(cycleCounter);
245
lengthCounter.resetCounters(cycleCounter);
246
envelopeUnit.resetCounters(cycleCounter);
247
sweepUnit.resetCounters(cycleCounter);
248
249
cycleCounter -= SoundUnit::COUNTER_MAX;
250
}
251
}
252
253
SYNCFUNC(Channel1)
254
{
255
SSS(lengthCounter);
256
SSS(dutyUnit);
257
SSS(envelopeUnit);
258
SSS(sweepUnit);
259
260
EBS(nextEventUnit, 0);
261
EVS(nextEventUnit, &dutyUnit, 1);
262
EVS(nextEventUnit, &sweepUnit, 2);
263
EVS(nextEventUnit, &envelopeUnit, 3);
264
EVS(nextEventUnit, &lengthCounter, 4);
265
EES(nextEventUnit, NULL);
266
267
NSS(cycleCounter);
268
NSS(soMask);
269
NSS(prevOut);
270
271
NSS(nr4);
272
NSS(master);
273
}
274
275
}
276
277