Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/resources/audio_stream_wav.cpp
9896 views
1
/**************************************************************************/
2
/* audio_stream_wav.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
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
31
#include "audio_stream_wav.h"
32
33
#include "core/io/file_access_memory.h"
34
#include "core/io/marshalls.h"
35
36
const float TRIM_DB_LIMIT = -50;
37
const int TRIM_FADE_OUT_FRAMES = 500;
38
39
void AudioStreamPlaybackWAV::start(double p_from_pos) {
40
if (base->format == AudioStreamWAV::FORMAT_IMA_ADPCM) {
41
//no seeking in IMA_ADPCM
42
for (int i = 0; i < 2; i++) {
43
ima_adpcm[i].step_index = 0;
44
ima_adpcm[i].predictor = 0;
45
ima_adpcm[i].loop_step_index = 0;
46
ima_adpcm[i].loop_predictor = 0;
47
ima_adpcm[i].last_nibble = -1;
48
ima_adpcm[i].loop_pos = 0x7FFFFFFF;
49
ima_adpcm[i].window_ofs = 0;
50
}
51
52
offset = 0;
53
} else {
54
seek(p_from_pos);
55
}
56
57
sign = 1;
58
active = true;
59
begin_resample();
60
}
61
62
void AudioStreamPlaybackWAV::stop() {
63
active = false;
64
}
65
66
bool AudioStreamPlaybackWAV::is_playing() const {
67
return active;
68
}
69
70
int AudioStreamPlaybackWAV::get_loop_count() const {
71
return 0;
72
}
73
74
double AudioStreamPlaybackWAV::get_playback_position() const {
75
return double(offset) / base->mix_rate;
76
}
77
78
void AudioStreamPlaybackWAV::seek(double p_time) {
79
if (base->format == AudioStreamWAV::FORMAT_IMA_ADPCM) {
80
return; //no seeking in ima-adpcm
81
}
82
83
double max = base->get_length();
84
if (p_time < 0) {
85
p_time = 0;
86
} else if (p_time >= max) {
87
p_time = max - 0.001;
88
}
89
90
offset = int64_t(p_time * base->mix_rate);
91
}
92
93
template <typename Depth, bool is_stereo, bool is_ima_adpcm, bool is_qoa>
94
void AudioStreamPlaybackWAV::decode_samples(const Depth *p_src, AudioFrame *p_dst, int64_t &p_offset, int8_t &p_increment, uint32_t p_amount, IMA_ADPCM_State *p_ima_adpcm, QOA_State *p_qoa) {
95
// this function will be compiled branchless by any decent compiler
96
97
int32_t final = 0, final_r = 0;
98
while (p_amount) {
99
p_amount--;
100
int64_t pos = p_offset << (is_stereo && !is_ima_adpcm && !is_qoa ? 1 : 0);
101
102
if (is_ima_adpcm) {
103
int64_t sample_pos = pos + p_ima_adpcm[0].window_ofs;
104
105
while (sample_pos > p_ima_adpcm[0].last_nibble) {
106
static const int16_t _ima_adpcm_step_table[89] = {
107
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
108
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
109
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
110
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
111
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
112
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
113
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
114
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
115
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
116
};
117
118
static const int8_t _ima_adpcm_index_table[16] = {
119
-1, -1, -1, -1, 2, 4, 6, 8,
120
-1, -1, -1, -1, 2, 4, 6, 8
121
};
122
123
for (int i = 0; i < (is_stereo ? 2 : 1); i++) {
124
int16_t nibble, diff, step;
125
126
p_ima_adpcm[i].last_nibble++;
127
128
uint8_t nbb = p_src[(p_ima_adpcm[i].last_nibble >> 1) * (is_stereo ? 2 : 1) + i];
129
nibble = (p_ima_adpcm[i].last_nibble & 1) ? (nbb >> 4) : (nbb & 0xF);
130
step = _ima_adpcm_step_table[p_ima_adpcm[i].step_index];
131
132
p_ima_adpcm[i].step_index += _ima_adpcm_index_table[nibble];
133
if (p_ima_adpcm[i].step_index < 0) {
134
p_ima_adpcm[i].step_index = 0;
135
}
136
if (p_ima_adpcm[i].step_index > 88) {
137
p_ima_adpcm[i].step_index = 88;
138
}
139
140
diff = step >> 3;
141
if (nibble & 1) {
142
diff += step >> 2;
143
}
144
if (nibble & 2) {
145
diff += step >> 1;
146
}
147
if (nibble & 4) {
148
diff += step;
149
}
150
if (nibble & 8) {
151
diff = -diff;
152
}
153
154
p_ima_adpcm[i].predictor += diff;
155
if (p_ima_adpcm[i].predictor < -0x8000) {
156
p_ima_adpcm[i].predictor = -0x8000;
157
} else if (p_ima_adpcm[i].predictor > 0x7FFF) {
158
p_ima_adpcm[i].predictor = 0x7FFF;
159
}
160
161
/* store loop if there */
162
if (p_ima_adpcm[i].last_nibble == p_ima_adpcm[i].loop_pos) {
163
p_ima_adpcm[i].loop_step_index = p_ima_adpcm[i].step_index;
164
p_ima_adpcm[i].loop_predictor = p_ima_adpcm[i].predictor;
165
}
166
167
//printf("%i - %i - pred %i\n",int(p_ima_adpcm[i].last_nibble),int(nibble),int(p_ima_adpcm[i].predictor));
168
}
169
}
170
171
final = p_ima_adpcm[0].predictor;
172
if (is_stereo) {
173
final_r = p_ima_adpcm[1].predictor;
174
}
175
176
} else if (is_qoa) {
177
uint32_t new_data_ofs = 8 + pos / QOA_FRAME_LEN * p_qoa->frame_len;
178
179
if (p_qoa->data_ofs != new_data_ofs) {
180
p_qoa->data_ofs = new_data_ofs;
181
const uint8_t *ofs_src = (uint8_t *)p_src + p_qoa->data_ofs;
182
qoa_decode_frame(ofs_src, p_qoa->frame_len, &p_qoa->desc, p_qoa->dec.ptr(), &p_qoa->dec_len);
183
}
184
185
uint32_t dec_idx = pos % QOA_FRAME_LEN << (is_stereo ? 1 : 0);
186
187
final = p_qoa->dec[dec_idx];
188
if (is_stereo) {
189
final_r = p_qoa->dec[dec_idx + 1];
190
}
191
192
} else {
193
final = p_src[pos];
194
if (is_stereo) {
195
final_r = p_src[pos + 1];
196
}
197
if constexpr (sizeof(Depth) == 1) { /* conditions will not exist anymore when compiled! */
198
final <<= 8;
199
if (is_stereo) {
200
final_r <<= 8;
201
}
202
}
203
}
204
205
if (!is_stereo) {
206
final_r = final; //copy to right channel if stereo
207
}
208
209
p_dst->left = final / 32767.0;
210
p_dst->right = final_r / 32767.0;
211
p_dst++;
212
213
p_offset += p_increment;
214
}
215
}
216
217
int AudioStreamPlaybackWAV::_mix_internal(AudioFrame *p_buffer, int p_frames) {
218
if (base->data.is_empty() || !active) {
219
for (int i = 0; i < p_frames; i++) {
220
p_buffer[i] = AudioFrame(0, 0);
221
}
222
return 0;
223
}
224
225
uint32_t len = base->data_bytes;
226
switch (base->format) {
227
case AudioStreamWAV::FORMAT_8_BITS:
228
len /= 1;
229
break;
230
case AudioStreamWAV::FORMAT_16_BITS:
231
len /= 2;
232
break;
233
case AudioStreamWAV::FORMAT_IMA_ADPCM:
234
len *= 2;
235
break;
236
case AudioStreamWAV::FORMAT_QOA:
237
len = qoa.desc.samples * qoa.desc.channels;
238
break;
239
}
240
241
if (base->stereo) {
242
len /= 2;
243
}
244
245
int64_t loop_begin = base->loop_begin;
246
int64_t loop_end = base->loop_end;
247
int64_t begin_limit = (base->loop_mode != AudioStreamWAV::LOOP_DISABLED) ? loop_begin : 0;
248
int64_t end_limit = (base->loop_mode != AudioStreamWAV::LOOP_DISABLED) ? loop_end : len - 1;
249
bool is_stereo = base->stereo;
250
251
int32_t todo = p_frames;
252
253
if (base->loop_mode == AudioStreamWAV::LOOP_BACKWARD) {
254
sign = -1;
255
}
256
257
int8_t increment = sign;
258
259
//looping
260
261
AudioStreamWAV::LoopMode loop_format = base->loop_mode;
262
AudioStreamWAV::Format format = base->format;
263
264
/* audio data */
265
266
const uint8_t *data = base->data.ptr();
267
AudioFrame *dst_buff = p_buffer;
268
269
if (format == AudioStreamWAV::FORMAT_IMA_ADPCM) {
270
if (loop_format != AudioStreamWAV::LOOP_DISABLED) {
271
ima_adpcm[0].loop_pos = loop_begin;
272
ima_adpcm[1].loop_pos = loop_begin;
273
loop_format = AudioStreamWAV::LOOP_FORWARD;
274
}
275
}
276
277
while (todo > 0) {
278
int64_t limit = 0;
279
int32_t target = 0, aux = 0;
280
281
/** LOOP CHECKING **/
282
283
if (increment < 0) {
284
/* going backwards */
285
286
if (loop_format != AudioStreamWAV::LOOP_DISABLED && offset < loop_begin) {
287
/* loopstart reached */
288
if (loop_format == AudioStreamWAV::LOOP_PINGPONG) {
289
/* bounce ping pong */
290
offset = loop_begin + (loop_begin - offset);
291
increment = -increment;
292
sign *= -1;
293
} else {
294
/* go to loop-end */
295
offset = loop_end - (loop_begin - offset);
296
}
297
} else {
298
/* check for sample not reaching beginning */
299
if (offset < 0) {
300
active = false;
301
break;
302
}
303
}
304
} else {
305
/* going forward */
306
if (loop_format != AudioStreamWAV::LOOP_DISABLED && offset >= loop_end) {
307
/* loopend reached */
308
309
if (loop_format == AudioStreamWAV::LOOP_PINGPONG) {
310
/* bounce ping pong */
311
offset = loop_end - (offset - loop_end);
312
increment = -increment;
313
sign *= -1;
314
} else {
315
/* go to loop-begin */
316
317
if (format == AudioStreamWAV::FORMAT_IMA_ADPCM) {
318
for (int i = 0; i < 2; i++) {
319
ima_adpcm[i].step_index = ima_adpcm[i].loop_step_index;
320
ima_adpcm[i].predictor = ima_adpcm[i].loop_predictor;
321
ima_adpcm[i].last_nibble = loop_begin;
322
}
323
offset = loop_begin;
324
} else {
325
offset = loop_begin + (offset - loop_end);
326
}
327
}
328
} else {
329
/* no loop, check for end of sample */
330
if (offset >= len) {
331
active = false;
332
break;
333
}
334
}
335
}
336
337
/** MIXCOUNT COMPUTING **/
338
339
/* next possible limit (looppoints or sample begin/end */
340
limit = (increment < 0) ? begin_limit : end_limit;
341
342
/* compute what is shorter, the todo or the limit? */
343
aux = (limit - offset) / increment + 1;
344
target = (aux < todo) ? aux : todo; /* mix target is the shorter buffer */
345
346
/* check just in case */
347
if (target <= 0) {
348
active = false;
349
break;
350
}
351
352
todo -= target;
353
354
switch (base->format) {
355
case AudioStreamWAV::FORMAT_8_BITS: {
356
if (is_stereo) {
357
decode_samples<int8_t, true, false, false>((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa);
358
} else {
359
decode_samples<int8_t, false, false, false>((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa);
360
}
361
} break;
362
case AudioStreamWAV::FORMAT_16_BITS: {
363
if (is_stereo) {
364
decode_samples<int16_t, true, false, false>((int16_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa);
365
} else {
366
decode_samples<int16_t, false, false, false>((int16_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa);
367
}
368
369
} break;
370
case AudioStreamWAV::FORMAT_IMA_ADPCM: {
371
if (is_stereo) {
372
decode_samples<int8_t, true, true, false>((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa);
373
} else {
374
decode_samples<int8_t, false, true, false>((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa);
375
}
376
377
} break;
378
case AudioStreamWAV::FORMAT_QOA: {
379
if (is_stereo) {
380
decode_samples<uint8_t, true, false, true>((uint8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa);
381
} else {
382
decode_samples<uint8_t, false, false, true>((uint8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa);
383
}
384
} break;
385
}
386
387
dst_buff += target;
388
}
389
390
if (todo) {
391
int mixed_frames = p_frames - todo;
392
//bit was missing from mix
393
int todo_ofs = p_frames - todo;
394
for (int i = todo_ofs; i < p_frames; i++) {
395
p_buffer[i] = AudioFrame(0, 0);
396
}
397
return mixed_frames;
398
}
399
return p_frames;
400
}
401
402
float AudioStreamPlaybackWAV::get_stream_sampling_rate() {
403
return base->mix_rate;
404
}
405
406
void AudioStreamPlaybackWAV::tag_used_streams() {
407
base->tag_used(get_playback_position());
408
}
409
410
void AudioStreamPlaybackWAV::set_is_sample(bool p_is_sample) {
411
_is_sample = p_is_sample;
412
}
413
414
bool AudioStreamPlaybackWAV::get_is_sample() const {
415
return _is_sample;
416
}
417
418
Ref<AudioSamplePlayback> AudioStreamPlaybackWAV::get_sample_playback() const {
419
return sample_playback;
420
}
421
422
void AudioStreamPlaybackWAV::set_sample_playback(const Ref<AudioSamplePlayback> &p_playback) {
423
sample_playback = p_playback;
424
if (sample_playback.is_valid()) {
425
sample_playback->stream_playback = Ref<AudioStreamPlayback>(this);
426
}
427
}
428
429
/////////////////////
430
431
void AudioStreamWAV::set_format(Format p_format) {
432
format = p_format;
433
}
434
435
AudioStreamWAV::Format AudioStreamWAV::get_format() const {
436
return format;
437
}
438
439
void AudioStreamWAV::set_loop_mode(LoopMode p_loop_mode) {
440
loop_mode = p_loop_mode;
441
}
442
443
AudioStreamWAV::LoopMode AudioStreamWAV::get_loop_mode() const {
444
return loop_mode;
445
}
446
447
void AudioStreamWAV::set_loop_begin(int p_frame) {
448
loop_begin = p_frame;
449
}
450
451
int AudioStreamWAV::get_loop_begin() const {
452
return loop_begin;
453
}
454
455
void AudioStreamWAV::set_loop_end(int p_frame) {
456
loop_end = p_frame;
457
}
458
459
int AudioStreamWAV::get_loop_end() const {
460
return loop_end;
461
}
462
463
void AudioStreamWAV::set_mix_rate(int p_hz) {
464
ERR_FAIL_COND(p_hz == 0);
465
mix_rate = p_hz;
466
}
467
468
int AudioStreamWAV::get_mix_rate() const {
469
return mix_rate;
470
}
471
472
void AudioStreamWAV::set_stereo(bool p_enable) {
473
stereo = p_enable;
474
}
475
476
bool AudioStreamWAV::is_stereo() const {
477
return stereo;
478
}
479
480
void AudioStreamWAV::set_tags(const Dictionary &p_tags) {
481
tags = p_tags;
482
}
483
484
Dictionary AudioStreamWAV::get_tags() const {
485
return tags;
486
}
487
488
double AudioStreamWAV::get_length() const {
489
int len = data_bytes;
490
switch (format) {
491
case AudioStreamWAV::FORMAT_8_BITS:
492
len /= 1;
493
break;
494
case AudioStreamWAV::FORMAT_16_BITS:
495
len /= 2;
496
break;
497
case AudioStreamWAV::FORMAT_IMA_ADPCM:
498
len *= 2;
499
break;
500
case AudioStreamWAV::FORMAT_QOA:
501
qoa_desc desc = {};
502
qoa_decode_header(data.ptr(), data_bytes, &desc);
503
len = desc.samples * desc.channels;
504
break;
505
}
506
507
if (stereo) {
508
len /= 2;
509
}
510
511
return double(len) / mix_rate;
512
}
513
514
bool AudioStreamWAV::is_monophonic() const {
515
return false;
516
}
517
518
void AudioStreamWAV::set_data(const Vector<uint8_t> &p_data) {
519
AudioServer::get_singleton()->lock();
520
521
data = p_data;
522
data_bytes = p_data.size();
523
524
AudioServer::get_singleton()->unlock();
525
}
526
527
Vector<uint8_t> AudioStreamWAV::get_data() const {
528
return data;
529
}
530
531
Error AudioStreamWAV::save_to_wav(const String &p_path) {
532
if (format == AudioStreamWAV::FORMAT_IMA_ADPCM || format == AudioStreamWAV::FORMAT_QOA) {
533
WARN_PRINT("Saving IMA_ADPCM and QOA samples is not supported yet");
534
return ERR_UNAVAILABLE;
535
}
536
537
int sub_chunk_2_size = data_bytes; //Subchunk2Size = Size of data in bytes
538
539
// Format code
540
// 1:PCM format (for 8 or 16 bit)
541
// 3:IEEE float format
542
int format_code = (format == FORMAT_IMA_ADPCM) ? 3 : 1;
543
544
int n_channels = stereo ? 2 : 1;
545
546
long sample_rate = mix_rate;
547
548
int byte_pr_sample = 0;
549
switch (format) {
550
case AudioStreamWAV::FORMAT_8_BITS:
551
byte_pr_sample = 1;
552
break;
553
case AudioStreamWAV::FORMAT_16_BITS:
554
case AudioStreamWAV::FORMAT_QOA:
555
byte_pr_sample = 2;
556
break;
557
case AudioStreamWAV::FORMAT_IMA_ADPCM:
558
byte_pr_sample = 4;
559
break;
560
}
561
562
String file_path = p_path;
563
if (file_path.substr(file_path.length() - 4, 4).to_lower() != ".wav") {
564
file_path += ".wav";
565
}
566
567
Ref<FileAccess> file = FileAccess::open(file_path, FileAccess::WRITE); //Overrides existing file if present
568
569
ERR_FAIL_COND_V(file.is_null(), ERR_FILE_CANT_WRITE);
570
571
// Create WAV Header
572
file->store_string("RIFF"); //ChunkID
573
file->store_32(sub_chunk_2_size + 36); //ChunkSize = 36 + SubChunk2Size (size of entire file minus the 8 bits for this and previous header)
574
file->store_string("WAVE"); //Format
575
file->store_string("fmt "); //Subchunk1ID
576
file->store_32(16); //Subchunk1Size = 16
577
file->store_16(format_code); //AudioFormat
578
file->store_16(n_channels); //Number of Channels
579
file->store_32(sample_rate); //SampleRate
580
file->store_32(sample_rate * n_channels * byte_pr_sample); //ByteRate
581
file->store_16(n_channels * byte_pr_sample); //BlockAlign = NumChannels * BytePrSample
582
file->store_16(byte_pr_sample * 8); //BitsPerSample
583
file->store_string("data"); //Subchunk2ID
584
file->store_32(sub_chunk_2_size); //Subchunk2Size
585
586
// Add data
587
const uint8_t *read_data = data.ptr();
588
switch (format) {
589
case AudioStreamWAV::FORMAT_8_BITS:
590
for (unsigned int i = 0; i < data_bytes; i++) {
591
uint8_t data_point = (read_data[i] + 128);
592
file->store_8(data_point);
593
}
594
break;
595
case AudioStreamWAV::FORMAT_16_BITS:
596
case AudioStreamWAV::FORMAT_QOA:
597
for (unsigned int i = 0; i < data_bytes / 2; i++) {
598
uint16_t data_point = decode_uint16(&read_data[i * 2]);
599
file->store_16(data_point);
600
}
601
break;
602
case AudioStreamWAV::FORMAT_IMA_ADPCM:
603
//Unimplemented
604
break;
605
}
606
607
return OK;
608
}
609
610
Ref<AudioStreamPlayback> AudioStreamWAV::instantiate_playback() {
611
Ref<AudioStreamPlaybackWAV> sample;
612
sample.instantiate();
613
sample->base = Ref<AudioStreamWAV>(this);
614
615
if (format == AudioStreamWAV::FORMAT_QOA) {
616
uint32_t ffp = qoa_decode_header(data.ptr(), data_bytes, &sample->qoa.desc);
617
ERR_FAIL_COND_V(ffp != 8, Ref<AudioStreamPlaybackWAV>());
618
sample->qoa.frame_len = qoa_max_frame_size(&sample->qoa.desc);
619
int samples_len = (sample->qoa.desc.samples > QOA_FRAME_LEN ? QOA_FRAME_LEN : sample->qoa.desc.samples);
620
int dec_len = sample->qoa.desc.channels * samples_len;
621
sample->qoa.dec.resize(dec_len);
622
}
623
624
return sample;
625
}
626
627
String AudioStreamWAV::get_stream_name() const {
628
return "";
629
}
630
631
Ref<AudioSample> AudioStreamWAV::generate_sample() const {
632
Ref<AudioSample> sample;
633
sample.instantiate();
634
sample->stream = this;
635
switch (loop_mode) {
636
case AudioStreamWAV::LoopMode::LOOP_DISABLED: {
637
sample->loop_mode = AudioSample::LoopMode::LOOP_DISABLED;
638
} break;
639
640
case AudioStreamWAV::LoopMode::LOOP_FORWARD: {
641
sample->loop_mode = AudioSample::LoopMode::LOOP_FORWARD;
642
} break;
643
644
case AudioStreamWAV::LoopMode::LOOP_PINGPONG: {
645
sample->loop_mode = AudioSample::LoopMode::LOOP_PINGPONG;
646
} break;
647
648
case AudioStreamWAV::LoopMode::LOOP_BACKWARD: {
649
sample->loop_mode = AudioSample::LoopMode::LOOP_BACKWARD;
650
} break;
651
}
652
sample->loop_begin = loop_begin;
653
sample->loop_end = loop_end;
654
sample->sample_rate = mix_rate;
655
return sample;
656
}
657
658
Ref<AudioStreamWAV> AudioStreamWAV::load_from_buffer(const Vector<uint8_t> &p_stream_data, const Dictionary &p_options) {
659
// /* STEP 1, READ WAVE FILE */
660
661
Ref<FileAccessMemory> file;
662
file.instantiate();
663
Error err = file->open_custom(p_stream_data.ptr(), p_stream_data.size());
664
ERR_FAIL_COND_V_MSG(err != OK, Ref<AudioStreamWAV>(), "Cannot create memfile for WAV file buffer.");
665
666
/* CHECK RIFF */
667
char riff[5];
668
riff[4] = 0;
669
file->get_buffer((uint8_t *)&riff, 4); //RIFF
670
671
if (riff[0] != 'R' || riff[1] != 'I' || riff[2] != 'F' || riff[3] != 'F') {
672
ERR_FAIL_V_MSG(Ref<AudioStreamWAV>(), vformat("Not a WAV file. File should start with 'RIFF', but found '%s', in file of size %d bytes", riff, file->get_length()));
673
}
674
675
/* GET FILESIZE */
676
677
// The file size in header is 8 bytes less than the actual size.
678
// See https://docs.fileformat.com/audio/wav/
679
const int FILE_SIZE_HEADER_OFFSET = 8;
680
uint32_t file_size_header = file->get_32() + FILE_SIZE_HEADER_OFFSET;
681
uint64_t file_size = file->get_length();
682
if (file_size != file_size_header) {
683
WARN_PRINT(vformat("File size %d is %s than the expected size %d.", file_size, file_size > file_size_header ? "larger" : "smaller", file_size_header));
684
}
685
686
/* CHECK WAVE */
687
688
char wave[5];
689
wave[4] = 0;
690
file->get_buffer((uint8_t *)&wave, 4); //WAVE
691
692
if (wave[0] != 'W' || wave[1] != 'A' || wave[2] != 'V' || wave[3] != 'E') {
693
ERR_FAIL_V_MSG(Ref<AudioStreamWAV>(), vformat("Not a WAV file. Header should contain 'WAVE', but found '%s', in file of size %d bytes", wave, file->get_length()));
694
}
695
696
// Let users override potential loop points from the WAV.
697
// We parse the WAV loop points only with "Detect From WAV" (0).
698
int import_loop_mode = p_options["edit/loop_mode"];
699
700
int format_bits = 0;
701
int format_channels = 0;
702
703
AudioStreamWAV::LoopMode loop_mode = AudioStreamWAV::LOOP_DISABLED;
704
uint16_t compression_code = 1;
705
bool format_found = false;
706
bool data_found = false;
707
int format_freq = 0;
708
int loop_begin = 0;
709
int loop_end = 0;
710
int frames = 0;
711
712
Vector<float> data;
713
714
HashMap<String, String> tag_map;
715
716
while (!file->eof_reached()) {
717
/* chunk */
718
char chunk_id[4];
719
file->get_buffer((uint8_t *)&chunk_id, 4); //RIFF
720
721
/* chunk size */
722
uint32_t chunksize = file->get_32();
723
uint32_t file_pos = file->get_position(); //save file pos, so we can skip to next chunk safely
724
725
if (file->eof_reached()) {
726
//ERR_PRINT("EOF REACH");
727
break;
728
}
729
730
if (chunk_id[0] == 'f' && chunk_id[1] == 'm' && chunk_id[2] == 't' && chunk_id[3] == ' ' && !format_found) {
731
/* IS FORMAT CHUNK */
732
733
//Issue: #7755 : Not a bug - usage of other formats (format codes) are unsupported in current importer version.
734
//Consider revision for engine version 3.0
735
compression_code = file->get_16();
736
if (compression_code != 1 && compression_code != 3) {
737
ERR_FAIL_V_MSG(Ref<AudioStreamWAV>(), "Format not supported for WAVE file (not PCM). Save WAVE files as uncompressed PCM or IEEE float instead.");
738
}
739
740
format_channels = file->get_16();
741
if (format_channels != 1 && format_channels != 2) {
742
ERR_FAIL_V_MSG(Ref<AudioStreamWAV>(), "Format not supported for WAVE file (not stereo or mono).");
743
}
744
745
format_freq = file->get_32(); //sampling rate
746
747
file->get_32(); // average bits/second (unused)
748
file->get_16(); // block align (unused)
749
format_bits = file->get_16(); // bits per sample
750
751
if (format_bits % 8 || format_bits == 0) {
752
ERR_FAIL_V_MSG(Ref<AudioStreamWAV>(), "Invalid amount of bits in the sample (should be one of 8, 16, 24 or 32).");
753
}
754
755
if (compression_code == 3 && format_bits % 32) {
756
ERR_FAIL_V_MSG(Ref<AudioStreamWAV>(), "Invalid amount of bits in the IEEE float sample (should be 32 or 64).");
757
}
758
759
/* Don't need anything else, continue */
760
format_found = true;
761
}
762
763
if (chunk_id[0] == 'd' && chunk_id[1] == 'a' && chunk_id[2] == 't' && chunk_id[3] == 'a' && !data_found) {
764
/* IS DATA CHUNK */
765
data_found = true;
766
767
if (!format_found) {
768
ERR_PRINT("'data' chunk before 'format' chunk found.");
769
break;
770
}
771
772
uint64_t remaining_bytes = file_size - file_pos;
773
frames = chunksize;
774
if (remaining_bytes < chunksize) {
775
WARN_PRINT("Data chunk size is smaller than expected. Proceeding with actual data size.");
776
frames = remaining_bytes;
777
}
778
779
ERR_FAIL_COND_V(format_channels == 0, Ref<AudioStreamWAV>());
780
frames /= format_channels;
781
frames /= (format_bits >> 3);
782
783
/*print_line("chunksize: "+itos(chunksize));
784
print_line("channels: "+itos(format_channels));
785
print_line("bits: "+itos(format_bits));
786
*/
787
788
data.resize(frames * format_channels);
789
790
if (compression_code == 1) {
791
if (format_bits == 8) {
792
for (int i = 0; i < frames * format_channels; i++) {
793
// 8 bit samples are UNSIGNED
794
795
data.write[i] = int8_t(file->get_8() - 128) / 128.f;
796
}
797
} else if (format_bits == 16) {
798
for (int i = 0; i < frames * format_channels; i++) {
799
//16 bit SIGNED
800
801
data.write[i] = int16_t(file->get_16()) / 32768.f;
802
}
803
} else {
804
for (int i = 0; i < frames * format_channels; i++) {
805
//16+ bits samples are SIGNED
806
// if sample is > 16 bits, just read extra bytes
807
808
uint32_t s = 0;
809
for (int b = 0; b < (format_bits >> 3); b++) {
810
s |= ((uint32_t)file->get_8()) << (b * 8);
811
}
812
s <<= (32 - format_bits);
813
814
data.write[i] = (int32_t(s) >> 16) / 32768.f;
815
}
816
}
817
} else if (compression_code == 3) {
818
if (format_bits == 32) {
819
for (int i = 0; i < frames * format_channels; i++) {
820
//32 bit IEEE Float
821
822
data.write[i] = file->get_float();
823
}
824
} else if (format_bits == 64) {
825
for (int i = 0; i < frames * format_channels; i++) {
826
//64 bit IEEE Float
827
828
data.write[i] = file->get_double();
829
}
830
}
831
}
832
833
// This is commented out due to some weird edge case seemingly in FileAccessMemory, doesn't seem to have any side effects though.
834
// if (file->eof_reached()) {
835
// ERR_FAIL_V_MSG(Ref<AudioStreamWAV>(), "Premature end of file.");
836
// }
837
}
838
839
if (import_loop_mode == 0 && chunk_id[0] == 's' && chunk_id[1] == 'm' && chunk_id[2] == 'p' && chunk_id[3] == 'l') {
840
// Loop point info!
841
842
/**
843
* Consider exploring next document:
844
* http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/RIFFNEW.pdf
845
* Especially on page:
846
* 16 - 17
847
* Timestamp:
848
* 22:38 06.07.2017 GMT
849
**/
850
851
for (int i = 0; i < 10; i++) {
852
file->get_32(); // i wish to know why should i do this... no doc!
853
}
854
855
// only read 0x00 (loop forward), 0x01 (loop ping-pong) and 0x02 (loop backward)
856
// Skip anything else because it's not supported, reserved for future uses or sampler specific
857
// from https://sites.google.com/site/musicgapi/technical-documents/wav-file-format#smpl (loop type values table)
858
int loop_type = file->get_32();
859
if (loop_type == 0x00 || loop_type == 0x01 || loop_type == 0x02) {
860
if (loop_type == 0x00) {
861
loop_mode = AudioStreamWAV::LOOP_FORWARD;
862
} else if (loop_type == 0x01) {
863
loop_mode = AudioStreamWAV::LOOP_PINGPONG;
864
} else if (loop_type == 0x02) {
865
loop_mode = AudioStreamWAV::LOOP_BACKWARD;
866
}
867
loop_begin = file->get_32();
868
loop_end = file->get_32();
869
}
870
}
871
872
if (chunk_id[0] == 'L' && chunk_id[1] == 'I' && chunk_id[2] == 'S' && chunk_id[3] == 'T') {
873
// RIFF 'LIST' chunk.
874
// See https://www.recordingblogs.com/wiki/list-chunk-of-a-wave-file
875
876
char list_id[4];
877
file->get_buffer((uint8_t *)&list_id, 4);
878
uint32_t end_of_chunk = file_pos + chunksize - 8;
879
880
if (list_id[0] == 'I' && list_id[1] == 'N' && list_id[2] == 'F' && list_id[3] == 'O') {
881
// 'INFO' list type.
882
// The size of an entry can be arbitrary.
883
while (file->get_position() < end_of_chunk) {
884
char info_id[4];
885
file->get_buffer((uint8_t *)&info_id, 4);
886
887
uint32_t text_size = file->get_32();
888
if (text_size == 0) {
889
continue;
890
}
891
892
Vector<char> text;
893
text.resize(text_size);
894
file->get_buffer((uint8_t *)&text[0], text_size);
895
896
// Skip padding byte if text_size is odd
897
if (text_size & 1) {
898
file->get_8();
899
}
900
901
// The data is always an ASCII string. ASCII is a subset of UTF-8.
902
String tag;
903
tag.append_utf8(&info_id[0], 4);
904
905
String tag_value;
906
tag_value.append_utf8(&text[0], text_size);
907
908
tag_map[tag] = tag_value;
909
}
910
}
911
}
912
913
// Move to the start of the next chunk. Note that RIFF requires a padding byte for odd
914
// chunk sizes.
915
file->seek(file_pos + chunksize + (chunksize & 1));
916
}
917
918
// STEP 2, APPLY CONVERSIONS
919
920
bool is16 = format_bits != 8;
921
int rate = format_freq;
922
923
/*
924
print_line("Input Sample: ");
925
print_line("\tframes: " + itos(frames));
926
print_line("\tformat_channels: " + itos(format_channels));
927
print_line("\t16bits: " + itos(is16));
928
print_line("\trate: " + itos(rate));
929
print_line("\tloop: " + itos(loop));
930
print_line("\tloop begin: " + itos(loop_begin));
931
print_line("\tloop end: " + itos(loop_end));
932
*/
933
934
//apply frequency limit
935
936
bool limit_rate = p_options["force/max_rate"];
937
int limit_rate_hz = p_options["force/max_rate_hz"];
938
if (limit_rate && rate > limit_rate_hz && rate > 0 && frames > 0) {
939
// resample!
940
int new_data_frames = (int)(frames * (float)limit_rate_hz / (float)rate);
941
942
Vector<float> new_data;
943
new_data.resize(new_data_frames * format_channels);
944
for (int c = 0; c < format_channels; c++) {
945
float frac = 0.0;
946
int ipos = 0;
947
948
for (int i = 0; i < new_data_frames; i++) {
949
// Cubic interpolation should be enough.
950
951
float y0 = data[MAX(0, ipos - 1) * format_channels + c];
952
float y1 = data[ipos * format_channels + c];
953
float y2 = data[MIN(frames - 1, ipos + 1) * format_channels + c];
954
float y3 = data[MIN(frames - 1, ipos + 2) * format_channels + c];
955
956
new_data.write[i * format_channels + c] = Math::cubic_interpolate(y1, y2, y0, y3, frac);
957
958
// update position and always keep fractional part within ]0...1]
959
// in order to avoid 32bit floating point precision errors
960
961
frac += (float)rate / (float)limit_rate_hz;
962
int tpos = (int)Math::floor(frac);
963
ipos += tpos;
964
frac -= tpos;
965
}
966
}
967
968
if (loop_mode) {
969
loop_begin = (int)(loop_begin * (float)new_data_frames / (float)frames);
970
loop_end = (int)(loop_end * (float)new_data_frames / (float)frames);
971
}
972
973
data = new_data;
974
rate = limit_rate_hz;
975
frames = new_data_frames;
976
}
977
978
bool normalize = p_options["edit/normalize"];
979
980
if (normalize) {
981
float max = 0.0;
982
for (int i = 0; i < data.size(); i++) {
983
float amp = Math::abs(data[i]);
984
if (amp > max) {
985
max = amp;
986
}
987
}
988
989
if (max > 0) {
990
float mult = 1.0 / max;
991
for (int i = 0; i < data.size(); i++) {
992
data.write[i] *= mult;
993
}
994
}
995
}
996
997
bool trim = p_options["edit/trim"];
998
999
if (trim && (loop_mode == AudioStreamWAV::LOOP_DISABLED) && format_channels > 0) {
1000
int first = 0;
1001
int last = (frames / format_channels) - 1;
1002
bool found = false;
1003
float limit = Math::db_to_linear(TRIM_DB_LIMIT);
1004
1005
for (int i = 0; i < data.size() / format_channels; i++) {
1006
float amp_channel_sum = 0.0;
1007
for (int j = 0; j < format_channels; j++) {
1008
amp_channel_sum += Math::abs(data[(i * format_channels) + j]);
1009
}
1010
1011
float amp = Math::abs(amp_channel_sum / (float)format_channels);
1012
1013
if (!found && amp > limit) {
1014
first = i;
1015
found = true;
1016
}
1017
1018
if (found && amp > limit) {
1019
last = i;
1020
}
1021
}
1022
1023
if (first < last) {
1024
Vector<float> new_data;
1025
new_data.resize((last - first) * format_channels);
1026
for (int i = first; i < last; i++) {
1027
float fade_out_mult = 1.0;
1028
1029
if (last - i < TRIM_FADE_OUT_FRAMES) {
1030
fade_out_mult = ((float)(last - i - 1) / (float)TRIM_FADE_OUT_FRAMES);
1031
}
1032
1033
for (int j = 0; j < format_channels; j++) {
1034
new_data.write[((i - first) * format_channels) + j] = data[(i * format_channels) + j] * fade_out_mult;
1035
}
1036
}
1037
1038
data = new_data;
1039
frames = data.size() / format_channels;
1040
}
1041
}
1042
1043
if (import_loop_mode >= 2) {
1044
loop_mode = (AudioStreamWAV::LoopMode)(import_loop_mode - 1);
1045
loop_begin = p_options["edit/loop_begin"];
1046
loop_end = p_options["edit/loop_end"];
1047
// Wrap around to max frames, so `-1` can be used to select the end, etc.
1048
if (loop_begin < 0) {
1049
loop_begin = CLAMP(loop_begin + frames, 0, frames - 1);
1050
}
1051
if (loop_end < 0) {
1052
loop_end = CLAMP(loop_end + frames, 0, frames - 1);
1053
}
1054
}
1055
1056
int compression = p_options["compress/mode"];
1057
bool force_mono = p_options["force/mono"];
1058
1059
if (force_mono && format_channels == 2) {
1060
Vector<float> new_data;
1061
new_data.resize(data.size() / 2);
1062
for (int i = 0; i < frames; i++) {
1063
new_data.write[i] = (data[i * 2 + 0] + data[i * 2 + 1]) / 2.0;
1064
}
1065
1066
data = new_data;
1067
format_channels = 1;
1068
}
1069
1070
bool force_8_bit = p_options["force/8_bit"];
1071
if (force_8_bit) {
1072
is16 = false;
1073
}
1074
1075
Vector<uint8_t> dst_data;
1076
AudioStreamWAV::Format dst_format;
1077
1078
if (compression == 1) {
1079
dst_format = AudioStreamWAV::FORMAT_IMA_ADPCM;
1080
if (format_channels == 1) {
1081
_compress_ima_adpcm(data, dst_data);
1082
} else {
1083
//byte interleave
1084
Vector<float> left;
1085
Vector<float> right;
1086
1087
int tframes = data.size() / 2;
1088
left.resize(tframes);
1089
right.resize(tframes);
1090
1091
for (int i = 0; i < tframes; i++) {
1092
left.write[i] = data[i * 2 + 0];
1093
right.write[i] = data[i * 2 + 1];
1094
}
1095
1096
Vector<uint8_t> bleft;
1097
Vector<uint8_t> bright;
1098
1099
_compress_ima_adpcm(left, bleft);
1100
_compress_ima_adpcm(right, bright);
1101
1102
int dl = bleft.size();
1103
dst_data.resize(dl * 2);
1104
1105
uint8_t *w = dst_data.ptrw();
1106
const uint8_t *rl = bleft.ptr();
1107
const uint8_t *rr = bright.ptr();
1108
1109
for (int i = 0; i < dl; i++) {
1110
w[i * 2 + 0] = rl[i];
1111
w[i * 2 + 1] = rr[i];
1112
}
1113
}
1114
1115
} else if (compression == 2) {
1116
dst_format = AudioStreamWAV::FORMAT_QOA;
1117
1118
qoa_desc desc = {};
1119
desc.samplerate = rate;
1120
desc.samples = frames;
1121
desc.channels = format_channels;
1122
1123
_compress_qoa(data, dst_data, &desc);
1124
} else {
1125
dst_format = is16 ? AudioStreamWAV::FORMAT_16_BITS : AudioStreamWAV::FORMAT_8_BITS;
1126
dst_data.resize(data.size() * (is16 ? 2 : 1));
1127
{
1128
uint8_t *w = dst_data.ptrw();
1129
1130
int ds = data.size();
1131
for (int i = 0; i < ds; i++) {
1132
if (is16) {
1133
int16_t v = CLAMP(data[i] * 32768, -32768, 32767);
1134
encode_uint16(v, &w[i * 2]);
1135
} else {
1136
int8_t v = CLAMP(data[i] * 128, -128, 127);
1137
w[i] = v;
1138
}
1139
}
1140
}
1141
}
1142
1143
Ref<AudioStreamWAV> sample;
1144
sample.instantiate();
1145
sample->set_data(dst_data);
1146
sample->set_format(dst_format);
1147
sample->set_mix_rate(rate);
1148
sample->set_loop_mode(loop_mode);
1149
sample->set_loop_begin(loop_begin);
1150
sample->set_loop_end(loop_end);
1151
sample->set_stereo(format_channels == 2);
1152
1153
if (!tag_map.is_empty()) {
1154
// Used to make the metadata tags more unified across different AudioStreams.
1155
// See https://www.recordingblogs.com/wiki/list-chunk-of-a-wave-file
1156
// https://wiki.hydrogenaudio.org/index.php?title=Tag_Mapping#Mapping_Tables
1157
HashMap<String, String> tag_id_remaps;
1158
tag_id_remaps.reserve(15);
1159
tag_id_remaps["IARL"] = "location";
1160
tag_id_remaps["IART"] = "artist";
1161
tag_id_remaps["ICMS"] = "organization";
1162
tag_id_remaps["ICMT"] = "comment";
1163
tag_id_remaps["ICNT"] = "releasecountry";
1164
tag_id_remaps["ICOP"] = "copyright";
1165
tag_id_remaps["ICRD"] = "date";
1166
tag_id_remaps["IENC"] = "encodedby";
1167
tag_id_remaps["IENG"] = "engineer";
1168
tag_id_remaps["IFRM"] = "tracktotal";
1169
tag_id_remaps["IGNR"] = "genre";
1170
tag_id_remaps["IKEY"] = "keywords";
1171
tag_id_remaps["ILNG"] = "language";
1172
tag_id_remaps["IMED"] = "media";
1173
tag_id_remaps["IMUS"] = "composer";
1174
tag_id_remaps["INAM"] = "title";
1175
tag_id_remaps["IPRD"] = "album";
1176
tag_id_remaps["IPRO"] = "producer";
1177
tag_id_remaps["IPRT"] = "tracknumber";
1178
tag_id_remaps["ISBJ"] = "description";
1179
tag_id_remaps["ISFT"] = "encoder";
1180
tag_id_remaps["ISRF"] = "media";
1181
tag_id_remaps["ITCH"] = "encodedby";
1182
tag_id_remaps["ITRK"] = "tracknumber";
1183
tag_id_remaps["IWRI"] = "author";
1184
tag_id_remaps["TLEN"] = "length";
1185
Dictionary tag_dictionary;
1186
for (const KeyValue<String, String> &E : tag_map) {
1187
HashMap<String, String>::ConstIterator remap = tag_id_remaps.find(E.key);
1188
String tag_key = E.key;
1189
if (remap) {
1190
tag_key = remap->value;
1191
}
1192
1193
tag_dictionary[tag_key] = E.value;
1194
}
1195
sample->set_tags(tag_dictionary);
1196
}
1197
1198
return sample;
1199
}
1200
1201
Ref<AudioStreamWAV> AudioStreamWAV::load_from_file(const String &p_path, const Dictionary &p_options) {
1202
const Vector<uint8_t> stream_data = FileAccess::get_file_as_bytes(p_path);
1203
ERR_FAIL_COND_V_MSG(stream_data.is_empty(), Ref<AudioStreamWAV>(), vformat("Cannot open file '%s'.", p_path));
1204
return load_from_buffer(stream_data, p_options);
1205
}
1206
1207
void AudioStreamWAV::_bind_methods() {
1208
ClassDB::bind_static_method("AudioStreamWAV", D_METHOD("load_from_buffer", "stream_data", "options"), &AudioStreamWAV::load_from_buffer, DEFVAL(Dictionary()));
1209
ClassDB::bind_static_method("AudioStreamWAV", D_METHOD("load_from_file", "path", "options"), &AudioStreamWAV::load_from_file, DEFVAL(Dictionary()));
1210
1211
ClassDB::bind_method(D_METHOD("set_data", "data"), &AudioStreamWAV::set_data);
1212
ClassDB::bind_method(D_METHOD("get_data"), &AudioStreamWAV::get_data);
1213
1214
ClassDB::bind_method(D_METHOD("set_format", "format"), &AudioStreamWAV::set_format);
1215
ClassDB::bind_method(D_METHOD("get_format"), &AudioStreamWAV::get_format);
1216
1217
ClassDB::bind_method(D_METHOD("set_loop_mode", "loop_mode"), &AudioStreamWAV::set_loop_mode);
1218
ClassDB::bind_method(D_METHOD("get_loop_mode"), &AudioStreamWAV::get_loop_mode);
1219
1220
ClassDB::bind_method(D_METHOD("set_loop_begin", "loop_begin"), &AudioStreamWAV::set_loop_begin);
1221
ClassDB::bind_method(D_METHOD("get_loop_begin"), &AudioStreamWAV::get_loop_begin);
1222
1223
ClassDB::bind_method(D_METHOD("set_loop_end", "loop_end"), &AudioStreamWAV::set_loop_end);
1224
ClassDB::bind_method(D_METHOD("get_loop_end"), &AudioStreamWAV::get_loop_end);
1225
1226
ClassDB::bind_method(D_METHOD("set_mix_rate", "mix_rate"), &AudioStreamWAV::set_mix_rate);
1227
ClassDB::bind_method(D_METHOD("get_mix_rate"), &AudioStreamWAV::get_mix_rate);
1228
1229
ClassDB::bind_method(D_METHOD("set_stereo", "stereo"), &AudioStreamWAV::set_stereo);
1230
ClassDB::bind_method(D_METHOD("is_stereo"), &AudioStreamWAV::is_stereo);
1231
1232
ClassDB::bind_method(D_METHOD("set_tags", "tags"), &AudioStreamWAV::set_tags);
1233
ClassDB::bind_method(D_METHOD("get_tags"), &AudioStreamWAV::get_tags);
1234
1235
ClassDB::bind_method(D_METHOD("save_to_wav", "path"), &AudioStreamWAV::save_to_wav);
1236
1237
ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_data", "get_data");
1238
ADD_PROPERTY(PropertyInfo(Variant::INT, "format", PROPERTY_HINT_ENUM, "8-Bit,16-Bit,IMA ADPCM,Quite OK Audio"), "set_format", "get_format");
1239
ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_mode", PROPERTY_HINT_ENUM, "Disabled,Forward,Ping-Pong,Backward"), "set_loop_mode", "get_loop_mode");
1240
ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_begin"), "set_loop_begin", "get_loop_begin");
1241
ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_end"), "set_loop_end", "get_loop_end");
1242
ADD_PROPERTY(PropertyInfo(Variant::INT, "mix_rate"), "set_mix_rate", "get_mix_rate");
1243
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stereo"), "set_stereo", "is_stereo");
1244
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "tags", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_tags", "get_tags");
1245
1246
BIND_ENUM_CONSTANT(FORMAT_8_BITS);
1247
BIND_ENUM_CONSTANT(FORMAT_16_BITS);
1248
BIND_ENUM_CONSTANT(FORMAT_IMA_ADPCM);
1249
BIND_ENUM_CONSTANT(FORMAT_QOA);
1250
1251
BIND_ENUM_CONSTANT(LOOP_DISABLED);
1252
BIND_ENUM_CONSTANT(LOOP_FORWARD);
1253
BIND_ENUM_CONSTANT(LOOP_PINGPONG);
1254
BIND_ENUM_CONSTANT(LOOP_BACKWARD);
1255
}
1256
1257