diff options
author | Juan Linietsky <reduzio@gmail.com> | 2014-02-09 22:10:30 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2014-02-09 22:10:30 -0300 |
commit | 0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac (patch) | |
tree | 276c4d099e178eb67fbd14f61d77b05e3808e9e3 /scene/io/resource_format_wav.cpp | |
parent | 0e49da1687bc8192ed210947da52c9e5c5f301bb (diff) | |
download | redot-engine-0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac.tar.gz |
GODOT IS OPEN SOURCE
Diffstat (limited to 'scene/io/resource_format_wav.cpp')
-rw-r--r-- | scene/io/resource_format_wav.cpp | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/scene/io/resource_format_wav.cpp b/scene/io/resource_format_wav.cpp new file mode 100644 index 0000000000..74eeb819b8 --- /dev/null +++ b/scene/io/resource_format_wav.cpp @@ -0,0 +1,255 @@ +/*************************************************************************/ +/* resource_format_wav.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ +#include "resource_format_wav.h" +#include "os/file_access.h" +#include "scene/resources/sample.h" + + +RES ResourceFormatLoaderWAV::load(const String &p_path,const String& p_original_path) { + + Error err; + FileAccess *file=FileAccess::open(p_path, FileAccess::READ,&err); + + ERR_FAIL_COND_V( err!=OK, RES() ); + + /* CHECK RIFF */ + char riff[5]; + riff[4]=0; + file->get_buffer((uint8_t*)&riff,4); //RIFF + + if (riff[0]!='R' || riff[1]!='I' || riff[2]!='F' || riff[3]!='F') { + + file->close(); + memdelete(file); + ERR_FAIL_V( RES() ); + } + + + /* GET FILESIZE */ + uint32_t filesize=file->get_32(); + + /* CHECK WAVE */ + + char wave[4]; + + file->get_buffer((uint8_t*)&wave,4); //RIFF + + if (wave[0]!='W' || wave[1]!='A' || wave[2]!='V' || wave[3]!='E') { + + + file->close(); + memdelete(file); + ERR_EXPLAIN("Not a WAV file (no WAVE RIFF Header)") + ERR_FAIL_V( RES() ); + } + + bool format_found=false; + bool data_found=false; + int format_bits=0; + int format_channels=0; + int format_freq=0; + Sample::LoopFormat loop=Sample::LOOP_NONE; + int loop_begin=0; + int loop_end=0; + + + Ref<Sample> sample( memnew( Sample ) ); + + + while (!file->eof_reached()) { + + + /* chunk */ + char chunkID[4]; + file->get_buffer((uint8_t*)&chunkID,4); //RIFF + + /* chunk size */ + uint32_t chunksize=file->get_32(); + uint32_t file_pos=file->get_pos(); //save file pos, so we can skip to next chunk safely + + if (file->eof_reached()) { + + //ERR_PRINT("EOF REACH"); + break; + } + + if (chunkID[0]=='f' && chunkID[1]=='m' && chunkID[2]=='t' && chunkID[3]==' ' && !format_found) { + /* IS FORMAT CHUNK */ + + uint16_t compression_code=file->get_16(); + + + if (compression_code!=1) { + ERR_PRINT("Format not supported for WAVE file (not PCM). Save WAVE files as uncompressed PCM instead."); + break; + } + + format_channels=file->get_16(); + if (format_channels!=1 && format_channels !=2) { + + ERR_PRINT("Format not supported for WAVE file (not stereo or mono)"); + break; + + } + + format_freq=file->get_32(); //sampling rate + + file->get_32(); // average bits/second (unused) + file->get_16(); // block align (unused) + format_bits=file->get_16(); // bits per sample + + if (format_bits%8) { + + ERR_PRINT("Strange number of bits in sample (not 8,16,24,32)"); + break; + } + + /* Dont need anything else, continue */ + format_found=true; + } + + + if (chunkID[0]=='d' && chunkID[1]=='a' && chunkID[2]=='t' && chunkID[3]=='a' && !data_found) { + /* IS FORMAT CHUNK */ + data_found=true; + + if (!format_found) { + ERR_PRINT("'data' chunk before 'format' chunk found."); + break; + + } + + int frames=chunksize; + frames/=format_channels; + frames/=(format_bits>>3); + + + sample->create( + (format_bits==8) ? Sample::FORMAT_PCM8 : Sample::FORMAT_PCM16, + (format_channels==2)?true:false, + frames ); + sample->set_mix_rate( format_freq ); + + DVector<uint8_t> data; + data.resize(chunksize); + DVector<uint8_t>::Write dataw = data.write(); + void * data_ptr = dataw.ptr(); + + for (int i=0;i<frames;i++) { + + + for (int c=0;c<format_channels;c++) { + + + if (format_bits==8) { + // 8 bit samples are UNSIGNED + + uint8_t s = file->get_8(); + s-=128; + int8_t *sp=(int8_t*)&s; + + int8_t *data_ptr8=&((int8_t*)data_ptr)[i*format_channels+c]; + + *data_ptr8=*sp; + + } else { + //16+ bits samples are SIGNED + // if sample is > 16 bits, just read extra bytes + + uint32_t data=0; + for (int b=0;b<(format_bits>>3);b++) { + + data|=((uint32_t)file->get_8())<<(b*8); + } + data<<=(32-format_bits); + + + int32_t s=data; + + int16_t *data_ptr16=&((int16_t*)data_ptr)[i*format_channels+c]; + + *data_ptr16=s>>16; + } + } + + } + + dataw=DVector<uint8_t>::Write(); + + sample->set_data(data); + + + if (file->eof_reached()) { + file->close(); + memdelete(file); + ERR_EXPLAIN("Premature end of file."); + ERR_FAIL_V(RES()); + } + } + + if (chunkID[0]=='s' && chunkID[1]=='m' && chunkID[2]=='p' && chunkID[3]=='l') { + //loop point info! + + for(int i=0;i<10;i++) + file->get_32(); // i wish to know why should i do this... no doc! + + loop=file->get_32()?Sample::LOOP_PING_PONG:Sample::LOOP_FORWARD; + loop_begin=file->get_32(); + loop_end=file->get_32(); + + } + file->seek( file_pos+chunksize ); + } + + sample->set_loop_format(loop); + sample->set_loop_begin(loop_begin); + sample->set_loop_end(loop_end); + + file->close(); + memdelete(file); + + return sample; + +} +void ResourceFormatLoaderWAV::get_recognized_extensions(List<String> *p_extensions) const { + + p_extensions->push_back("wav"); +} +bool ResourceFormatLoaderWAV::handles_type(const String& p_type) const { + + return (p_type=="Sample"); +} + +String ResourceFormatLoaderWAV::get_resource_type(const String &p_path) const { + + if (p_path.extension().to_lower()=="wav") + return "Sample"; + return ""; +} + |