1 //
2 //   Copyright (C) 2007 by sinamas <sinamas at users.sourceforge.net>
3 //
4 //   This program is free software; you can redistribute it and/or modify
5 //   it under the terms of the GNU General Public License version 2 as
6 //   published by the Free Software Foundation.
7 //
8 //   This program is distributed in the hope that it will be useful,
9 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
10 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 //   GNU General Public License version 2 for more details.
12 //
13 //   You should have received a copy of the GNU General Public License
14 //   version 2 along with this program; if not, write to the
15 //   Free Software Foundation, Inc.,
16 //   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17 //
18 
19 #include "channel4.h"
20 #include "../savestate.h"
21 #include <algorithm>
22 
toPeriod(unsigned const nr3)23 static unsigned long toPeriod(unsigned const 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 
Lfsr()37 Channel4::Lfsr::Lfsr()
38 : backupCounter_(counter_disabled)
39 , reg_(0x7FFF)
40 , nr3_(0)
41 , master_(false)
42 {
43 }
44 
updateBackupCounter(unsigned long const cc)45 void Channel4::Lfsr::updateBackupCounter(unsigned long const cc) {
46 	if (backupCounter_ <= cc) {
47 		unsigned long const period = toPeriod(nr3_);
48 		unsigned long periods = (cc - backupCounter_) / period + 1;
49 		backupCounter_ += periods * period;
50 
51 		if (master_ && nr3_ < 0xE0) {
52 			if (nr3_ & 8) {
53 				while (periods > 6) {
54 					unsigned const xored = (reg_ << 1 ^ reg_) & 0x7E;
55 					reg_ = (reg_ >> 6 & ~0x7E) | xored | xored << 8;
56 					periods -= 6;
57 				}
58 
59 				unsigned const xored = ((reg_ ^ reg_ >> 1) << (7 - periods)) & 0x7F;
60 				reg_ = (reg_ >> periods & ~(0x80 - (0x80 >> periods))) | xored | xored << 8;
61 			} else {
62 				while (periods > 15) {
63 					reg_ = reg_ ^ reg_ >> 1;
64 					periods -= 15;
65 				}
66 
67 				reg_ = reg_ >> periods | (((reg_ ^ reg_ >> 1) << (15 - periods)) & 0x7FFF);
68 			}
69 		}
70 	}
71 }
72 
reviveCounter(unsigned long cc)73 void Channel4::Lfsr::reviveCounter(unsigned long cc) {
74 	updateBackupCounter(cc);
75 	counter_ = backupCounter_;
76 }
77 
event()78 inline void Channel4::Lfsr::event() {
79 	if (nr3_ < 0xE0) {
80 		unsigned const shifted = reg_ >> 1;
81 		unsigned const xored = (reg_ ^ shifted) & 1;
82 		reg_ = shifted | xored << 14;
83 
84 		if (nr3_ & 8)
85 			reg_ = (reg_ & ~0x40) | xored << 6;
86 	}
87 
88 	counter_ += toPeriod(nr3_);
89 	backupCounter_ = counter_;
90 }
91 
nr3Change(unsigned newNr3,unsigned long cc)92 void Channel4::Lfsr::nr3Change(unsigned newNr3, unsigned long cc) {
93 	updateBackupCounter(cc);
94 	nr3_ = newNr3;
95 }
96 
nr4Init(unsigned long cc)97 void Channel4::Lfsr::nr4Init(unsigned long cc) {
98 	disableMaster();
99 	updateBackupCounter(cc);
100 	master_ = true;
101 	backupCounter_ += 4;
102 	counter_ = backupCounter_;
103 }
104 
reset(unsigned long cc)105 void Channel4::Lfsr::reset(unsigned long cc) {
106 	nr3_ = 0;
107 	disableMaster();
108 	backupCounter_ = cc + toPeriod(nr3_);
109 }
110 
resetCounters(unsigned long oldCc)111 void Channel4::Lfsr::resetCounters(unsigned long oldCc) {
112 	updateBackupCounter(oldCc);
113 	backupCounter_ -= counter_max;
114 	SoundUnit::resetCounters(oldCc);
115 }
116 
saveState(SaveState & state,unsigned long cc)117 void Channel4::Lfsr::saveState(SaveState &state, unsigned long cc) {
118 	updateBackupCounter(cc);
119 	state.spu.ch4.lfsr.counter = backupCounter_;
120 	state.spu.ch4.lfsr.reg = reg_;
121 }
122 
loadState(SaveState const & state)123 void Channel4::Lfsr::loadState(SaveState const &state) {
124 	counter_ = backupCounter_ = std::max(state.spu.ch4.lfsr.counter, state.spu.cycleCounter);
125 	reg_ = state.spu.ch4.lfsr.reg;
126 	master_ = state.spu.ch4.master;
127 	nr3_ = state.mem.ioamhram.get()[0x122];
128 }
129 
Channel4()130 Channel4::Channel4()
131 : staticOutputTest_(*this, lfsr_)
132 , disableMaster_(master_, lfsr_)
133 , lengthCounter_(disableMaster_, 0x3F)
134 , envelopeUnit_(staticOutputTest_)
135 , nextEventUnit_(0)
136 , cycleCounter_(0)
137 , soMask_(0)
138 , prevOut_(0)
139 , nr4_(0)
140 , master_(false)
141 {
142 	setEvent();
143 }
144 
setEvent()145 void Channel4::setEvent() {
146 	nextEventUnit_ = &envelopeUnit_;
147 	if (lengthCounter_.counter() < nextEventUnit_->counter())
148 		nextEventUnit_ = &lengthCounter_;
149 }
150 
setNr1(unsigned data)151 void Channel4::setNr1(unsigned data) {
152 	lengthCounter_.nr1Change(data, nr4_, cycleCounter_);
153 	setEvent();
154 }
155 
setNr2(unsigned data)156 void Channel4::setNr2(unsigned data) {
157 	if (envelopeUnit_.nr2Change(data))
158 		disableMaster_();
159 	else
160 		staticOutputTest_(cycleCounter_);
161 
162 	setEvent();
163 }
164 
setNr4(unsigned const data)165 void Channel4::setNr4(unsigned const data) {
166 	lengthCounter_.nr4Change(nr4_, data, cycleCounter_);
167 	nr4_ = data;
168 
169 	if (data & 0x80) { // init-bit
170 		nr4_ &= 0x7F;
171 		master_ = !envelopeUnit_.nr4Init(cycleCounter_);
172 
173 		if (master_)
174 			lfsr_.nr4Init(cycleCounter_);
175 
176 		staticOutputTest_(cycleCounter_);
177 	}
178 
179 	setEvent();
180 }
181 
setSo(unsigned long soMask)182 void Channel4::setSo(unsigned long soMask) {
183 	soMask_ = soMask;
184 	staticOutputTest_(cycleCounter_);
185 	setEvent();
186 }
187 
reset()188 void Channel4::reset() {
189 	// cycleCounter >> 12 & 7 represents the frame sequencer position.
190 	cycleCounter_ &= 0xFFF;
191 	cycleCounter_ += ~(cycleCounter_ + 2) << 1 & 0x1000;
192 
193 	lfsr_.reset(cycleCounter_);
194 	envelopeUnit_.reset();
195 	setEvent();
196 }
197 
saveState(SaveState & state)198 void Channel4::saveState(SaveState &state) {
199 	lfsr_.saveState(state, cycleCounter_);
200 	envelopeUnit_.saveState(state.spu.ch4.env);
201 	lengthCounter_.saveState(state.spu.ch4.lcounter);
202 
203 	state.spu.ch4.nr4 = nr4_;
204 	state.spu.ch4.master = master_;
205 }
206 
loadState(SaveState const & state)207 void Channel4::loadState(SaveState const &state) {
208 	lfsr_.loadState(state);
209 	envelopeUnit_.loadState(state.spu.ch4.env, state.mem.ioamhram.get()[0x121],
210 	                        state.spu.cycleCounter);
211 	lengthCounter_.loadState(state.spu.ch4.lcounter, state.spu.cycleCounter);
212 
213 	cycleCounter_ = state.spu.cycleCounter;
214 	nr4_ = state.spu.ch4.nr4;
215 	master_ = state.spu.ch4.master;
216 }
217 
update(uint_least32_t * buf,unsigned long const soBaseVol,unsigned long cycles)218 void Channel4::update(uint_least32_t *buf, unsigned long const soBaseVol, unsigned long cycles) {
219 	unsigned long const outBase = envelopeUnit_.dacIsOn() ? soBaseVol & soMask_ : 0;
220 	unsigned long const outLow = outBase * (0 - 15ul);
221 	unsigned long const endCycles = cycleCounter_ + cycles;
222 
223 	for (;;) {
224 		unsigned long const outHigh = outBase * (envelopeUnit_.getVolume() * 2 - 15ul);
225 		unsigned long const nextMajorEvent = std::min(nextEventUnit_->counter(), endCycles);
226 		unsigned long out = lfsr_.isHighState() ? outHigh : outLow;
227 
228 		while (lfsr_.counter() <= nextMajorEvent) {
229 			*buf += out - prevOut_;
230 			prevOut_ = out;
231 			buf += lfsr_.counter() - cycleCounter_;
232 			cycleCounter_ = lfsr_.counter();
233 
234 			lfsr_.event();
235 			out = lfsr_.isHighState() ? outHigh : outLow;
236 		}
237 
238 		if (cycleCounter_ < nextMajorEvent) {
239 			*buf += out - prevOut_;
240 			prevOut_ = out;
241 			buf += nextMajorEvent - cycleCounter_;
242 			cycleCounter_ = nextMajorEvent;
243 		}
244 
245 		if (nextEventUnit_->counter() == nextMajorEvent) {
246 			nextEventUnit_->event();
247 			setEvent();
248 		} else
249 			break;
250 	}
251 
252 	if (cycleCounter_ >= SoundUnit::counter_max) {
253 		lengthCounter_.resetCounters(cycleCounter_);
254 		lfsr_.resetCounters(cycleCounter_);
255 		envelopeUnit_.resetCounters(cycleCounter_);
256 		cycleCounter_ -= SoundUnit::counter_max;
257 	}
258 }
259 
260 }
261