aboutsummaryrefslogtreecommitdiff
path: root/engines/scumm/imuse/pcspk.h
blob: 195bd34b073ac5154fbb60c0591053391f2dad3c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#ifndef SCUMM_IMUSE_PCSPK_H
#define SCUMM_IMUSE_PCSPK_H

#include "audio/softsynth/emumidi.h"
#include "audio/softsynth/pcspk.h"

namespace Scumm {

class PcSpkDriver : public MidiDriver_Emulated {
public:
	PcSpkDriver(Audio::Mixer *mixer);
	~PcSpkDriver();

	virtual int open();
	virtual void close();

	virtual void send(uint32 d);
	virtual void sysEx_customInstrument(byte channel, uint32 type, const byte *instr);

	virtual MidiChannel *allocateChannel();
	virtual MidiChannel *getPercussionChannel() { return 0; }

	bool isStereo() const { return _pcSpk.isStereo(); }
	int getRate() const { return _pcSpk.getRate(); }
protected:
	void generateSamples(int16 *buf, int len);
	void onTimer();

private:
	Audio::PCSpeaker _pcSpk;
	int _effectTimer;
	uint8 _randBase;

	void updateNote();
	void output(uint16 out);

	static uint8 getEffectModifier(uint16 level);
	int16 getEffectModLevel(int16 level, int8 mod);
	int16 getRandScale(int16 input);

	struct EffectEnvelope {
		uint8 state;
		int16 currentLevel;
		int16 duration;
		int16 maxLevel;
		int16 startLevel;
		uint8 loop;
		uint8 stateTargetLevels[4];
		uint8 stateModWheelLevels[4];
		uint8 modWheelSensitivity;
		uint8 modWheelState;
		uint8 modWheelLast;
		int16 stateNumSteps;
		int16 stateStepCounter;
		int16 changePerStep;
		int8 dir;
		int16 changePerStepRem;
		int16 changeCountRem;
	};

	struct EffectDefinition {
		int16 phase;
		uint8 type;
		uint8 useModWheel;
		EffectEnvelope *envelope;
	};

	struct OutputChannel {
		uint8 active;
		uint8 note;
		uint8 sustainNoteOff;
		uint8 length;
		const uint8 *instrument;
		uint8 unkA;
		uint8 unkB;
		uint8 unkC;
		int16 unkE;
		EffectEnvelope effectEnvelopeA;
		EffectDefinition effectDefA;
		EffectEnvelope effectEnvelopeB;
		EffectDefinition effectDefB;
		int16 unk60;
	};

	struct MidiChannel_PcSpk : public MidiChannel {
		virtual MidiDriver *device();
		virtual byte getNumber();
		virtual void release();

		virtual void send(uint32 b);
		virtual void noteOff(byte note);
		virtual void noteOn(byte note, byte velocity);
		virtual void programChange(byte program);
		virtual void pitchBend(int16 bend);
		virtual void controlChange(byte control, byte value);
		virtual void pitchBendFactor(byte value);
		virtual void priority(byte value);
		virtual void sysEx_customInstrument(uint32 type, const byte *instr);

		void init(PcSpkDriver *owner, byte channel);
		bool allocate();

		PcSpkDriver *_owner;
		bool _allocated;
		byte _channel;

		OutputChannel _out;
		uint8 _instrument[23];
		uint8 _programNr;
		uint8 _priority;
		uint8 _tl;
		uint8 _modWheel;
		uint8 _sustain;
		uint8 _pitchBendFactor;
		int16 _pitchBend;
	};

	void setupEffects(MidiChannel_PcSpk &chan, EffectEnvelope &env, EffectDefinition &def, byte flags, const byte *data);
	void startEffect(EffectEnvelope &env, const byte *data);
	void initNextEnvelopeState(EffectEnvelope &env);
	void updateEffectGenerator(MidiChannel_PcSpk &chan, EffectEnvelope &env, EffectDefinition &def);
	uint8 advanceEffectEnvelope(EffectEnvelope &env, EffectDefinition &def);

	MidiChannel_PcSpk _channels[6];
	MidiChannel_PcSpk *_activeChannel;

	MidiChannel_PcSpk *_lastActiveChannel;
	uint16 _lastActiveOut;

	static const byte _outInstrumentData[1024];
	static const byte _outputTable1[];
	static const byte _outputTable2[];
	static const uint16 _effectEnvStepTable[];
	static const uint16 _frequencyTable[];
};

} // End of namespace Scumm

#endif