1 /*
2 BStone: A Source port of
3 Blake Stone: Aliens of Gold and Blake Stone: Planet Strike
4
5 Copyright (c) 1992-2013 Apogee Entertainment, LLC
6 Copyright (c) 2013-2015 Boris I. Bendovsky (bibendovsky@hotmail.com)
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the
20 Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 */
23
24
25 //
26 // A decoder for AdLib sound effects.
27 //
28
29
30 #include "bstone_adlib_sfx_decoder.h"
31 #include <cstdint>
32 #include "bstone_endian.h"
33
34
35 namespace bstone {
36
37
reset()38 void AdlibSfxDecoder::Instrument::reset()
39 {
40 m_char = 0;
41 c_char = 0;
42 m_scale = 0;
43 c_scale = 0;
44 m_attack = 0;
45 c_attack = 0;
46 m_sus = 0;
47 c_sus = 0;
48 m_wave = 0;
49 c_wave = 0;
50 }
51
AdlibSfxDecoder()52 AdlibSfxDecoder::AdlibSfxDecoder() :
53 commands_count_(),
54 command_index_(),
55 samples_per_tick_(),
56 remains_count_(),
57 hf_()
58 {
59 }
60
61 // (virtual)
~AdlibSfxDecoder()62 AdlibSfxDecoder::~AdlibSfxDecoder()
63 {
64 uninitialize();
65 }
66
67 // (virtual)
initialize(const void * raw_data,int raw_size,int dst_rate)68 bool AdlibSfxDecoder::initialize(
69 const void* raw_data,
70 int raw_size,
71 int dst_rate)
72 {
73 if (!AdlibDecoder::initialize(
74 raw_data,
75 raw_size,
76 dst_rate))
77 {
78 return false;
79 }
80
81 reader_.open(raw_data, raw_size);
82
83 int sfx_length = bstone::Endian::le(reader_.read_s32());
84
85 if (sfx_length <= 0) {
86 return false;
87 }
88
89 if ((sfx_length + get_header_size()) >= raw_size) {
90 return false;
91 }
92
93 // Skip priority.
94 reader_.skip(2);
95
96 instrument_.m_char = reader_.read_u8();
97 instrument_.c_char = reader_.read_u8();
98 instrument_.m_scale = reader_.read_u8();
99 instrument_.c_scale = reader_.read_u8();
100 instrument_.m_attack = reader_.read_u8();
101 instrument_.c_attack = reader_.read_u8();
102 instrument_.m_sus = reader_.read_u8();
103 instrument_.c_sus = reader_.read_u8();
104 instrument_.m_wave = reader_.read_u8();
105 instrument_.c_wave = reader_.read_u8();
106
107 // Skip nConn, voice, mode and 3 unused octets
108 reader_.skip(6);
109
110 if (instrument_.m_sus == 0 && instrument_.c_sus == 0) {
111 return false;
112 }
113
114 hf_ = reader_.read_u8();
115 hf_ = ((hf_ & 7) << 2) | 0x20;
116
117 initialize_instrument();
118
119 command_index_ = 0;
120 commands_count_ = sfx_length;
121 samples_per_tick_ = emulator_.get_sample_rate() / get_tick_rate();
122 set_dst_length_in_samples(samples_per_tick_ * sfx_length);
123 remains_count_ = 0;
124
125 set_is_initialized(true);
126
127 return true;
128 }
129
130 // (virtual)
uninitialize()131 void AdlibSfxDecoder::uninitialize()
132 {
133 reader_.close();
134 instrument_.reset();
135 commands_count_ = 0;
136 command_index_ = 0;
137 samples_per_tick_ = 0;
138 remains_count_ = 0;
139 hf_ = 0;
140
141 AdlibDecoder::uninitialize();
142 }
143
144 // (virtual)
reset()145 bool AdlibSfxDecoder::reset()
146 {
147 if (!AdlibDecoder::reset()) {
148 return false;
149 }
150
151 initialize_instrument();
152
153 command_index_ = 0;
154 remains_count_ = 0;
155
156 reader_.set_position(get_header_size());
157
158 return true;
159 }
160
161 // (virtual)
clone()162 AudioDecoder* AdlibSfxDecoder::clone()
163 {
164 return new AdlibSfxDecoder(*this);
165 }
166
167 // (virtual)
decode(int dst_count,int16_t * dst_data)168 int AdlibSfxDecoder::decode(
169 int dst_count,
170 int16_t* dst_data)
171 {
172 if (!is_initialized()) {
173 return 0;
174 }
175
176 if (dst_count < 1) {
177 return 0;
178 }
179
180 if (!dst_data) {
181 return 0;
182 }
183
184 if (command_index_ == commands_count_ && remains_count_ == 0) {
185 return 0;
186 }
187
188 int decoded_samples_count = 0;
189
190 for (bool quit = false; !quit; ) {
191 if (remains_count_ > 0) {
192 int count = std::min(dst_count, remains_count_);
193
194 emulator_.generate(count, dst_data);
195
196 dst_data += count;
197 dst_count -= count;
198 remains_count_ -= count;
199 decoded_samples_count += count;
200 } else {
201 if (command_index_ < commands_count_) {
202 int lf = reader_.read_u8();
203
204 if (lf > 0) {
205 emulator_.write(AL_FREQ_L, lf);
206 emulator_.write(AL_FREQ_H, hf_);
207 } else
208 emulator_.write(AL_FREQ_H, 0x00);
209
210 ++command_index_;
211
212 remains_count_ = samples_per_tick_;
213 }
214 }
215
216 quit =
217 (command_index_ == commands_count_ && remains_count_ == 0) ||
218 dst_count == 0;
219 }
220
221 return decoded_samples_count;
222 }
223
initialize_instrument()224 void AdlibSfxDecoder::initialize_instrument()
225 {
226 // carrier
227 const int c = 3;
228
229 // modifier
230 const int m = 0;
231
232 emulator_.write(m + AL_CHAR, instrument_.m_char);
233 emulator_.write(m + AL_SCALE, instrument_.m_scale);
234 emulator_.write(m + AL_ATTACK, instrument_.m_attack);
235 emulator_.write(m + AL_SUS, instrument_.m_sus);
236 emulator_.write(m + AL_WAVE, instrument_.m_wave);
237 emulator_.write(c + AL_CHAR, instrument_.c_char);
238 emulator_.write(c + AL_SCALE, instrument_.c_scale);
239 emulator_.write(c + AL_ATTACK, instrument_.c_attack);
240 emulator_.write(c + AL_SUS, instrument_.c_sus);
241 emulator_.write(c + AL_WAVE, instrument_.c_wave);
242
243 // AL_FEED_CON
244 emulator_.write(AL_FEED_CON, 0);
245 }
246
247 // (static)
get_tick_rate()248 int AdlibSfxDecoder::get_tick_rate()
249 {
250 return 140;
251 }
252
253 // (static)
get_header_size()254 int AdlibSfxDecoder::get_header_size()
255 {
256 return 23;
257 }
258
259
260 } // bstone
261