Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libgambatte/src/sound/channel2.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 "channel2.h"
20
#include "../savestate.h"
21
22
namespace gambatte {
23
24
Channel2::Channel2() :
25
staticOutputTest(*this, dutyUnit),
26
disableMaster(master, dutyUnit),
27
lengthCounter(disableMaster, 0x3F),
28
envelopeUnit(staticOutputTest),
29
cycleCounter(0),
30
soMask(0),
31
prevOut(0),
32
nr4(0),
33
master(false)
34
{
35
setEvent();
36
}
37
38
void Channel2::setEvent() {
39
// nextEventUnit = &dutyUnit;
40
// if (envelopeUnit.getCounter() < nextEventUnit->getCounter())
41
nextEventUnit = &envelopeUnit;
42
if (lengthCounter.getCounter() < nextEventUnit->getCounter())
43
nextEventUnit = &lengthCounter;
44
}
45
46
void Channel2::setNr1(const unsigned data) {
47
lengthCounter.nr1Change(data, nr4, cycleCounter);
48
dutyUnit.nr1Change(data, cycleCounter);
49
50
setEvent();
51
}
52
53
void Channel2::setNr2(const unsigned data) {
54
if (envelopeUnit.nr2Change(data))
55
disableMaster();
56
else
57
staticOutputTest(cycleCounter);
58
59
setEvent();
60
}
61
62
void Channel2::setNr3(const unsigned data) {
63
dutyUnit.nr3Change(data, cycleCounter);
64
setEvent();
65
}
66
67
void Channel2::setNr4(const unsigned data) {
68
lengthCounter.nr4Change(nr4, data, cycleCounter);
69
70
nr4 = data;
71
72
if (data & 0x80) { //init-bit
73
nr4 &= 0x7F;
74
master = !envelopeUnit.nr4Init(cycleCounter);
75
staticOutputTest(cycleCounter);
76
}
77
78
dutyUnit.nr4Change(data, cycleCounter);
79
80
setEvent();
81
}
82
83
void Channel2::setSo(const unsigned long soMask) {
84
this->soMask = soMask;
85
staticOutputTest(cycleCounter);
86
setEvent();
87
}
88
89
void Channel2::reset() {
90
cycleCounter = 0x1000 | (cycleCounter & 0xFFF); // cycleCounter >> 12 & 7 represents the frame sequencer position.
91
92
// lengthCounter.reset();
93
dutyUnit.reset();
94
envelopeUnit.reset();
95
96
setEvent();
97
}
98
99
void Channel2::init(const bool cgb) {
100
lengthCounter.init(cgb);
101
}
102
103
void Channel2::loadState(const SaveState &state) {
104
dutyUnit.loadState(state.spu.ch2.duty, state.mem.ioamhram.get()[0x116], state.spu.ch2.nr4,state.spu.cycleCounter);
105
envelopeUnit.loadState(state.spu.ch2.env, state.mem.ioamhram.get()[0x117], state.spu.cycleCounter);
106
lengthCounter.loadState(state.spu.ch2.lcounter, state.spu.cycleCounter);
107
108
cycleCounter = state.spu.cycleCounter;
109
nr4 = state.spu.ch2.nr4;
110
master = state.spu.ch2.master;
111
}
112
113
void Channel2::update(uint_least32_t *buf, const unsigned long soBaseVol, unsigned long cycles) {
114
const unsigned long outBase = envelopeUnit.dacIsOn() ? soBaseVol & soMask : 0;
115
const unsigned long outLow = outBase * (0 - 15ul);
116
const unsigned long endCycles = cycleCounter + cycles;
117
118
for (;;) {
119
const unsigned long outHigh = master ? outBase * (envelopeUnit.getVolume() * 2 - 15ul) : outLow;
120
const unsigned long nextMajorEvent = nextEventUnit->getCounter() < endCycles ? nextEventUnit->getCounter() : endCycles;
121
unsigned long out = dutyUnit.isHighState() ? outHigh : outLow;
122
123
while (dutyUnit.getCounter() <= nextMajorEvent) {
124
*buf += out - prevOut;
125
prevOut = out;
126
buf += dutyUnit.getCounter() - cycleCounter;
127
cycleCounter = dutyUnit.getCounter();
128
129
dutyUnit.event();
130
out = dutyUnit.isHighState() ? outHigh : outLow;
131
}
132
133
if (cycleCounter < nextMajorEvent) {
134
*buf += out - prevOut;
135
prevOut = out;
136
buf += nextMajorEvent - cycleCounter;
137
cycleCounter = nextMajorEvent;
138
}
139
140
if (nextEventUnit->getCounter() == nextMajorEvent) {
141
nextEventUnit->event();
142
setEvent();
143
} else
144
break;
145
}
146
147
if (cycleCounter & SoundUnit::COUNTER_MAX) {
148
dutyUnit.resetCounters(cycleCounter);
149
lengthCounter.resetCounters(cycleCounter);
150
envelopeUnit.resetCounters(cycleCounter);
151
152
cycleCounter -= SoundUnit::COUNTER_MAX;
153
}
154
}
155
156
SYNCFUNC(Channel2)
157
{
158
SSS(lengthCounter);
159
SSS(dutyUnit);
160
SSS(envelopeUnit);
161
162
EBS(nextEventUnit, 0);
163
EVS(nextEventUnit, &dutyUnit, 1);
164
EVS(nextEventUnit, &envelopeUnit, 2);
165
EVS(nextEventUnit, &lengthCounter, 3);
166
EES(nextEventUnit, NULL);
167
168
NSS(cycleCounter);
169
NSS(soMask);
170
NSS(prevOut);
171
172
NSS(nr4);
173
NSS(master);
174
}
175
176
}
177
178