1 /*************************************************************************/
2 /* audio_stream_mpc.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30 #include "audio_stream_mpc.h"
31
_open_file()32 Error AudioStreamPlaybackMPC::_open_file() {
33
34 if (f) {
35 memdelete(f);
36 f = NULL;
37 }
38 Error err;
39 //printf("mpc open file %ls\n", file.c_str());
40 f = FileAccess::open(file, FileAccess::READ, &err);
41
42 if (err) {
43 f = NULL;
44 ERR_FAIL_V(err);
45 return err;
46 }
47
48 //printf("file size is %i\n", f->get_len());
49 //f->seek_end(0);
50 streamlen = f->get_len();
51 //f->seek(0);
52 if (streamlen <= 0) {
53 memdelete(f);
54 f = NULL;
55 ERR_FAIL_V(ERR_INVALID_DATA);
56 }
57
58 data_ofs = 0;
59 if (preload) {
60
61 data.resize(streamlen);
62 DVector<uint8_t>::Write w = data.write();
63 f->get_buffer(&w[0], streamlen);
64 memdelete(f);
65 f = NULL;
66 }
67
68 return OK;
69 }
70
_close_file()71 void AudioStreamPlaybackMPC::_close_file() {
72
73 if (f) {
74 memdelete(f);
75 f = NULL;
76 }
77 data.resize(0);
78 streamlen = 0;
79 data_ofs = 0;
80 }
81
_read_file(void * p_dst,int p_bytes)82 int AudioStreamPlaybackMPC::_read_file(void *p_dst, int p_bytes) {
83
84 if (f)
85 return f->get_buffer((uint8_t *)p_dst, p_bytes);
86
87 DVector<uint8_t>::Read r = data.read();
88 if (p_bytes + data_ofs > streamlen) {
89 p_bytes = streamlen - data_ofs;
90 }
91
92 copymem(p_dst, &r[data_ofs], p_bytes);
93 //print_line("read file: "+itos(p_bytes));
94 data_ofs += p_bytes;
95 return p_bytes;
96 }
97
_seek_file(int p_pos)98 bool AudioStreamPlaybackMPC::_seek_file(int p_pos) {
99
100 if (p_pos < 0 || p_pos > streamlen)
101 return false;
102
103 if (f) {
104 f->seek(p_pos);
105 return true;
106 }
107
108 //print_line("read file to: "+itos(p_pos));
109 data_ofs = p_pos;
110 return true;
111 }
_tell_file() const112 int AudioStreamPlaybackMPC::_tell_file() const {
113
114 if (f)
115 return f->get_pos();
116
117 //print_line("tell file, get: "+itos(data_ofs));
118 return data_ofs;
119 }
120
_sizeof_file() const121 int AudioStreamPlaybackMPC::_sizeof_file() const {
122
123 //print_line("sizeof file, get: "+itos(streamlen));
124 return streamlen;
125 }
126
_canseek_file() const127 bool AudioStreamPlaybackMPC::_canseek_file() const {
128
129 //print_line("canseek file, get true");
130 return true;
131 }
132
133 /////////////////////
134
_mpc_read(mpc_reader * p_reader,void * p_dst,mpc_int32_t p_bytes)135 mpc_int32_t AudioStreamPlaybackMPC::_mpc_read(mpc_reader *p_reader, void *p_dst, mpc_int32_t p_bytes) {
136
137 AudioStreamPlaybackMPC *smpc = (AudioStreamPlaybackMPC *)p_reader->data;
138 return smpc->_read_file(p_dst, p_bytes);
139 }
140
_mpc_seek(mpc_reader * p_reader,mpc_int32_t p_offset)141 mpc_bool_t AudioStreamPlaybackMPC::_mpc_seek(mpc_reader *p_reader, mpc_int32_t p_offset) {
142
143 AudioStreamPlaybackMPC *smpc = (AudioStreamPlaybackMPC *)p_reader->data;
144 return smpc->_seek_file(p_offset);
145 }
_mpc_tell(mpc_reader * p_reader)146 mpc_int32_t AudioStreamPlaybackMPC::_mpc_tell(mpc_reader *p_reader) {
147
148 AudioStreamPlaybackMPC *smpc = (AudioStreamPlaybackMPC *)p_reader->data;
149 return smpc->_tell_file();
150 }
_mpc_get_size(mpc_reader * p_reader)151 mpc_int32_t AudioStreamPlaybackMPC::_mpc_get_size(mpc_reader *p_reader) {
152
153 AudioStreamPlaybackMPC *smpc = (AudioStreamPlaybackMPC *)p_reader->data;
154 return smpc->_sizeof_file();
155 }
_mpc_canseek(mpc_reader * p_reader)156 mpc_bool_t AudioStreamPlaybackMPC::_mpc_canseek(mpc_reader *p_reader) {
157
158 AudioStreamPlaybackMPC *smpc = (AudioStreamPlaybackMPC *)p_reader->data;
159 return smpc->_canseek_file();
160 }
161
mix(int16_t * p_bufer,int p_frames)162 int AudioStreamPlaybackMPC::mix(int16_t *p_bufer, int p_frames) {
163
164 if (!active || paused)
165 return 0;
166
167 int todo = p_frames;
168
169 while (todo > MPC_DECODER_BUFFER_LENGTH / si.channels) {
170
171 mpc_frame_info frame;
172
173 frame.buffer = sample_buffer;
174
175 mpc_status err = mpc_demux_decode(demux, &frame);
176 if (frame.bits != -1) {
177
178 int16_t *dst_buff = p_bufer;
179
180 #ifdef MPC_FIXED_POINT
181
182 for (int i = 0; i < frame.samples * si.channels; i++) {
183 int tmp = sample_buffer[i] >> MPC_FIXED_POINT_FRACTPART;
184 if (tmp > ((1 << 15) - 1)) tmp = ((1 << 15) - 1);
185 if (tmp < -(1 << 15)) tmp = -(1 << 15);
186 dst_buff[i] = tmp;
187 }
188 #else
189 for (int i = 0; i < frame.samples * si.channels; i++) {
190
191 int tmp = Math::fast_ftoi(sample_buffer[i] * 32767.0);
192 if (tmp > ((1 << 15) - 1)) tmp = ((1 << 15) - 1);
193 if (tmp < -(1 << 15)) tmp = -(1 << 15);
194 dst_buff[i] = tmp;
195 }
196
197 #endif
198
199 int frames = frame.samples;
200 p_bufer += si.channels * frames;
201 todo -= frames;
202 } else {
203
204 if (err != MPC_STATUS_OK) {
205
206 stop();
207 ERR_PRINT("Error decoding MPC");
208 break;
209 } else {
210
211 //finished
212 if (!loop) {
213 stop();
214 break;
215 } else {
216
217 loops++;
218 mpc_demux_exit(demux);
219 _seek_file(0);
220 demux = mpc_demux_init(&reader);
221 //do loop somehow
222 }
223 }
224 }
225 }
226
227 return p_frames - todo;
228 }
229
_reload()230 Error AudioStreamPlaybackMPC::_reload() {
231
232 ERR_FAIL_COND_V(demux != NULL, ERR_FILE_ALREADY_IN_USE);
233
234 Error err = _open_file();
235 ERR_FAIL_COND_V(err != OK, ERR_CANT_OPEN);
236
237 demux = mpc_demux_init(&reader);
238 ERR_FAIL_COND_V(!demux, ERR_CANT_CREATE);
239 mpc_demux_get_info(demux, &si);
240
241 return OK;
242 }
243
set_file(const String & p_file)244 void AudioStreamPlaybackMPC::set_file(const String &p_file) {
245
246 file = p_file;
247
248 Error err = _open_file();
249 ERR_FAIL_COND(err != OK);
250 demux = mpc_demux_init(&reader);
251 ERR_FAIL_COND(!demux);
252 mpc_demux_get_info(demux, &si);
253 stream_min_size = MPC_DECODER_BUFFER_LENGTH * 2 / si.channels;
254 stream_rate = si.sample_freq;
255 stream_channels = si.channels;
256
257 mpc_demux_exit(demux);
258 demux = NULL;
259 _close_file();
260 }
261
get_file() const262 String AudioStreamPlaybackMPC::get_file() const {
263
264 return file;
265 }
266
play(float p_offset)267 void AudioStreamPlaybackMPC::play(float p_offset) {
268
269 if (active)
270 stop();
271 active = false;
272
273 Error err = _open_file();
274 ERR_FAIL_COND(err != OK);
275 if (_reload() != OK)
276 return;
277 active = true;
278 loops = 0;
279 }
280
stop()281 void AudioStreamPlaybackMPC::stop() {
282
283 if (!active)
284 return;
285 if (demux) {
286 mpc_demux_exit(demux);
287 demux = NULL;
288 }
289 _close_file();
290 active = false;
291 }
is_playing() const292 bool AudioStreamPlaybackMPC::is_playing() const {
293
294 return active;
295 }
296
set_loop(bool p_enable)297 void AudioStreamPlaybackMPC::set_loop(bool p_enable) {
298
299 loop = p_enable;
300 }
has_loop() const301 bool AudioStreamPlaybackMPC::has_loop() const {
302
303 return loop;
304 }
305
get_length() const306 float AudioStreamPlaybackMPC::get_length() const {
307
308 return 0;
309 }
310
get_stream_name() const311 String AudioStreamPlaybackMPC::get_stream_name() const {
312
313 return "";
314 }
315
get_loop_count() const316 int AudioStreamPlaybackMPC::get_loop_count() const {
317
318 return 0;
319 }
320
get_pos() const321 float AudioStreamPlaybackMPC::get_pos() const {
322
323 return 0;
324 }
seek_pos(float p_time)325 void AudioStreamPlaybackMPC::seek_pos(float p_time) {
326 }
327
_bind_methods()328 void AudioStreamPlaybackMPC::_bind_methods() {
329
330 ObjectTypeDB::bind_method(_MD("set_file", "name"), &AudioStreamPlaybackMPC::set_file);
331 ObjectTypeDB::bind_method(_MD("get_file"), &AudioStreamPlaybackMPC::get_file);
332
333 ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "file", PROPERTY_HINT_FILE, "mpc"), _SCS("set_file"), _SCS("get_file"));
334 }
335
AudioStreamPlaybackMPC()336 AudioStreamPlaybackMPC::AudioStreamPlaybackMPC() {
337
338 preload = false;
339 f = NULL;
340 streamlen = 0;
341 data_ofs = 0;
342 active = false;
343 paused = false;
344 loop = false;
345 demux = NULL;
346 reader.data = this;
347 reader.read = _mpc_read;
348 reader.seek = _mpc_seek;
349 reader.tell = _mpc_tell;
350 reader.get_size = _mpc_get_size;
351 reader.canseek = _mpc_canseek;
352 loops = 0;
353 }
354
~AudioStreamPlaybackMPC()355 AudioStreamPlaybackMPC::~AudioStreamPlaybackMPC() {
356
357 stop();
358
359 if (f)
360 memdelete(f);
361 }
362
load(const String & p_path,const String & p_original_path,Error * r_error)363 RES ResourceFormatLoaderAudioStreamMPC::load(const String &p_path, const String &p_original_path, Error *r_error) {
364 if (r_error)
365 *r_error = OK; //streamed so it will always work..
366 AudioStreamMPC *mpc_stream = memnew(AudioStreamMPC);
367 mpc_stream->set_file(p_path);
368 return Ref<AudioStreamMPC>(mpc_stream);
369 }
370
get_recognized_extensions(List<String> * p_extensions) const371 void ResourceFormatLoaderAudioStreamMPC::get_recognized_extensions(List<String> *p_extensions) const {
372
373 p_extensions->push_back("mpc");
374 }
handles_type(const String & p_type) const375 bool ResourceFormatLoaderAudioStreamMPC::handles_type(const String &p_type) const {
376
377 return (p_type == "AudioStream") || (p_type == "AudioStreamMPC");
378 }
379
get_resource_type(const String & p_path) const380 String ResourceFormatLoaderAudioStreamMPC::get_resource_type(const String &p_path) const {
381
382 if (p_path.extension().to_lower() == "mpc")
383 return "AudioStreamMPC";
384 return "";
385 }
386