1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #ifndef SCUMM_IMUSE_PCSPK_H
24 #define SCUMM_IMUSE_PCSPK_H
25 
26 #include "audio/softsynth/emumidi.h"
27 #include "audio/softsynth/pcspk.h"
28 
29 namespace Scumm {
30 
31 class PcSpkDriver : public MidiDriver_Emulated {
32 public:
33 	PcSpkDriver(Audio::Mixer *mixer);
34 	~PcSpkDriver() override;
35 
36 	int open() override;
37 	void close() override;
38 
39 	void send(uint32 d) override;
40 	void sysEx_customInstrument(byte channel, uint32 type, const byte *instr) override;
41 
42 	MidiChannel *allocateChannel() override;
getPercussionChannel()43 	MidiChannel *getPercussionChannel() override { return 0; }
44 
isStereo()45 	bool isStereo() const override { return _pcSpk.isStereo(); }
getRate()46 	int getRate() const override { return _pcSpk.getRate(); }
47 protected:
48 	void generateSamples(int16 *buf, int len) override;
49 	void onTimer() override;
50 
51 private:
52 	Audio::PCSpeaker _pcSpk;
53 	int _effectTimer;
54 	uint8 _randBase;
55 
56 	void updateNote();
57 	void output(uint16 out);
58 
59 	static uint8 getEffectModifier(uint16 level);
60 	int16 getEffectModLevel(int16 level, int8 mod);
61 	int16 getRandScale(int16 input);
62 
63 	struct EffectEnvelope {
64 		uint8 state;
65 		int16 currentLevel;
66 		int16 duration;
67 		int16 maxLevel;
68 		int16 startLevel;
69 		uint8 loop;
70 		uint8 stateTargetLevels[4];
71 		uint8 stateModWheelLevels[4];
72 		uint8 modWheelSensitivity;
73 		uint8 modWheelState;
74 		uint8 modWheelLast;
75 		int16 stateNumSteps;
76 		int16 stateStepCounter;
77 		int16 changePerStep;
78 		int8 dir;
79 		int16 changePerStepRem;
80 		int16 changeCountRem;
81 	};
82 
83 	struct EffectDefinition {
84 		int16 phase;
85 		uint8 type;
86 		uint8 useModWheel;
87 		EffectEnvelope *envelope;
88 	};
89 
90 	struct OutputChannel {
91 		uint8 active;
92 		uint8 note;
93 		uint8 sustainNoteOff;
94 		uint8 length;
95 		const uint8 *instrument;
96 		uint8 unkA;
97 		uint8 unkB;
98 		uint8 unkC;
99 		int16 unkE;
100 		EffectEnvelope effectEnvelopeA;
101 		EffectDefinition effectDefA;
102 		EffectEnvelope effectEnvelopeB;
103 		EffectDefinition effectDefB;
104 		int16 unk60;
105 	};
106 
107 	struct MidiChannel_PcSpk : public MidiChannel {
108 		MidiDriver *device() override;
109 		byte getNumber() override;
110 		void release() override;
111 
112 		void send(uint32 b) override;
113 		void noteOff(byte note) override;
114 		void noteOn(byte note, byte velocity) override;
115 		void programChange(byte program) override;
116 		void pitchBend(int16 bend) override;
117 		void controlChange(byte control, byte value) override;
118 		void pitchBendFactor(byte value) override;
119 		void priority(byte value) override;
120 		void sysEx_customInstrument(uint32 type, const byte *instr) override;
121 
122 		void init(PcSpkDriver *owner, byte channel);
123 		bool allocate();
124 
125 		PcSpkDriver *_owner;
126 		bool _allocated;
127 		byte _channel;
128 
129 		OutputChannel _out;
130 		uint8 _instrument[23];
131 		uint8 _programNr;
132 		uint8 _priority;
133 		uint8 _tl;
134 		uint8 _modWheel;
135 		uint8 _sustain;
136 		uint8 _pitchBendFactor;
137 		int16 _pitchBend;
138 	};
139 
140 	void setupEffects(MidiChannel_PcSpk &chan, EffectEnvelope &env, EffectDefinition &def, byte flags, const byte *data);
141 	void startEffect(EffectEnvelope &env, const byte *data);
142 	void initNextEnvelopeState(EffectEnvelope &env);
143 	void updateEffectGenerator(MidiChannel_PcSpk &chan, EffectEnvelope &env, EffectDefinition &def);
144 	uint8 advanceEffectEnvelope(EffectEnvelope &env, EffectDefinition &def);
145 
146 	MidiChannel_PcSpk _channels[6];
147 	MidiChannel_PcSpk *_activeChannel;
148 
149 	MidiChannel_PcSpk *_lastActiveChannel;
150 	uint16 _lastActiveOut;
151 
152 	static const byte _outInstrumentData[1024];
153 	static const byte _outputTable1[];
154 	static const byte _outputTable2[];
155 	static const uint16 _effectEnvStepTable[];
156 	static const uint16 _frequencyTable[];
157 };
158 
159 } // End of namespace Scumm
160 
161 #endif
162