Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libgambatte/src/sound/channel3.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 "channel3.h"
20
#include "../savestate.h"
21
#include <cstring>
22
#include <algorithm>
23
24
static inline unsigned toPeriod(const unsigned nr3, const unsigned nr4) {
25
return 0x800 - ((nr4 << 8 & 0x700) | nr3);
26
}
27
28
namespace gambatte {
29
30
Channel3::Channel3() :
31
disableMaster(master, waveCounter),
32
lengthCounter(disableMaster, 0xFF),
33
cycleCounter(0),
34
soMask(0),
35
prevOut(0),
36
waveCounter(SoundUnit::COUNTER_DISABLED),
37
lastReadTime(0),
38
nr0(0),
39
nr3(0),
40
nr4(0),
41
wavePos(0),
42
rShift(4),
43
sampleBuf(0),
44
master(false),
45
cgb(false)
46
{}
47
48
void Channel3::setNr0(const unsigned data) {
49
nr0 = data & 0x80;
50
51
if (!(data & 0x80))
52
disableMaster();
53
}
54
55
void Channel3::setNr2(const unsigned data) {
56
rShift = (data >> 5 & 3U) - 1;
57
58
if (rShift > 3)
59
rShift = 4;
60
}
61
62
void Channel3::setNr4(const unsigned data) {
63
lengthCounter.nr4Change(nr4, data, cycleCounter);
64
65
nr4 = data & 0x7F;
66
67
if (data & nr0/* & 0x80*/) {
68
if (!cgb && waveCounter == cycleCounter + 1) {
69
const unsigned pos = ((wavePos + 1) & 0x1F) >> 1;
70
71
if (pos < 4)
72
waveRam[0] = waveRam[pos];
73
else
74
std::memcpy(waveRam, waveRam + (pos & ~3), 4);
75
}
76
77
master = true;
78
wavePos = 0;
79
lastReadTime = waveCounter = cycleCounter + toPeriod(nr3, data) + 3;
80
}
81
}
82
83
void Channel3::setSo(const unsigned long soMask) {
84
this->soMask = soMask;
85
}
86
87
void Channel3::reset() {
88
cycleCounter = 0x1000 | (cycleCounter & 0xFFF); // cycleCounter >> 12 & 7 represents the frame sequencer position.
89
90
// lengthCounter.reset();
91
sampleBuf = 0;
92
}
93
94
void Channel3::init(const bool cgb) {
95
this->cgb = cgb;
96
lengthCounter.init(cgb);
97
}
98
99
void Channel3::setStatePtrs(SaveState &state) {
100
state.spu.ch3.waveRam.set(waveRam, sizeof waveRam);
101
}
102
103
void Channel3::loadState(const SaveState &state) {
104
lengthCounter.loadState(state.spu.ch3.lcounter, state.spu.cycleCounter);
105
106
cycleCounter = state.spu.cycleCounter;
107
waveCounter = std::max(state.spu.ch3.waveCounter, state.spu.cycleCounter);
108
lastReadTime = state.spu.ch3.lastReadTime;
109
nr3 = state.spu.ch3.nr3;
110
nr4 = state.spu.ch3.nr4;
111
wavePos = state.spu.ch3.wavePos & 0x1F;
112
sampleBuf = state.spu.ch3.sampleBuf;
113
master = state.spu.ch3.master;
114
115
nr0 = state.mem.ioamhram.get()[0x11A] & 0x80;
116
setNr2(state.mem.ioamhram.get()[0x11C]);
117
}
118
119
void Channel3::updateWaveCounter(const unsigned long cc) {
120
if (cc >= waveCounter) {
121
const unsigned period = toPeriod(nr3, nr4);
122
const unsigned long periods = (cc - waveCounter) / period;
123
124
lastReadTime = waveCounter + periods * period;
125
waveCounter = lastReadTime + period;
126
127
wavePos += periods + 1;
128
wavePos &= 0x1F;
129
130
sampleBuf = waveRam[wavePos >> 1];
131
}
132
}
133
134
void Channel3::update(uint_least32_t *buf, const unsigned long soBaseVol, unsigned long cycles) {
135
const unsigned long outBase = (nr0/* & 0x80*/) ? soBaseVol & soMask : 0;
136
137
if (outBase && rShift != 4) {
138
const unsigned long endCycles = cycleCounter + cycles;
139
140
for (;;) {
141
const unsigned long nextMajorEvent = lengthCounter.getCounter() < endCycles ? lengthCounter.getCounter() : endCycles;
142
unsigned long out = outBase * (master ? ((sampleBuf >> (~wavePos << 2 & 4) & 0xF) >> rShift) * 2 - 15ul : 0 - 15ul);
143
144
while (waveCounter <= nextMajorEvent) {
145
*buf += out - prevOut;
146
prevOut = out;
147
buf += waveCounter - cycleCounter;
148
cycleCounter = waveCounter;
149
150
lastReadTime = waveCounter;
151
waveCounter += toPeriod(nr3, nr4);
152
++wavePos;
153
wavePos &= 0x1F;
154
sampleBuf = waveRam[wavePos >> 1];
155
out = outBase * (/*master ? */((sampleBuf >> (~wavePos << 2 & 4) & 0xF) >> rShift) * 2 - 15ul/* : 0 - 15ul*/);
156
}
157
158
if (cycleCounter < nextMajorEvent) {
159
*buf += out - prevOut;
160
prevOut = out;
161
buf += nextMajorEvent - cycleCounter;
162
cycleCounter = nextMajorEvent;
163
}
164
165
if (lengthCounter.getCounter() == nextMajorEvent) {
166
lengthCounter.event();
167
} else
168
break;
169
}
170
} else {
171
if (outBase) {
172
const unsigned long out = outBase * (0 - 15ul);
173
174
*buf += out - prevOut;
175
prevOut = out;
176
}
177
178
cycleCounter += cycles;
179
180
while (lengthCounter.getCounter() <= cycleCounter) {
181
updateWaveCounter(lengthCounter.getCounter());
182
lengthCounter.event();
183
}
184
185
updateWaveCounter(cycleCounter);
186
}
187
188
if (cycleCounter & SoundUnit::COUNTER_MAX) {
189
lengthCounter.resetCounters(cycleCounter);
190
191
if (waveCounter != SoundUnit::COUNTER_DISABLED)
192
waveCounter -= SoundUnit::COUNTER_MAX;
193
194
lastReadTime -= SoundUnit::COUNTER_MAX;
195
cycleCounter -= SoundUnit::COUNTER_MAX;
196
}
197
}
198
199
SYNCFUNC(Channel3)
200
{
201
NSS(waveRam);
202
203
SSS(lengthCounter);
204
205
NSS(cycleCounter);
206
NSS(soMask);
207
NSS(prevOut);
208
NSS(waveCounter);
209
NSS(lastReadTime);
210
211
NSS(nr0);
212
NSS(nr3);
213
NSS(nr4);
214
NSS(wavePos);
215
NSS(rShift);
216
NSS(sampleBuf);
217
218
NSS(master);
219
NSS(cgb);
220
}
221
222
}
223
224