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