| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*  resource_format_wav.cpp                                              */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*                       This file is part of:                           */ | 
					
						
							|  |  |  | /*                           GODOT ENGINE                                */ | 
					
						
							|  |  |  | /*                    http://www.godotengine.org                         */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2017-01-01 22:01:57 +01:00
										 |  |  | /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur.                 */ | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* 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.                */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2017-01-15 16:06:14 -03:00
										 |  |  | #if 0
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | #include "resource_format_wav.h"
 | 
					
						
							|  |  |  | #include "os/file_access.h"
 | 
					
						
							|  |  |  | #include "scene/resources/sample.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-23 20:15:56 -03:00
										 |  |  | RES ResourceFormatLoaderWAV::load(const String &p_path, const String& p_original_path, Error *r_error) { | 
					
						
							|  |  |  | 	if (r_error) | 
					
						
							|  |  |  | 		*r_error=ERR_FILE_CANT_OPEN; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	Error err; | 
					
						
							|  |  |  | 	FileAccess *file=FileAccess::open(p_path, FileAccess::READ,&err); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ERR_FAIL_COND_V( err!=OK, RES() ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-23 20:15:56 -03:00
										 |  |  | 	if (r_error) | 
					
						
							|  |  |  | 		*r_error=ERR_FILE_CORRUPT; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	/* 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; | 
					
						
							| 
									
										
										
										
											2015-05-19 23:37:04 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 			frames/=format_channels; | 
					
						
							|  |  |  | 			frames/=(format_bits>>3); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-26 01:05:08 -03:00
										 |  |  | 			/*print_line("chunksize: "+itos(chunksize));
 | 
					
						
							| 
									
										
										
										
											2015-05-19 23:37:04 -03:00
										 |  |  | 			print_line("channels: "+itos(format_channels)); | 
					
						
							|  |  |  | 			print_line("bits: "+itos(format_bits)); | 
					
						
							| 
									
										
										
										
											2015-05-26 01:05:08 -03:00
										 |  |  | */ | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 			sample->create( | 
					
						
							|  |  |  | 					(format_bits==8) ? Sample::FORMAT_PCM8 : Sample::FORMAT_PCM16, | 
					
						
							|  |  |  | 					(format_channels==2)?true:false, | 
					
						
							|  |  |  | 					frames ); | 
					
						
							|  |  |  | 			sample->set_mix_rate( format_freq ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-19 23:37:04 -03:00
										 |  |  | 			int len=frames; | 
					
						
							|  |  |  | 			if (format_channels==2) | 
					
						
							|  |  |  | 				len*=2; | 
					
						
							|  |  |  | 			if (format_bits>8) | 
					
						
							|  |  |  | 				len*=2; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-07 18:25:37 -03:00
										 |  |  | 			PoolVector<uint8_t> data; | 
					
						
							| 
									
										
										
										
											2015-05-19 23:37:04 -03:00
										 |  |  | 			data.resize(len); | 
					
						
							| 
									
										
										
										
											2017-01-07 18:25:37 -03:00
										 |  |  | 			PoolVector<uint8_t>::Write dataw = data.write(); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 			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; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-07 18:25:37 -03:00
										 |  |  | 			dataw=PoolVector<uint8_t>::Write(); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-23 20:15:56 -03:00
										 |  |  | 	if (r_error) | 
					
						
							|  |  |  | 		*r_error=OK; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-26 14:50:42 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	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 { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-14 00:51:09 -03:00
										 |  |  | 	if (p_path.get_extension().to_lower()=="wav") | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 		return "Sample"; | 
					
						
							|  |  |  | 	return ""; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-15 16:06:14 -03:00
										 |  |  | #endif
 |