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 #ifndef SOUND_CHANNEL4_H
20 #define SOUND_CHANNEL4_H
21 
22 #include "envelope_unit.h"
23 #include "gbint.h"
24 #include "length_counter.h"
25 #include "master_disabler.h"
26 #include "static_output_tester.h"
27 
28 namespace gambatte {
29 
30 struct SaveState;
31 
32 class Channel4 {
33 public:
34 	Channel4();
35 	void setNr1(unsigned data);
36 	void setNr2(unsigned data);
setNr3(unsigned data)37 	void setNr3(unsigned data) { lfsr_.nr3Change(data, cycleCounter_); }
38 	void setNr4(unsigned data);
39 	void setSo(unsigned long soMask);
isActive()40 	bool isActive() const { return master_; }
41 	void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
42 	void reset();
43 	void saveState(SaveState &state);
44 	void loadState(SaveState const &state);
45 
46 private:
47 	class Lfsr : public SoundUnit {
48 	public:
49 		Lfsr();
50 		virtual void event();
51 		virtual void resetCounters(unsigned long oldCc);
isHighState()52 		bool isHighState() const { return ~reg_ & 1; }
53 		void nr3Change(unsigned newNr3, unsigned long cc);
54 		void nr4Init(unsigned long cc);
55 		void reset(unsigned long cc);
56 		void saveState(SaveState &state, unsigned long cc);
57 		void loadState(SaveState const &state);
disableMaster()58 		void disableMaster() { killCounter(); master_ = false; reg_ = 0x7FFF; }
killCounter()59 		void killCounter() { counter_ = counter_disabled; }
60 		void reviveCounter(unsigned long cc);
61 
62 	private:
63 		unsigned long backupCounter_;
64 		unsigned short reg_;
65 		unsigned char nr3_;
66 		bool master_;
67 
68 		void updateBackupCounter(unsigned long cc);
69 	};
70 
71 	class Ch4MasterDisabler : public MasterDisabler {
72 	public:
Ch4MasterDisabler(bool & m,Lfsr & lfsr)73 		Ch4MasterDisabler(bool &m, Lfsr &lfsr) : MasterDisabler(m), lfsr_(lfsr) {}
operator()74 		virtual void operator()() { MasterDisabler::operator()(); lfsr_.disableMaster(); }
75 
76 	private:
77 		Lfsr &lfsr_;
78 	};
79 
80 	friend class StaticOutputTester<Channel4, Lfsr>;
81 
82 	StaticOutputTester<Channel4, Lfsr> staticOutputTest_;
83 	Ch4MasterDisabler disableMaster_;
84 	LengthCounter lengthCounter_;
85 	EnvelopeUnit envelopeUnit_;
86 	Lfsr lfsr_;
87 	SoundUnit *nextEventUnit_;
88 	unsigned long cycleCounter_;
89 	unsigned long soMask_;
90 	unsigned long prevOut_;
91 	unsigned char nr4_;
92 	bool master_;
93 
94 	void setEvent();
95 };
96 
97 }
98 
99 #endif
100