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 #include "common/debug.h"
24 #include "common/system.h"
25
26 #include "audio/fmopl.h"
27 #include "audio/mpu401.h"
28 #include "audio/mididrv.h"
29
30 namespace Parallaction {
31
32 const uint kNumVoices = 9;
33 // adlib FM voices 0-5
34 const uint kNumMelodic = 6;
35 // adlib FM voice 6 and 7-8
36 const uint kNumPercussion = 5;
37
38 // mask for maximum volume level
39 #define LEVEL_MASK 0x7f
40
41 struct OPLOperator {
42 uint8 characteristic; // amplitude modulation, vibrato, envelope, keyboard scaling, modulator frequency
43 uint8 levels;
44 uint8 attackDecay;
45 uint8 sustainRelease;
46 uint8 waveform;
47 };
48
49 struct MelodicProgram {
50 OPLOperator op[2];
51 uint8 feedbackAlgo;
52 };
53
54 struct PercussionNote {
55 OPLOperator op[2];
56 uint8 feedbackAlgo;
57 uint8 percussion;
58 uint8 valid;
59 uint16 frequency;
60 uint8 octave;
61 };
62
63 static const MelodicProgram melodicPrograms[128] = {
64 {{{ 0x1, 0x51, 0xf2, 0xb2, 0x0 }, { 0x11, 0x0, 0xf2, 0xa2, 0x0 }}, 0x0 },
65 {{{ 0xc2, 0x4b, 0xf1, 0x53, 0x0 }, { 0xd2, 0x0, 0xf2, 0x74, 0x0 }}, 0x4 },
66 {{{ 0x81, 0x9d, 0xf2, 0x74, 0x0 }, { 0x13, 0x0, 0xf2, 0xf1, 0x0 }}, 0x6 },
67 {{{ 0x3, 0x4f, 0xf1, 0x53, 0x0 }, { 0x17, 0x3, 0xf2, 0x74, 0x0 }}, 0x6 },
68 {{{ 0xd1, 0x81, 0x81, 0x73, 0x2 }, { 0xd4, 0x0, 0xe1, 0x34, 0x0 }}, 0x3 },
69 {{{ 0x1, 0x0, 0x94, 0xa6, 0x0 }, { 0x2, 0x0, 0x83, 0x26, 0x0 }}, 0x1 },
70 {{{ 0xf3, 0x84, 0x81, 0x2, 0x1 }, { 0x55, 0x80, 0xdd, 0x3, 0x0 }}, 0x4 },
71 {{{ 0x5, 0x8a, 0xf2, 0x26, 0x0 }, { 0x1, 0x80, 0xf3, 0x48, 0x0 }}, 0x0 },
72 {{{ 0x32, 0x0, 0xb1, 0x14, 0x0 }, { 0x12, 0x0, 0xfd, 0x36, 0x0 }}, 0x3 },
73 {{{ 0x1, 0x0, 0x82, 0xa, 0x2 }, { 0x2, 0x0, 0x85, 0x15, 0x0 }}, 0x3 },
74 {{{ 0xd1, 0x1, 0x97, 0xaa, 0x0 }, { 0x4, 0xd, 0xf3, 0xa5, 0x1 }}, 0x9 },
75 {{{ 0x17, 0x0, 0xf2, 0x62, 0x0 }, { 0x12, 0x0, 0xf2, 0x72, 0x0 }}, 0x8 },
76 {{{ 0x6, 0x0, 0xff, 0xf4, 0x0 }, { 0xc4, 0x0, 0xf8, 0xb5, 0x0 }}, 0xe },
77 {{{ 0xc0, 0x81, 0xf2, 0x13, 0x2 }, { 0xc0, 0xc1, 0xf3, 0x14, 0x2 }}, 0xb },
78 {{{ 0x44, 0x53, 0xf5, 0x31, 0x0 }, { 0x60, 0x80, 0xfd, 0x22, 0x0 }}, 0x6 },
79 {{{ 0xe0, 0x80, 0xf4, 0xf2, 0x0 }, { 0x61, 0x0, 0xf2, 0x6, 0x0 }}, 0x8 },
80 {{{ 0xc1, 0x6, 0x83, 0x23, 0x0 }, { 0xc1, 0x4, 0xf0, 0x26, 0x0 }}, 0x1 },
81 {{{ 0x26, 0x0, 0xf4, 0xb6, 0x0 }, { 0x21, 0x0, 0x81, 0x4b, 0x0 }}, 0x1 },
82 {{{ 0x24, 0x80, 0xff, 0xf, 0x0 }, { 0x21, 0x80, 0xff, 0xf, 0x0 }}, 0x1 },
83 {{{ 0x24, 0x4f, 0xf2, 0xb, 0x0 }, { 0x31, 0x0, 0x52, 0xb, 0x0 }}, 0xb },
84 {{{ 0x31, 0x8, 0x81, 0xb, 0x0 }, { 0xa1, 0x80, 0x92, 0x3b, 0x0 }}, 0x0 },
85 {{{ 0x70, 0xc5, 0x52, 0x11, 0x1 }, { 0x71, 0x80, 0x31, 0xfe, 0x1 }}, 0x0 },
86 {{{ 0x51, 0x88, 0x10, 0xf0, 0x0 }, { 0x42, 0x83, 0x40, 0xfc, 0x0 }}, 0x8 },
87 {{{ 0xf0, 0xd9, 0x81, 0x3, 0x0 }, { 0xb1, 0x80, 0xf1, 0x5, 0x0 }}, 0xa },
88 {{{ 0x21, 0x4f, 0xf1, 0x31, 0x0 }, { 0x2, 0x80, 0xc3, 0x45, 0x0 }}, 0x0 },
89 {{{ 0x7, 0x8f, 0x9c, 0x33, 0x1 }, { 0x1, 0x80, 0x8a, 0x13, 0x0 }}, 0x0 },
90 {{{ 0x21, 0x40, 0xf1, 0x31, 0x0 }, { 0x6, 0x80, 0xf4, 0x44, 0x0 }}, 0x0 },
91 {{{ 0x21, 0x40, 0xf1, 0x31, 0x3 }, { 0x81, 0x0, 0xf4, 0x44, 0x2 }}, 0x2 },
92 {{{ 0x11, 0x8d, 0xfd, 0x11, 0x0 }, { 0x11, 0x80, 0xfd, 0x11, 0x0 }}, 0x8 },
93 {{{ 0xf0, 0x1, 0x97, 0x17, 0x0 }, { 0x21, 0xd, 0xf1, 0x18, 0x0 }}, 0x8 },
94 {{{ 0xf1, 0x1, 0x97, 0x17, 0x0 }, { 0x21, 0xd, 0xf1, 0x18, 0x0 }}, 0x8 },
95 {{{ 0xcd, 0x9e, 0x55, 0xd1, 0x0 }, { 0xd1, 0x0, 0xf2, 0x71, 0x0 }}, 0xe },
96 {{{ 0x1, 0x0, 0xf2, 0x88, 0x0 }, { 0x1, 0x0, 0xf5, 0x88, 0x0 }}, 0x1 },
97 {{{ 0x30, 0xd, 0xf2, 0xef, 0x0 }, { 0x21, 0x0, 0xf5, 0x78, 0x0 }}, 0x6 },
98 {{{ 0x0, 0x10, 0xf4, 0xd9, 0x0 }, { 0x0, 0x0, 0xf5, 0xd7, 0x0 }}, 0x4 },
99 {{{ 0x1, 0x4c, 0xf2, 0x50, 0x0 }, { 0x1, 0x40, 0xd2, 0x59, 0x0 }}, 0x8 },
100 {{{ 0x20, 0x11, 0xe2, 0x8a, 0x0 }, { 0x20, 0x0, 0xe4, 0xa8, 0x0 }}, 0xa },
101 {{{ 0x21, 0x40, 0x7b, 0x4, 0x1 }, { 0x21, 0x0, 0x75, 0x72, 0x0 }}, 0x2 },
102 {{{ 0x31, 0xd, 0xf2, 0xef, 0x0 }, { 0x21, 0x0, 0xf5, 0x78, 0x0 }}, 0xa },
103 {{{ 0x1, 0xc, 0xf5, 0x2f, 0x1 }, { 0x0, 0x80, 0xf5, 0x5c, 0x0 }}, 0x0 },
104 {{{ 0xb0, 0x1c, 0x81, 0x3, 0x2 }, { 0x20, 0x0, 0x54, 0x67, 0x2 }}, 0xe },
105 {{{ 0x1, 0x0, 0xf1, 0x65, 0x0 }, { 0x1, 0x80, 0xa3, 0xa8, 0x2 }}, 0x1 },
106 {{{ 0xe1, 0x4f, 0xc1, 0xd3, 0x2 }, { 0x21, 0x0, 0x32, 0x74, 0x1 }}, 0x0 },
107 {{{ 0x2, 0x0, 0xf6, 0x16, 0x0 }, { 0x12, 0x0, 0xf2, 0xf8, 0x0 }}, 0x1 },
108 {{{ 0xe0, 0x63, 0xf8, 0xf3, 0x0 }, { 0x70, 0x80, 0xf7, 0xf3, 0x0 }}, 0x4 },
109 {{{ 0x1, 0x6, 0xf3, 0xff, 0x0 }, { 0x8, 0x0, 0xf7, 0xff, 0x0 }}, 0x4 },
110 {{{ 0x21, 0x16, 0xb0, 0x81, 0x1 }, { 0x22, 0x0, 0xb3, 0x13, 0x1 }}, 0xc },
111 {{{ 0x1, 0x4f, 0xf0, 0xff, 0x0 }, { 0x30, 0x0, 0x90, 0xf, 0x0 }}, 0x6 },
112 {{{ 0x0, 0x10, 0xf1, 0xf2, 0x2 }, { 0x1, 0x0, 0xf1, 0xf2, 0x3 }}, 0x0 },
113 {{{ 0x1, 0x4f, 0xf1, 0x50, 0x0 }, { 0x21, 0x80, 0xa3, 0x5, 0x3 }}, 0x6 },
114 {{{ 0xb1, 0x3, 0x55, 0x3, 0x0 }, { 0xb1, 0x3, 0x8, 0xa, 0x0 }}, 0x9 },
115 {{{ 0x22, 0x0, 0xa9, 0x34, 0x1 }, { 0x1, 0x0, 0xa2, 0x42, 0x2 }}, 0x2 },
116 {{{ 0xa0, 0xdc, 0x81, 0x31, 0x3 }, { 0xb1, 0x80, 0xf1, 0x1, 0x3 }}, 0x0 },
117 {{{ 0x1, 0x4f, 0xf1, 0x50, 0x0 }, { 0x21, 0x80, 0xa3, 0x5, 0x3 }}, 0x6 },
118 {{{ 0xf1, 0x80, 0xa0, 0x72, 0x0 }, { 0x74, 0x0, 0x90, 0x22, 0x0 }}, 0x9 },
119 {{{ 0xe1, 0x13, 0x71, 0xae, 0x0 }, { 0xe1, 0x0, 0xf0, 0xfc, 0x1 }}, 0xa },
120 {{{ 0x31, 0x1c, 0x41, 0xb, 0x0 }, { 0xa1, 0x80, 0x92, 0x3b, 0x0 }}, 0xe },
121 {{{ 0x71, 0x1c, 0x41, 0x1f, 0x0 }, { 0xa1, 0x80, 0x92, 0x3b, 0x0 }}, 0xe },
122 {{{ 0x21, 0x1c, 0x53, 0x1d, 0x0 }, { 0xa1, 0x80, 0x52, 0x3b, 0x0 }}, 0xc },
123 {{{ 0x21, 0x1d, 0xa4, 0xae, 0x1 }, { 0x21, 0x0, 0xb1, 0x9e, 0x0 }}, 0xc },
124 {{{ 0xe1, 0x16, 0x71, 0xae, 0x0 }, { 0xe1, 0x0, 0x81, 0x9e, 0x0 }}, 0xa },
125 {{{ 0xe1, 0x15, 0x71, 0xae, 0x0 }, { 0xe2, 0x0, 0x81, 0x9e, 0x0 }}, 0xe },
126 {{{ 0x21, 0x16, 0x71, 0xae, 0x0 }, { 0x21, 0x0, 0x81, 0x9e, 0x0 }}, 0xe },
127 {{{ 0x71, 0x1c, 0x41, 0x1f, 0x0 }, { 0xa1, 0x80, 0x92, 0x3b, 0x0 }}, 0xe },
128 {{{ 0x21, 0x4f, 0x81, 0x53, 0x0 }, { 0x32, 0x0, 0x22, 0x2c, 0x0 }}, 0xa },
129 {{{ 0x22, 0x4f, 0x81, 0x53, 0x0 }, { 0x32, 0x0, 0x22, 0x2c, 0x0 }}, 0xa },
130 {{{ 0x23, 0x4f, 0x81, 0x53, 0x0 }, { 0x34, 0x0, 0x22, 0x2c, 0x0 }}, 0xa },
131 {{{ 0xe1, 0x16, 0x71, 0xae, 0x0 }, { 0xe1, 0x0, 0x81, 0x9e, 0x0 }}, 0xa },
132 {{{ 0x71, 0xc5, 0x6e, 0x17, 0x0 }, { 0x22, 0x5, 0x8b, 0xe, 0x0 }}, 0x2 },
133 {{{ 0xe6, 0x27, 0x70, 0xf, 0x1 }, { 0xe3, 0x0, 0x60, 0x9f, 0x0 }}, 0xa },
134 {{{ 0x30, 0xc8, 0xd5, 0x19, 0x0 }, { 0xb1, 0x80, 0x61, 0x1b, 0x0 }}, 0xc },
135 {{{ 0x32, 0x9a, 0x51, 0x1b, 0x0 }, { 0xa1, 0x82, 0xa2, 0x3b, 0x0 }}, 0xc },
136 {{{ 0xad, 0x3, 0x74, 0x29, 0x0 }, { 0xa2, 0x82, 0x73, 0x29, 0x0 }}, 0x7 },
137 {{{ 0x21, 0x83, 0x74, 0x17, 0x0 }, { 0x62, 0x8d, 0x65, 0x17, 0x0 }}, 0x7 },
138 {{{ 0x94, 0xb, 0x85, 0xff, 0x1 }, { 0x13, 0x0, 0x74, 0xff, 0x0 }}, 0xc },
139 {{{ 0x74, 0x87, 0xa4, 0x2, 0x0 }, { 0xd6, 0x80, 0x45, 0x42, 0x0 }}, 0x2 },
140 {{{ 0xb3, 0x85, 0x76, 0x21, 0x1 }, { 0x20, 0x0, 0x3d, 0xc1, 0x0 }}, 0x6 },
141 {{{ 0x17, 0x4f, 0xf2, 0x61, 0x0 }, { 0x12, 0x8, 0xf1, 0xb4, 0x0 }}, 0x8 },
142 {{{ 0x4f, 0x86, 0x65, 0x1, 0x0 }, { 0x1f, 0x0, 0x32, 0x74, 0x0 }}, 0x4 },
143 {{{ 0xe1, 0x23, 0x71, 0xae, 0x0 }, { 0xe4, 0x0, 0x82, 0x9e, 0x0 }}, 0xa },
144 {{{ 0x11, 0x86, 0xf2, 0xbd, 0x0 }, { 0x4, 0x80, 0xa0, 0x9b, 0x1 }}, 0x8 },
145 {{{ 0x20, 0x90, 0xf5, 0x9e, 0x2 }, { 0x11, 0x0, 0xf4, 0x5b, 0x3 }}, 0xc },
146 {{{ 0xf0, 0x80, 0x34, 0xe4, 0x0 }, { 0x7e, 0x0, 0xa2, 0x6, 0x0 }}, 0x8 },
147 {{{ 0x90, 0xf, 0xff, 0x1, 0x3 }, { 0x0, 0x0, 0x1f, 0x1, 0x0 }}, 0xe },
148 {{{ 0x1, 0x4f, 0xf0, 0xff, 0x0 }, { 0x33, 0x0, 0x90, 0xf, 0x0 }}, 0x6 },
149 {{{ 0x1e, 0x0, 0x1f, 0xf, 0x0 }, { 0x10, 0x0, 0x1f, 0x7f, 0x0 }}, 0x0 },
150 {{{ 0xbe, 0x0, 0xf1, 0x1, 0x3 }, { 0x31, 0x0, 0xf1, 0x1, 0x0 }}, 0x4 },
151 {{{ 0xbe, 0x0, 0xf1, 0x1, 0x3 }, { 0x31, 0x0, 0xf1, 0x1, 0x0 }}, 0x4 },
152 {{{ 0x93, 0x6, 0xc1, 0x4, 0x1 }, { 0x82, 0x0, 0x51, 0x9, 0x0 }}, 0x6 },
153 {{{ 0xa0, 0x0, 0x96, 0x33, 0x0 }, { 0x20, 0x0, 0x55, 0x2b, 0x0 }}, 0x6 },
154 {{{ 0x0, 0xc0, 0xff, 0x5, 0x0 }, { 0x0, 0x0, 0xff, 0x5, 0x3 }}, 0x0 },
155 {{{ 0x4, 0x8, 0xf8, 0x7, 0x0 }, { 0x1, 0x0, 0x82, 0x74, 0x0 }}, 0x8 },
156 {{{ 0x0, 0x0, 0x2f, 0x5, 0x0 }, { 0x20, 0x0, 0xff, 0x5, 0x3 }}, 0xa },
157 {{{ 0x93, 0x0, 0xf7, 0x7, 0x2 }, { 0x0, 0x0, 0xf7, 0x7, 0x0 }}, 0xa },
158 {{{ 0x0, 0x40, 0x80, 0x7a, 0x0 }, { 0xc4, 0x0, 0xc0, 0x7e, 0x0 }}, 0x8 },
159 {{{ 0x90, 0x80, 0x55, 0xf5, 0x0 }, { 0x0, 0x0, 0x55, 0xf5, 0x0 }}, 0x8 },
160 {{{ 0xe1, 0x80, 0x34, 0xe4, 0x0 }, { 0x69, 0x0, 0xf2, 0x6, 0x0 }}, 0x8 },
161 {{{ 0x3, 0x2, 0xf0, 0xff, 0x3 }, { 0x11, 0x80, 0xf0, 0xff, 0x2 }}, 0x2 },
162 {{{ 0x1e, 0x0, 0x1f, 0xf, 0x0 }, { 0x10, 0x0, 0x1f, 0x7f, 0x0 }}, 0x0 },
163 {{{ 0x0, 0x0, 0x2f, 0x1, 0x0 }, { 0x0, 0x0, 0xff, 0x1, 0x0 }}, 0x4 },
164 {{{ 0xbe, 0x0, 0xf1, 0x1, 0x3 }, { 0x31, 0x0, 0xf1, 0x1, 0x0 }}, 0x4 },
165 {{{ 0x93, 0x85, 0x3f, 0x6, 0x1 }, { 0x0, 0x0, 0x5f, 0x7, 0x0 }}, 0x6 },
166 {{{ 0x6, 0x0, 0xa0, 0xf0, 0x0 }, { 0x44, 0x0, 0xc5, 0x75, 0x0 }}, 0xe },
167 {{{ 0x60, 0x0, 0x10, 0x81, 0x0 }, { 0x20, 0x8c, 0x12, 0x91, 0x0 }}, 0xe },
168 {{{ 0x1, 0x40, 0xf1, 0x53, 0x0 }, { 0x8, 0x40, 0xf1, 0x53, 0x0 }}, 0x0 },
169 {{{ 0x31, 0x0, 0x56, 0x31, 0x0 }, { 0x16, 0x0, 0x7d, 0x41, 0x0 }}, 0x0 },
170 {{{ 0x0, 0x10, 0xf2, 0x72, 0x0 }, { 0x13, 0x0, 0xf2, 0x72, 0x0 }}, 0xc },
171 {{{ 0x10, 0x0, 0x75, 0x93, 0x1 }, { 0x1, 0x0, 0xf5, 0x82, 0x1 }}, 0x0 },
172 {{{ 0x0, 0x0, 0xf6, 0xff, 0x2 }, { 0x0, 0x0, 0xf6, 0xff, 0x0 }}, 0x8 },
173 {{{ 0x30, 0x0, 0xff, 0xa0, 0x3 }, { 0x63, 0x0, 0x65, 0xb, 0x2 }}, 0x0 },
174 {{{ 0x2a, 0x0, 0xf6, 0x87, 0x0 }, { 0x2b, 0x0, 0x76, 0x25, 0x0 }}, 0x0 },
175 {{{ 0x85, 0x0, 0xb8, 0x84, 0x0 }, { 0x43, 0x0, 0xe5, 0x8f, 0x0 }}, 0x6 },
176 {{{ 0x7, 0x4f, 0xf2, 0x60, 0x0 }, { 0x12, 0x0, 0xf2, 0x72, 0x0 }}, 0x8 },
177 {{{ 0x5, 0x40, 0xb3, 0xd3, 0x0 }, { 0x86, 0x80, 0xf2, 0x24, 0x0 }}, 0x2 },
178 {{{ 0xd0, 0x0, 0x11, 0xcf, 0x0 }, { 0xd1, 0x0, 0xf4, 0xe8, 0x3 }}, 0x0 },
179 {{{ 0x5, 0x4e, 0xda, 0x25, 0x2 }, { 0x1, 0x0, 0xf9, 0x15, 0x0 }}, 0xa },
180 {{{ 0x3, 0x0, 0x8f, 0x7, 0x2 }, { 0x2, 0x0, 0xff, 0x6, 0x0 }}, 0x0 },
181 {{{ 0x13, 0x0, 0x8f, 0x7, 0x2 }, { 0x2, 0x0, 0xf9, 0x5, 0x0 }}, 0x0 },
182 {{{ 0xf0, 0x1, 0x97, 0x17, 0x0 }, { 0x21, 0xd, 0xf1, 0x18, 0x0 }}, 0x8 },
183 {{{ 0xf1, 0x41, 0x11, 0x11, 0x0 }, { 0xf1, 0x41, 0x11, 0x11, 0x0 }}, 0x2 },
184 {{{ 0x13, 0x0, 0x8f, 0x7, 0x2 }, { 0x2, 0x0, 0xff, 0x6, 0x0 }}, 0x0 },
185 {{{ 0x1, 0x0, 0x2f, 0x1, 0x0 }, { 0x1, 0x0, 0xaf, 0x1, 0x3 }}, 0xf },
186 {{{ 0x1, 0x6, 0xf3, 0xff, 0x0 }, { 0x8, 0x0, 0xf7, 0xff, 0x0 }}, 0x4 },
187 {{{ 0xc0, 0x4f, 0xf1, 0x3, 0x0 }, { 0xbe, 0xc, 0x10, 0x1, 0x0 }}, 0x2 },
188 {{{ 0x0, 0x2, 0xf0, 0xff, 0x0 }, { 0x11, 0x80, 0xf0, 0xff, 0x0 }}, 0x6 },
189 {{{ 0x81, 0x47, 0xf1, 0x83, 0x0 }, { 0xa2, 0x4, 0x91, 0x86, 0x0 }}, 0x6 },
190 {{{ 0xf0, 0xc0, 0xff, 0xff, 0x3 }, { 0xe5, 0x0, 0xfb, 0xf0, 0x0 }}, 0xe },
191 {{{ 0x0, 0x2, 0xf0, 0xff, 0x0 }, { 0x11, 0x80, 0xf0, 0xff, 0x0 }}, 0x6 }
192 };
193
194 static const PercussionNote percussionNotes[47] = {
195 {{{ 0x0, 0xb, 0xa8, 0x38, 0x0 }, { 0x0, 0x0, 0xd6, 0x49, 0x0 }}, 0x0, 0x4, 0x1, 0x97, 0x4 },
196 {{{ 0xc0, 0xc0, 0xf8, 0x3f, 0x2 }, { 0xc0, 0x0, 0xf6, 0x8e, 0x0 }}, 0x0, 0x4, 0x1, 0xf7, 0x4 },
197 {{{ 0xc0, 0x80, 0xc9, 0xab, 0x0 }, { 0xeb, 0x40, 0xb5, 0xf6, 0x0 }}, 0x1, 0x3, 0x1, 0x6a, 0x6 },
198 {{{ 0xc, 0x0, 0xd8, 0xa6, 0x0 }, { 0x0, 0x0, 0xd6, 0x4f, 0x0 }}, 0x1, 0x3, 0x1, 0x6c, 0x5 },
199 {{{ 0x1, 0x0, 0xe2, 0xd2, 0x0 }, { 0x3, 0x41, 0x8f, 0x48, 0x49 }}, 0xc, 0x4, 0x1, 0x2f, 0x5 },
200 {{{ 0x0, 0x0, 0xc8, 0x58, 0x3 }, { 0x0, 0x0, 0xf6, 0x4f, 0x0 }}, 0x9, 0x3, 0x1, 0x108, 0x4 },
201 {{{ 0x1, 0x0, 0xff, 0x5, 0x0 }, { 0xf2, 0xff, 0xe0, 0x50, 0x52 }}, 0x5d, 0x2, 0x1, 0x9f, 0x5 },
202 {{{ 0xe, 0x9, 0xb9, 0x47, 0x0 }, { 0xeb, 0x40, 0xf5, 0xe6, 0x0 }}, 0x0, 0x0, 0x1, 0x82, 0x6 },
203 {{{ 0x0, 0x0, 0xd6, 0x83, 0x0 }, { 0xd6, 0xd7, 0xe0, 0x41, 0x5e }}, 0x4a, 0x2, 0x1, 0xc7, 0x5 },
204 {{{ 0x1, 0x9, 0x89, 0x67, 0x0 }, { 0xd6, 0xd7, 0xe0, 0x41, 0x5e }}, 0x4a, 0x0, 0x1, 0x80, 0x6 },
205 {{{ 0x1, 0x0, 0xd6, 0x96, 0x0 }, { 0xd6, 0xd7, 0xe0, 0x41, 0x5e }}, 0x4a, 0x2, 0x1, 0xed, 0x5 },
206 {{{ 0x0, 0x9, 0xa9, 0x55, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x1, 0x82, 0x6 },
207 {{{ 0x2, 0x0, 0xc6, 0x96, 0x0 }, { 0xe0, 0x0, 0xe0, 0x40, 0x0 }}, 0x1, 0x2, 0x1, 0x123, 0x5 },
208 {{{ 0x5, 0x0, 0xf6, 0x56, 0x0 }, { 0xf7, 0xff, 0xb3, 0x90, 0x4f }}, 0x1, 0x2, 0x1, 0x15b, 0x5 },
209 {{{ 0x1, 0x0, 0xf7, 0x14, 0x0 }, { 0xf7, 0xff, 0x36, 0x90, 0x79 }}, 0xe7, 0x1, 0x1, 0x1ac, 0x5 },
210 {{{ 0x0, 0x0, 0xf6, 0x56, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x1, 0x2, 0x1, 0x18b, 0x5 },
211 {{{ 0x0, 0x83, 0xfb, 0x5, 0x0 }, { 0xf7, 0x41, 0x39, 0x90, 0x79 }}, 0x1, 0x1, 0x1, 0xc8, 0x5 },
212 {{{ 0x0, 0x0, 0xff, 0x5, 0x0 }, { 0xf7, 0xff, 0x36, 0x90, 0x79 }}, 0xe7, 0x1, 0x1, 0xf9, 0x5 },
213 {{{ 0x1, 0x0, 0xa0, 0x5, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x2, 0x1, 0x27a, 0x6 },
214 {{{ 0x0, 0x5, 0xf3, 0x6, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x2, 0x1, 0x108, 0x7 },
215 {{{ 0x1, 0x0, 0xf9, 0x34, 0x0 }, { 0xf7, 0xff, 0x36, 0x90, 0x79 }}, 0xe7, 0x1, 0x1, 0x147, 0x4 },
216 {{{ 0x0, 0x0, 0xf7, 0x16, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x2, 0x1, 0x120, 0x6 },
217 {{{ 0x1, 0x0, 0xff, 0x5, 0x0 }, { 0xf7, 0xff, 0x36, 0x90, 0x79 }}, 0xe7, 0x1, 0x1, 0x42, 0x6 },
218 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
219 {{{ 0x1, 0x0, 0xff, 0x5, 0x0 }, { 0xf7, 0xff, 0x36, 0x90, 0x79 }}, 0xe7, 0x1, 0x1, 0x6d, 0x5 },
220 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
221 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
222 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
223 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
224 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
225 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
226 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
227 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
228 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
229 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
230 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
231 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
232 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
233 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
234 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
235 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
236 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
237 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
238 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
239 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
240 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 },
241 {{{ 0x0, 0x0, 0x0, 0x0, 0x0 }, { 0x0, 0x0, 0x0, 0x0, 0x0 }}, 0x0, 0x0, 0x0, 0x3fc, 0x4 }
242 };
243
244 const uint16 melodicFrequencies[36] = {
245 0x55, 0x5a, 0x60, 0x66, 0x6c, 0x72, 0x79, 0x80, 0x88,
246 0x90, 0x99, 0xa1, 0xab, 0xb5, 0xc0, 0xcc, 0xd8, 0xe5,
247 0xf2, 0x101, 0x110, 0x120, 0x132, 0x143, 0x156, 0x16b, 0x181,
248 0x198, 0x1b0, 0x1ca, 0x1e5, 0x202, 0x220, 0x241, 0x263, 0x286
249 };
250
251 class AdLibDriver;
252
253 class AdLibChannel : public MidiChannel_MPU401 {
254 public:
255 void reset();
256
257 uint8 _program;
258 uint8 _volume;
259 uint8 _pedal;
260 };
261
262 struct MelodicVoice {
263 bool _used;
264 uint8 _channel;
265 uint8 _program;
266
267 uint8 _key;
268 uint32 _timestamp;
269 uint16 _frequency;
270 int8 _octave;
271 };
272
273 class AdLibDriver : public MidiDriver {
274 public:
AdLibDriver(Audio::Mixer * mixer)275 AdLibDriver(Audio::Mixer *mixer) {
276 for (uint i = 0; i < 16; ++i)
277 _channels[i].init(this, i);
278
279 _isOpen = false;
280
281 _opl = NULL;
282 memset(_voices, 0, sizeof(_voices));
283
284 _lastVoice = 0;
285 _percussionMask = 0;
286
287 _adlibTimerProc = NULL;
288 _adlibTimerParam = NULL;
289 }
290
291 int open() override;
292 void close() override;
293 void send(uint32 b) override;
294 MidiChannel *allocateChannel() override;
getPercussionChannel()295 MidiChannel *getPercussionChannel() override { return &_channels[9]; }
isOpen() const296 bool isOpen() const override { return _isOpen; }
getBaseTempo()297 uint32 getBaseTempo() override { return 1000000 / OPL::OPL::kDefaultCallbackFrequency; }
298
setTimerCallback(void * timerParam,Common::TimerManager::TimerProc timerProc)299 void setTimerCallback(void *timerParam, Common::TimerManager::TimerProc timerProc) override {
300 _adlibTimerProc = timerProc;
301 _adlibTimerParam = timerParam;
302 }
303
304 protected:
305 OPL::OPL *_opl;
306 AdLibChannel _channels[16];
307 MelodicVoice _voices[kNumMelodic];
308 uint8 _notesPerPercussion[kNumPercussion];
309
310 uint _lastVoice;
311
312 uint8 _percussionMask;
313
314 void noteOff(uint8 channel, uint8 note);
315 void noteOn(uint8 channel, uint8 note, uint8 velocity);
316 void allNotesOff();
317 void setModulationWheel(uint8 channel, uint8 value);
318 void setFootController(uint8 channel, uint8 value);
319 void setVolume(uint8 channel, uint8 value);
320 void setPitchBend(uint8 channel, int16 value);
321
322 void playNote(uint8 voice, uint8 octave, uint16 frequency);
323
324 void programOperatorSimple(uint8 offset, const OPLOperator &op);
325 void programOperator(uint8 offset, const OPLOperator &op);
326 void setOperatorLevel(uint8 offset, const OPLOperator &op, uint8 velocity, uint8 channel, bool forceVolume);
327
328 void setupPercussion(const PercussionNote ¬e);
329 void playPercussion(uint8 channel, const PercussionNote ¬e, uint8 velocity);
330
331 void programMelodicVoice(uint8 voice, uint8 program);
332 void playMelodicNote(uint8 voice, uint8 channel, uint8 note, uint8 velocity);
333 void muteMelodicVoice(uint8 voice);
334
335 void initVoices();
336
337 private:
338 void onTimer();
339
340 Common::TimerManager::TimerProc _adlibTimerProc;
341 void *_adlibTimerParam;
342 bool _isOpen;
343 };
344
createAdLibDriver()345 MidiDriver *createAdLibDriver() {
346 return new AdLibDriver(g_system->getMixer());
347 }
348
reset()349 void AdLibChannel::reset() {
350 _program = 0;
351 _volume = 127;
352 _pedal = 0;
353 }
354
355 /*
356 bit 7 - Clear: AM depth is 1 dB
357 bit 6 - Clear: Vibrato depth is 7 cent
358 bit 5 - Set: Rhythm enabled (6 melodic voices)
359 bit 4 - Bass drum off
360 bit 3 - Snare drum off
361 bit 2 - Tom tom off
362 bit 1 - Cymbal off
363 bit 0 - Hi Hat off
364 */
365 const uint8 kDefaultPercussionMask = 0x20;
366
open()367 int AdLibDriver::open() {
368 if (_isOpen)
369 return MERR_ALREADY_OPEN;
370
371 _isOpen = true;
372
373 _opl = OPL::Config::create();
374 _opl->init();
375 _opl->writeReg(0x1, 0x20); // set bit 5 (enable all waveforms)
376
377 // Reset the OPL registers.
378 for (uint i = 0; i < kNumVoices; ++i) {
379 _opl->writeReg(0xA0 + i, 0); // frequency
380 _opl->writeReg(0xB0 + i, 0); // key on
381 _opl->writeReg(0xC0 + i, 0); // feedback
382 }
383 _opl->writeReg(0xBD, kDefaultPercussionMask);
384
385 initVoices();
386
387 _opl->start(new Common::Functor0Mem<void, AdLibDriver>(this, &AdLibDriver::onTimer));
388 return 0;
389 }
390
close()391 void AdLibDriver::close() {
392 if (!_isOpen)
393 return;
394
395 _isOpen = false;
396
397 delete _opl;
398 }
399
send(uint32 b)400 void AdLibDriver::send(uint32 b) {
401 uint channel = b & 0xf;
402 uint cmd = (b >> 4) & 0xf;
403 uint param1 = (b >> 8) & 0xff;
404 uint param2 = (b >> 16) & 0xff;
405
406 switch (cmd) {
407 case 8:
408 noteOff(channel, param1);
409 break;
410 case 9:
411 // TODO: map volume?
412 noteOn(channel, param1, param2);
413 break;
414 case 11:
415 // controller change
416 switch (param1) {
417 case 1:
418 setModulationWheel(channel, param2);
419 break;
420 case 4:
421 setFootController(channel, param2);
422 break;
423 case 7:
424 setVolume(channel, param2);
425 break;
426 case 123:
427 // all notes off
428 allNotesOff();
429 break;
430 default:
431 break;
432 }
433 break;
434 case 12:
435 // program change
436 _channels[channel]._program = param1;
437 break;
438 case 14:
439 setPitchBend(channel, (param1 | (param2 << 7)) - 0x2000);
440 break;
441 default:
442 break;
443 }
444 }
445
noteOff(uint8 channel,uint8 note)446 void AdLibDriver::noteOff(uint8 channel, uint8 note) {
447 if (channel == 9) {
448 if (note < 35 || note > 81)
449 return;
450
451 _percussionMask &= ~(1 << percussionNotes[note - 35].percussion);
452 _opl->writeReg(0xBD, _percussionMask);
453 return;
454 }
455
456 for (int i = kNumMelodic - 1; i >= 0; --i) {
457 if (_voices[i]._channel != channel)
458 continue;
459 if (_voices[i]._key != note)
460 continue;
461 muteMelodicVoice(i);
462 _voices[i]._used = false;
463 return;
464 }
465
466 //debug(1, "failed to find voice off for channel %d, note %d", channel, note);
467 }
468
noteOn(uint8 channel,uint8 note,uint8 velocity)469 void AdLibDriver::noteOn(uint8 channel, uint8 note, uint8 velocity) {
470 if (channel == 9) {
471 if (note < 35 || note > 81)
472 return;
473
474 const PercussionNote &info = percussionNotes[note - 35];
475 if (!info.valid)
476 return;
477
478 if (note != _notesPerPercussion[info.percussion]) {
479 setupPercussion(info);
480 _notesPerPercussion[info.percussion] = note;
481 }
482
483 playPercussion(channel, info, velocity);
484 return;
485 }
486
487 if (velocity == 0) {
488 noteOff(channel, note);
489 return;
490 }
491
492 // We want to play a note on a melodic (voice) channel.
493
494 // First, look for a voice playing the same note with the same program.
495 for (uint i = 0; i < kNumMelodic; ++i) {
496 if (_voices[i]._channel != channel || _voices[i]._key != note)
497 continue;
498 if (_voices[i]._program != _channels[channel]._program)
499 continue;
500 muteMelodicVoice(i);
501 playMelodicNote(i, channel, note, velocity);
502 return;
503 }
504
505 // The loops below try to start at _lastVoice and find a voice to use.
506 // They ignore _lastVoice itself, and update _lastVoice if they succeed.
507
508 // Then, try finding a melodic voice with the same program.
509 for (uint i = (_lastVoice + 1) % kNumMelodic; i != _lastVoice; i = (i + 1) % kNumMelodic) {
510 if (_voices[i]._used)
511 continue;
512 if (_voices[i]._program != _channels[channel]._program)
513 continue;
514 playMelodicNote(i, channel, note, velocity);
515 _lastVoice = i;
516 return;
517 }
518
519 // Then, try finding a free melodic voice of any kind.
520 for (uint i = (_lastVoice + 1) % kNumMelodic; i != _lastVoice; i = (i + 1) % kNumMelodic) {
521 if (_voices[i]._used)
522 continue;
523 programMelodicVoice(i, _channels[channel]._program);
524 playMelodicNote(i, channel, note, velocity);
525 _lastVoice = i;
526 return;
527 }
528
529 // Then just try finding a melodic voice with the same program,
530 // and steal it.
531 for (uint i = (_lastVoice + 1) % kNumMelodic; i != _lastVoice; i = (i + 1) % kNumMelodic) {
532 if (_voices[i]._program != _channels[channel]._program)
533 continue;
534 muteMelodicVoice(i);
535 playMelodicNote(i, channel, note, velocity);
536 _lastVoice = i;
537 return;
538 }
539
540 // Finally, just take control of the channel used least recently.
541 uint voiceId = 0;
542 uint32 bestTimestamp = 0xffffffff;
543 for (uint i = 0; i < kNumMelodic; ++i)
544 if (bestTimestamp > _voices[i]._timestamp) {
545 voiceId = i;
546 bestTimestamp = _voices[i]._timestamp;
547 }
548
549 //debug(1, "ran out of voices for channel %d, note %d, program %d: reused voice %d", channel, note, _channels[channel]._program, voiceId);
550 programMelodicVoice(voiceId, _channels[channel]._program);
551 playMelodicNote(voiceId, channel, note, velocity);
552 _lastVoice = voiceId;
553 }
554
555 // TODO: this doesn't match original
allNotesOff()556 void AdLibDriver::allNotesOff() {
557 for (uint i = 0; i < kNumMelodic; ++i) {
558 muteMelodicVoice(i);
559 _voices[i]._used = false;
560 }
561
562 _percussionMask = kDefaultPercussionMask;
563 _opl->writeReg(0xBD, kDefaultPercussionMask);
564 }
565
setModulationWheel(uint8 channel,uint8 value)566 void AdLibDriver::setModulationWheel(uint8 channel, uint8 value) {
567 if (value >= 64)
568 _percussionMask |= 0x80;
569 else
570 _percussionMask &= 0x7f;
571
572 _opl->writeReg(0xBD, _percussionMask);
573 }
574
setFootController(uint8 channel,uint8 value)575 void AdLibDriver::setFootController(uint8 channel, uint8 value) {
576 _channels[channel]._pedal = (value >= 64);
577 }
578
setVolume(uint8 channel,uint8 value)579 void AdLibDriver::setVolume(uint8 channel, uint8 value) {
580 _channels[channel]._volume = value;
581 }
582
setPitchBend(uint8 channel,int16 value)583 void AdLibDriver::setPitchBend(uint8 channel, int16 value) {
584 for (uint i = 0; i < kNumMelodic; ++i) {
585 if (_voices[i]._channel != channel || !_voices[i]._used)
586 continue;
587
588 // index into frequency table
589 uint f = 12 + (_voices[i]._key % 12);
590
591 int16 bendAmount = value;
592 if (bendAmount > 0) {
593 // bend up two semitones
594 bendAmount *= (melodicFrequencies[f + 2] - melodicFrequencies[f]);
595 } else {
596 // bend down two semitones
597 bendAmount *= (melodicFrequencies[f] - melodicFrequencies[f - 2]);
598 }
599 bendAmount /= 0x2000;
600 bendAmount += melodicFrequencies[f]; // add the base frequency
601 playNote(i, _voices[i]._octave, bendAmount);
602 _voices[i]._timestamp = g_system->getMillis();
603 }
604 }
605
playNote(uint8 voice,uint8 octave,uint16 frequency)606 void AdLibDriver::playNote(uint8 voice, uint8 octave, uint16 frequency) {
607 /* Percussions are always fed keyOn = 0 even to set the note, as they are activated using the
608 BD register instead. I wonder if they can just be fed the same value as melodic voice and
609 be done with it. */
610 uint8 keyOn = (voice < kNumMelodic) ? 0x20 : 0;
611
612 // key on, octave, high 2 bits of frequency
613 _opl->writeReg(0xB0 + voice, keyOn | ((octave & 7) << 2) | ((frequency >> 8) & 3));
614 // low 8 bits of frequency
615 _opl->writeReg(0xA0 + voice, frequency & 0xff);
616 }
617
programOperatorSimple(uint8 offset,const OPLOperator & op)618 void AdLibDriver::programOperatorSimple(uint8 offset, const OPLOperator &op) {
619 _opl->writeReg(0x40 + offset, op.levels & LEVEL_MASK);
620 _opl->writeReg(0x60 + offset, op.attackDecay);
621 _opl->writeReg(0x80 + offset, op.sustainRelease);
622 }
623
programOperator(uint8 offset,const OPLOperator & op)624 void AdLibDriver::programOperator(uint8 offset, const OPLOperator &op) {
625 _opl->writeReg(0x20 + offset, op.characteristic);
626 _opl->writeReg(0x60 + offset, op.attackDecay);
627 _opl->writeReg(0x80 + offset, op.sustainRelease);
628 _opl->writeReg(0xE0 + offset, op.waveform);
629 _opl->writeReg(0x40 + offset, op.levels);
630 }
631
632 const uint16 adlibLogVolume[] = {
633 0, 37, 58, 73, 85, 95, 103, 110, 116, 121, 127, 131, 135, 139, 143, 146,
634 149, 153, 155, 158, 161, 163, 165, 168, 170, 172, 174, 176, 178, 179, 181, 183,
635 184, 186, 188, 189, 191, 192, 193, 195, 196, 197, 198, 200, 201, 202, 203, 204,
636 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 219,
637 220, 221, 222, 223, 223, 224, 225, 226, 226, 227, 228, 228, 229, 230, 231, 231,
638 232, 233, 233, 234, 234, 235, 236, 236, 237, 237, 238, 239, 239, 240, 240, 241,
639 241, 242, 242, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249,
640 249, 250, 250, 251, 251, 252, 252, 253, 253, 253, 254, 254, 255, 255, 256, 256,
641 256
642 };
643
setOperatorLevel(uint8 offset,const OPLOperator & op,uint8 velocity,uint8 channel,bool forceVolume)644 void AdLibDriver::setOperatorLevel(uint8 offset, const OPLOperator &op, uint8 velocity, uint8 channel, bool forceVolume) {
645 uint8 programLevel = LEVEL_MASK;
646 if (!forceVolume)
647 programLevel -= (op.levels & LEVEL_MASK);
648
649 uint32 noteLevel = adlibLogVolume[velocity];
650 uint32 channelLevel = adlibLogVolume[_channels[channel]._volume];
651 // programLevel comes from the static data and is probably already in the correct logarithmic scale
652 uint32 finalLevel = LEVEL_MASK - ((noteLevel * channelLevel * programLevel) >> 16);
653
654 // high 2 bits are scaling level, the rest is (inversed) volume
655 _opl->writeReg(0x40 + offset, (op.levels & 0xc0) | (finalLevel & 0x3f));
656 }
657
658 const uint8 operatorOffsetsForPercussion[] = {
659 0x11, // hi-hat
660 0x15, // cymbal
661 0x12, // tom tom
662 0x14 // snare drum
663 };
664
setupPercussion(const PercussionNote & note)665 void AdLibDriver::setupPercussion(const PercussionNote ¬e) {
666 if (note.percussion < 4) {
667 // simple percussion (1 operator)
668
669 // turn off relevant percussion
670 _percussionMask &= ~(1 << note.percussion);
671 _opl->writeReg(0xBD, _percussionMask);
672
673 programOperatorSimple(operatorOffsetsForPercussion[note.percussion], note.op[0]);
674 return;
675 }
676
677 // bass drum (2 operators)
678
679 // turn off bass drum
680 _percussionMask &= ~(0x10);
681 _opl->writeReg(0xBD, _percussionMask);
682
683 programOperator(0x10, note.op[0]);
684 programOperator(0x13, note.op[1]);
685
686 _opl->writeReg(0xC0 + 6, note.feedbackAlgo);
687 }
688
playPercussion(uint8 channel,const PercussionNote & note,uint8 velocity)689 void AdLibDriver::playPercussion(uint8 channel, const PercussionNote ¬e, uint8 velocity) {
690 if (note.percussion < 4) {
691 // simple percussion (1 operator)
692
693 // turn off relevant percussion
694 _percussionMask &= ~(1 << note.percussion);
695 _opl->writeReg(0xBD, _percussionMask);
696
697 setOperatorLevel(operatorOffsetsForPercussion[note.percussion], note.op[0], velocity, channel, true);
698
699 if (note.percussion == 2) {
700 // tom tom
701 playNote(8, note.octave, note.frequency);
702 } else if (note.percussion == 3) {
703 // snare drum
704 playNote(7, note.octave, note.frequency);
705 }
706
707 // turn on relevant percussion
708 _percussionMask |= (1 << note.percussion);
709 _opl->writeReg(0xBD, _percussionMask);
710 return;
711 }
712
713 // turn off bass drum
714 _percussionMask &= ~(0x10);
715 _opl->writeReg(0xBD, _percussionMask);
716
717 if (note.feedbackAlgo & 1) {
718 // operators 1 and 2 in additive synthesis
719 setOperatorLevel(0x10, note.op[0], velocity, channel, true);
720 setOperatorLevel(0x13, note.op[1], velocity, channel, true);
721 } else {
722 // operator 2 is modulating operator 1
723 setOperatorLevel(0x13, note.op[1], velocity, channel, true);
724 }
725
726 playNote(6, note.octave, note.frequency);
727
728 // turn on bass drum
729 _percussionMask |= 0x10;
730 _opl->writeReg(0xBD, _percussionMask);
731 }
732
733 const uint8 offset1ForMelodic[kNumVoices] = { 0x0, 0x1, 0x2, 0x8, 0x9, 0xa, 0x10, 0x11, 0x12 };
734 const uint8 offset2ForMelodic[kNumVoices] = { 0x3, 0x4, 0x5, 0xb, 0xc, 0xd, 0x13, 0x14, 0x15 };
735
programMelodicVoice(uint8 voice,uint8 program)736 void AdLibDriver::programMelodicVoice(uint8 voice, uint8 program) {
737 assert(program < 128);
738 assert(voice < kNumMelodic);
739
740 const MelodicProgram &info = melodicPrograms[program];
741 uint8 offset1 = offset1ForMelodic[voice];
742 uint8 offset2 = offset2ForMelodic[voice];
743
744 // Start at lowest volume.
745 _opl->writeReg(0x40 + offset1, LEVEL_MASK);
746 _opl->writeReg(0x40 + offset2, LEVEL_MASK);
747
748 muteMelodicVoice(voice);
749
750 programOperator(offset1, info.op[0]);
751 programOperator(offset2, info.op[1]);
752
753 _opl->writeReg(0xC0 + voice, info.feedbackAlgo);
754 }
755
playMelodicNote(uint8 voice,uint8 channel,uint8 note,uint8 velocity)756 void AdLibDriver::playMelodicNote(uint8 voice, uint8 channel, uint8 note, uint8 velocity) {
757 assert(voice < kNumMelodic);
758
759 uint8 octave = note / 12;
760 uint8 f = 12 + (note % 12);
761
762 if (octave > 7)
763 octave = 7;
764
765 const MelodicProgram &info = melodicPrograms[_channels[channel]._program];
766 uint8 offset1 = offset1ForMelodic[voice];
767 uint8 offset2 = offset2ForMelodic[voice];
768
769 if (info.feedbackAlgo & 1) {
770 setOperatorLevel(offset1, info.op[0], velocity, channel, false);
771 setOperatorLevel(offset2, info.op[1], velocity, channel, false);
772 } else {
773 setOperatorLevel(offset2, info.op[1], velocity, channel, true);
774 }
775
776 playNote(voice, octave, melodicFrequencies[f]);
777
778 _voices[voice]._program = _channels[channel]._program;
779 _voices[voice]._key = note;
780 _voices[voice]._channel = channel;
781 _voices[voice]._timestamp = g_system->getMillis();
782 _voices[voice]._frequency = melodicFrequencies[f];
783 _voices[voice]._octave = octave;
784 _voices[voice]._used = true;
785 }
786
muteMelodicVoice(uint8 voice)787 void AdLibDriver::muteMelodicVoice(uint8 voice) {
788 _opl->writeReg(0xB0 + voice, 0 | ((_voices[voice]._octave & 7) << 2) | ((_voices[voice]._frequency >> 8) & 3));
789 }
790
allocateChannel()791 MidiChannel *AdLibDriver::allocateChannel() {
792 for (uint i = 0; i < 16; ++i) {
793 if (i == 9)
794 continue;
795
796 if (_channels[i].allocate())
797 return &_channels[i];
798 }
799
800 return NULL;
801 }
802
onTimer()803 void AdLibDriver::onTimer() {
804 if (_adlibTimerProc)
805 (*_adlibTimerProc)(_adlibTimerParam);
806 }
807
initVoices()808 void AdLibDriver::initVoices() {
809 _percussionMask = kDefaultPercussionMask;
810 _opl->writeReg(0xBD, _percussionMask);
811
812 for (uint i = 0; i < 16; ++i)
813 _channels[i].reset();
814
815 for (uint i = 0; i < kNumMelodic; ++i) {
816 _voices[i]._key = 0xff;
817 _voices[i]._program = 0xff;
818 _voices[i]._channel = 0xff;
819 _voices[i]._timestamp = 0;
820 _voices[i]._frequency = 0;
821 _voices[i]._octave = 0;
822 _voices[i]._used = false;
823 }
824
825 for (uint i = 0; i < kNumPercussion; ++i)
826 _notesPerPercussion[i] = 0xff;
827
828 _lastVoice = 0;
829 }
830
831 } // namespace Parallaction
832