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 music.
27 //
28
29
30 #include "bstone_adlib_music_decoder.h"
31 #include <cstdint>
32 #include "bstone_endian.h"
33
34
35 namespace bstone {
36
37
AdlibMusicDecoder()38 AdlibMusicDecoder::AdlibMusicDecoder() :
39 commands_count_(),
40 command_index_(),
41 samples_per_tick_(),
42 remains_count_()
43 {
44 }
45
46 // (virtual)
~AdlibMusicDecoder()47 AdlibMusicDecoder::~AdlibMusicDecoder()
48 {
49 uninitialize();
50 }
51
52 // (virtual)
initialize(const void * raw_data,int raw_size,int dst_rate)53 bool AdlibMusicDecoder::initialize(
54 const void* raw_data,
55 int raw_size,
56 int dst_rate)
57 {
58 if (!AdlibDecoder::initialize(
59 raw_data,
60 raw_size,
61 dst_rate))
62 {
63 return false;
64 }
65
66 reader_.open(raw_data, raw_size);
67
68 int commands_size = bstone::Endian::le(reader_.read_u16());
69
70 if ((commands_size % 4) != 0) {
71 return false;
72 }
73
74 if ((commands_size + 2) > raw_size) {
75 return false;
76 }
77
78 command_index_ = 0;
79 commands_count_ = commands_size / 4;
80
81 samples_per_tick_ = emulator_.get_sample_rate() / get_tick_rate();
82 remains_count_ = 0;
83
84 int ticks_count = 0;
85
86 for (int i = 0; i < commands_count_; ++i) {
87 reader_.skip(2);
88 ticks_count += bstone::Endian::le(reader_.read_u16());
89 }
90
91 set_dst_length_in_samples(ticks_count * samples_per_tick_);
92
93 reader_.set_position(2);
94
95 set_is_initialized(true);
96
97 return true;
98 }
99
100 // (virtual)
uninitialize()101 void AdlibMusicDecoder::uninitialize()
102 {
103 reader_.close();
104 commands_count_ = 0;
105 command_index_ = 0;
106 samples_per_tick_ = 0;
107 remains_count_ = 0;
108
109 AdlibDecoder::uninitialize();
110 }
111
112 // (virtual)
reset()113 bool AdlibMusicDecoder::reset()
114 {
115 if (!AdlibDecoder::reset()) {
116 return false;
117 }
118
119 reader_.set_position(2);
120
121 command_index_ = 0;
122 remains_count_ = 0;
123
124 return true;
125 }
126
127 // (virtual)
clone()128 AudioDecoder* AdlibMusicDecoder::clone()
129 {
130 return new AdlibMusicDecoder(*this);
131 }
132
133 // (virtual)
decode(int dst_count,int16_t * dst_data)134 int AdlibMusicDecoder::decode(
135 int dst_count,
136 int16_t* dst_data)
137 {
138 if (!is_initialized()) {
139 return 0;
140 }
141
142 if (dst_count < 1) {
143 return 0;
144 }
145
146 if (!dst_data) {
147 return 0;
148 }
149
150 if (command_index_ == commands_count_ && remains_count_ == 0) {
151 return 0;
152 }
153
154 int decoded_samples_count = 0;
155
156 for (bool quit = false; !quit; ) {
157 if (remains_count_ > 0) {
158 int count = std::min(dst_count, remains_count_);
159
160 emulator_.generate(count, dst_data);
161
162 dst_data += count;
163 dst_count -= count;
164 remains_count_ -= count;
165 decoded_samples_count += count;
166 } else {
167 int delay = 0;
168
169 while (command_index_ < commands_count_ && delay == 0) {
170 int command_port = reader_.read_u8();
171 int command_value = reader_.read_u8();
172 delay = bstone::Endian::le(reader_.read_u16());
173
174 emulator_.write(command_port, command_value);
175 ++command_index_;
176 }
177
178 if (delay > 0) {
179 remains_count_ = delay * samples_per_tick_;
180 }
181 }
182
183 quit =
184 (command_index_ == commands_count_ && remains_count_ == 0) ||
185 dst_count == 0;
186 }
187
188 return decoded_samples_count;
189 }
190
191 // (static)
get_tick_rate()192 int AdlibMusicDecoder::get_tick_rate()
193 {
194 return 700;
195 }
196
197
198 } // bstone
199