AudioStreamSample can now be saved to a WAV file

8 and 16 bit sample saving has been implemented.
This commit is contained in:
Gustav Lund 2018-07-23 14:51:23 +02:00
parent cd2070c684
commit adb43b6976

View file

@ -29,6 +29,8 @@
/*************************************************************************/
#include "audio_stream_sample.h"
#include "io/marshalls.h"
#include "os/file_access.h"
void AudioStreamPlaybackSample::start(float p_from_pos) {
@ -510,7 +512,73 @@ PoolVector<uint8_t> AudioStreamSample::get_data() const {
}
void AudioStreamSample::save_to_wav(String p_path) {
// TODO! Implement saving to wav file
if (format == AudioStreamSample::FORMAT_IMA_ADPCM) {
WARN_PRINTS("Saving IMA_ADPC samples are not supported yet");
return;
}
int sub_chunk_2_size = data_bytes; //Subchunk2Size = Size of data in bytes
// Format code
// 1:PCM format (for 8 or 16 bit)
// 3:IEEE float format
int format_code = (format == FORMAT_IMA_ADPCM) ? 3 : 1;
int n_channels = stereo ? 2 : 1;
long sample_rate = mix_rate;
int byte_pr_sample = 0;
switch (format) {
case AudioStreamSample::FORMAT_8_BITS: byte_pr_sample = 1; break;
case AudioStreamSample::FORMAT_16_BITS: byte_pr_sample = 2; break;
case AudioStreamSample::FORMAT_IMA_ADPCM: byte_pr_sample = 4; break;
}
String file_path = p_path;
if (!(file_path.substr(file_path.length() - 4, 4) == ".wav")) {
file_path += ".wav";
}
Error err;
FileAccess *file = FileAccess::open(file_path, FileAccess::WRITE, &err); //Overrides existing file if present
// Create WAV Header
file->store_string("RIFF"); //ChunkID
file->store_32(sub_chunk_2_size + 36); //ChunkSize = 36 + SubChunk2Size (size of entire file minus the 8 bits for this and previous header)
file->store_string("WAVE"); //Format
file->store_string("fmt "); //Subchunk1ID
file->store_32(16); //Subchunk1Size = 16
file->store_16(format_code); //AudioFormat
file->store_16(n_channels); //Number of Channels
file->store_32(sample_rate); //SampleRate
file->store_32(sample_rate * n_channels * byte_pr_sample); //ByteRate
file->store_16(n_channels * byte_pr_sample); //BlockAlign = NumChannels * BytePrSample
file->store_16(byte_pr_sample * 8); //BitsPerSample
file->store_string("data"); //Subchunk2ID
file->store_32(sub_chunk_2_size); //Subchunk2Size
// Add data
PoolVector<uint8_t>::Read read_data = get_data().read();
switch (format) {
case AudioStreamSample::FORMAT_8_BITS:
for (int i = 0; i < data_bytes; i++) {
uint8_t data_point = (read_data[i] + 128);
file->store_8(data_point);
}
break;
case AudioStreamSample::FORMAT_16_BITS:
for (int i = 0; i < data_bytes / 2; i++) {
uint16_t data_point = decode_uint16(&read_data[i * 2]);
file->store_16(data_point);
}
break;
case AudioStreamSample::FORMAT_IMA_ADPCM:
//Unimplemented
break;
}
file->close();
}
Ref<AudioStreamPlayback> AudioStreamSample::instance_playback() {
@ -549,6 +617,8 @@ void AudioStreamSample::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stereo", "stereo"), &AudioStreamSample::set_stereo);
ClassDB::bind_method(D_METHOD("is_stereo"), &AudioStreamSample::is_stereo);
ClassDB::bind_method(D_METHOD("save_to_wav", "path"), &AudioStreamSample::save_to_wav);
ADD_PROPERTY(PropertyInfo(Variant::POOL_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_data", "get_data");
ADD_PROPERTY(PropertyInfo(Variant::INT, "format", PROPERTY_HINT_ENUM, "8-Bit,16-Bit,IMA-ADPCM"), "set_format", "get_format");
ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_mode", PROPERTY_HINT_ENUM, "Disabled,Forward,Ping-Pong"), "set_loop_mode", "get_loop_mode");