Ajout version Release/x64 avec les libraries x64 et tuning de la version Debug
This commit is contained in:
		
							
								
								
									
										397
									
								
								SQCSim2021/external/irrKlang-64bit-1.6.0/plugins/ikpMP3/CIrrKlangAudioStreamMP3.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										397
									
								
								SQCSim2021/external/irrKlang-64bit-1.6.0/plugins/ikpMP3/CIrrKlangAudioStreamMP3.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,397 @@ | ||||
| // Copyright (C) 2002-2007 Nikolaus Gebhardt | ||||
| // Part of the code for this plugin for irrKlang is based on: | ||||
| //  MP3 input for Audiere by Matt Campbell <mattcampbell@pobox.com>, based on | ||||
| //  libavcodec from ffmpeg (http://ffmpeg.sourceforge.net/). | ||||
| // See license.txt for license details of this plugin. | ||||
|  | ||||
| #include "CIrrKlangAudioStreamMP3.h" | ||||
| #include <memory.h> | ||||
| #include <stdlib.h> // free, malloc and realloc | ||||
| #include <string.h> | ||||
|  | ||||
| namespace irrklang | ||||
| { | ||||
|  | ||||
| CIrrKlangAudioStreamMP3::CIrrKlangAudioStreamMP3(IFileReader* file) | ||||
| : File(file), TheMPAuDecContext(0), InputPosition(0), InputLength(0), | ||||
| 	DecodeBuffer(0), FirstFrameRead(false), EndOfFileReached(0), | ||||
| 	FileBegin(0), Position(0) | ||||
| { | ||||
| 	if (File) | ||||
| 	{ | ||||
| 		File->grab(); | ||||
|  | ||||
| 		TheMPAuDecContext = new MPAuDecContext(); | ||||
|  | ||||
| 		if (!TheMPAuDecContext || mpaudec_init(TheMPAuDecContext) < 0) | ||||
| 		{ | ||||
| 			File->drop(); | ||||
| 			File = 0; | ||||
| 			delete TheMPAuDecContext; | ||||
| 			TheMPAuDecContext = 0; | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		// init, get format | ||||
|  | ||||
| 		DecodeBuffer = new ik_u8[MPAUDEC_MAX_AUDIO_FRAME_SIZE]; | ||||
|  | ||||
| 		if (File->getSize()>0) | ||||
| 		{ | ||||
| 			// seekable file, now parse file to get size | ||||
| 			// (needed to make it possible for the engine to loop a stream correctly) | ||||
|  | ||||
| 			skipID3IfNecessary(); | ||||
|  | ||||
| 			TheMPAuDecContext->parse_only = 1; | ||||
| 			Format.FrameCount = 0; | ||||
|  | ||||
| 			while(!EndOfFileReached) | ||||
| 			{ | ||||
| 				if (!decodeFrame()) | ||||
| 					break; | ||||
|  | ||||
| 				Format.FrameCount += TheMPAuDecContext->frame_size; | ||||
|  | ||||
| 				if (!EndOfFileReached /*&& File->isSeekable()*/ ) | ||||
| 				{ | ||||
| 					// to be able to seek in the stream, store offsets and sizes | ||||
|  | ||||
| 					SFramePositionData data; | ||||
| 					data.size = TheMPAuDecContext->frame_size; | ||||
| 					data.offset = File->getPos() - (InputLength - InputPosition) - TheMPAuDecContext->coded_frame_size; | ||||
|  | ||||
| 					FramePositionData.push_back(data); | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			TheMPAuDecContext->parse_only = 0; | ||||
| 			setPosition(0); | ||||
| 		} | ||||
| 		else | ||||
| 			decodeFrame(); // decode first frame to read audio format | ||||
|  | ||||
| 		if (!TheMPAuDecContext->channels || | ||||
| 			!TheMPAuDecContext->sample_rate ) | ||||
| 		{ | ||||
| 			File->drop(); | ||||
| 			File = 0; | ||||
| 			delete TheMPAuDecContext; | ||||
| 			TheMPAuDecContext = 0; | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| CIrrKlangAudioStreamMP3::~CIrrKlangAudioStreamMP3() | ||||
| { | ||||
| 	if (File) | ||||
| 		File->drop(); | ||||
|  | ||||
| 	if (TheMPAuDecContext) | ||||
| 	{ | ||||
| 		mpaudec_clear(TheMPAuDecContext); | ||||
| 		delete TheMPAuDecContext; | ||||
| 	} | ||||
|  | ||||
| 	delete [] DecodeBuffer; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| //! returns format of the audio stream | ||||
| SAudioStreamFormat CIrrKlangAudioStreamMP3::getFormat() | ||||
| { | ||||
| 	return Format; | ||||
| } | ||||
|  | ||||
|  | ||||
| //! tells the audio stream to read n audio frames into the specified buffer | ||||
| ik_s32 CIrrKlangAudioStreamMP3::readFrames(void* target, ik_s32 frameCountToRead) | ||||
| { | ||||
| 	const int frameSize = Format.getFrameSize(); | ||||
|  | ||||
| 	int framesRead = 0; | ||||
| 	ik_u8* out = (ik_u8*)target; | ||||
|  | ||||
| 	while (framesRead < frameCountToRead) | ||||
| 	{ | ||||
| 		// no more samples?  ask the MP3 for more | ||||
| 		if (DecodedQueue.getSize() < frameSize) | ||||
| 		{ | ||||
| 			if (!decodeFrame() || EndOfFileReached) | ||||
| 				return framesRead; | ||||
|  | ||||
| 			// if the buffer is still empty, we are done | ||||
| 			if (DecodedQueue.getSize() < frameSize) | ||||
| 				return framesRead; | ||||
| 		} | ||||
|  | ||||
| 		const int framesLeft = frameCountToRead - framesRead; | ||||
| 		const int dequeSize = DecodedQueue.getSize() / frameSize; | ||||
| 		const int framesToRead = framesLeft < dequeSize ? framesLeft : dequeSize; | ||||
|  | ||||
| 		DecodedQueue.read(out, framesToRead * frameSize); | ||||
|  | ||||
| 		out += framesToRead * frameSize; | ||||
| 		framesRead += framesToRead; | ||||
| 		Position += framesToRead; | ||||
| 	} | ||||
|  | ||||
| 	return framesRead; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| bool CIrrKlangAudioStreamMP3::decodeFrame() | ||||
| { | ||||
|     int outputSize = 0; | ||||
|  | ||||
| 	while (!outputSize) | ||||
| 	{ | ||||
| 		if (InputPosition == InputLength) | ||||
| 		{ | ||||
| 			InputPosition = 0; | ||||
| 			InputLength = File->read(InputBuffer, IKP_MP3_INPUT_BUFFER_SIZE); | ||||
|  | ||||
| 			if (InputLength == 0) | ||||
| 			{ | ||||
| 				EndOfFileReached = true; | ||||
| 				return true; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		int rv = mpaudec_decode_frame( TheMPAuDecContext, (ik_s16*)DecodeBuffer, | ||||
| 									   &outputSize, | ||||
| 									   (ik_u8*)InputBuffer + InputPosition, | ||||
| 									   InputLength - InputPosition); | ||||
|  | ||||
| 		if (rv < 0) | ||||
| 			return false; | ||||
|  | ||||
| 		InputPosition += rv; | ||||
| 	} // end while | ||||
|  | ||||
| 	if (!FirstFrameRead) | ||||
| 	{ | ||||
| 		Format.ChannelCount = TheMPAuDecContext->channels; | ||||
| 		Format.SampleRate = TheMPAuDecContext->sample_rate; | ||||
| 		Format.SampleFormat = ESF_S16; | ||||
| 		Format.FrameCount = -1; // unknown lenght | ||||
|  | ||||
| 		FirstFrameRead = true; | ||||
| 	} | ||||
| 	else | ||||
| 	if (TheMPAuDecContext->channels != Format.ChannelCount || | ||||
| 		TheMPAuDecContext->sample_rate != Format.SampleRate) | ||||
| 	{ | ||||
| 		// Can't handle format changes mid-stream. | ||||
| 		return false; | ||||
|     } | ||||
|  | ||||
| 	if (!TheMPAuDecContext->parse_only) | ||||
| 	{ | ||||
| 		if (outputSize < 0) | ||||
| 		{ | ||||
| 			// Couldn't decode this frame.  Too bad, already lost it. | ||||
| 			// This should only happen when seeking. | ||||
|  | ||||
| 			outputSize = TheMPAuDecContext->frame_size; | ||||
| 			memset(DecodeBuffer, 0, outputSize * Format.getFrameSize()); | ||||
| 		} | ||||
|  | ||||
| 		DecodedQueue.write(DecodeBuffer, outputSize); | ||||
| 	} | ||||
|  | ||||
|     return true; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| //! sets the position of the audio stream. | ||||
| /** For example to let the stream be read from the beginning of the file again, | ||||
| setPosition(0) would be called. This is usually done be the sound engine to | ||||
| loop a stream after if has reached the end. Return true if sucessful and 0 if not. */ | ||||
| bool CIrrKlangAudioStreamMP3::setPosition(ik_s32 pos) | ||||
| { | ||||
| 	if (!File || !TheMPAuDecContext) | ||||
| 		return false; | ||||
|  | ||||
| 	if (pos == 0) | ||||
| 	{ | ||||
| 		// usually done for looping, just reset to start | ||||
|  | ||||
| 		File->seek(FileBegin); // skip possible ID3 header | ||||
|  | ||||
| 		EndOfFileReached = false; | ||||
|  | ||||
| 		DecodedQueue.clear(); | ||||
|  | ||||
| 		MPAuDecContext oldContext = *TheMPAuDecContext; | ||||
|  | ||||
| 		mpaudec_clear(TheMPAuDecContext); | ||||
| 		mpaudec_init(TheMPAuDecContext); | ||||
|  | ||||
| 		TheMPAuDecContext->bit_rate = oldContext.bit_rate; | ||||
| 		TheMPAuDecContext->channels = oldContext.channels; | ||||
| 		TheMPAuDecContext->frame_size = oldContext.frame_size; | ||||
| 		TheMPAuDecContext->sample_rate = oldContext.sample_rate; | ||||
|  | ||||
| 		InputPosition = 0; | ||||
| 		InputLength = 0; | ||||
| 		Position = 0; | ||||
| 		CurrentFramePosition = 0; | ||||
|  | ||||
| 		return true; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		// user wants to seek in the stream, so do this here | ||||
|  | ||||
| 		int scan_position = 0; | ||||
| 		int target_frame = 0; | ||||
| 		int frame_count = (int)FramePositionData.size(); | ||||
|  | ||||
| 		while (target_frame < frame_count) | ||||
| 		{ | ||||
| 			int frame_size = FramePositionData[target_frame].size; | ||||
|  | ||||
| 			if (pos <= scan_position + frame_size) | ||||
| 				break; | ||||
| 			else | ||||
| 			{ | ||||
| 				scan_position += frame_size; | ||||
| 				target_frame++; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
|  | ||||
| 		const int MAX_FRAME_DEPENDENCY = 10; | ||||
| 		target_frame = std::max(0, target_frame - MAX_FRAME_DEPENDENCY); | ||||
| 		setPosition(0); | ||||
|  | ||||
| 		File->seek(FramePositionData[target_frame].offset, false); | ||||
|  | ||||
| 		int i; | ||||
| 		for (i = 0; i < target_frame; i++) | ||||
| 		{ | ||||
| 			if (i>=(int)FramePositionData.size()) | ||||
| 			{ | ||||
| 				// internal error | ||||
| 				setPosition(0); | ||||
| 				return false; | ||||
| 			} | ||||
|  | ||||
| 			Position += FramePositionData[i].size; | ||||
| 		} | ||||
|  | ||||
| 		if (!decodeFrame() || EndOfFileReached) | ||||
| 		{ | ||||
| 			setPosition(0); | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
| 		int frames_to_consume = pos - Position; // PCM frames now | ||||
| 		if (frames_to_consume > 0) | ||||
| 		{ | ||||
| 			ik_u8 *buf = new ik_u8[frames_to_consume * Format.getFrameSize()]; | ||||
| 			readFrames(buf, frames_to_consume); | ||||
| 			delete[] buf; | ||||
| 		} | ||||
|  | ||||
|       	return true; | ||||
| 	} | ||||
|  | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
|  | ||||
| CIrrKlangAudioStreamMP3::QueueBuffer::QueueBuffer() | ||||
| { | ||||
| 	Capacity = 256; | ||||
| 	Size = 0; | ||||
|  | ||||
| 	Buffer = (ik_u8*)malloc(Capacity); | ||||
| } | ||||
|  | ||||
|  | ||||
| CIrrKlangAudioStreamMP3::QueueBuffer::~QueueBuffer() | ||||
| { | ||||
| 	free(Buffer); | ||||
| } | ||||
|  | ||||
| int CIrrKlangAudioStreamMP3::QueueBuffer::getSize() | ||||
| { | ||||
| 	return Size; | ||||
| } | ||||
|  | ||||
| void CIrrKlangAudioStreamMP3::QueueBuffer::write(const void* buffer, int size) | ||||
| { | ||||
| 	bool needRealloc = false; | ||||
|  | ||||
| 	while (size + Size > Capacity) | ||||
| 	{ | ||||
| 		Capacity *= 2; | ||||
| 		needRealloc = true; | ||||
| 	} | ||||
|  | ||||
|     if (needRealloc) | ||||
| 	{ | ||||
|         Buffer = (ik_u8*)realloc(Buffer, Capacity); | ||||
|     } | ||||
|  | ||||
| 	memcpy(Buffer + Size, buffer, size); | ||||
| 	Size += size; | ||||
| } | ||||
|  | ||||
|  | ||||
| int CIrrKlangAudioStreamMP3::QueueBuffer::read(void* buffer, int size) | ||||
| { | ||||
| 	int toRead = size < Size ? size : Size; | ||||
|  | ||||
| 	memcpy(buffer, Buffer, toRead); | ||||
| 	memmove(Buffer, Buffer + toRead, Size - toRead); | ||||
|  | ||||
| 	Size -= toRead; | ||||
| 	return toRead; | ||||
| } | ||||
|  | ||||
|  | ||||
| void CIrrKlangAudioStreamMP3::QueueBuffer::clear() | ||||
| { | ||||
| 	Size = 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| void CIrrKlangAudioStreamMP3::skipID3IfNecessary() | ||||
| { | ||||
| 	char header[10]; | ||||
| 	int read = File->read(&header, 10); | ||||
|  | ||||
| 	if (read == 10 && | ||||
| 		header[0] == 'I' && header[1] == 'D' && header[2] == '3') | ||||
| 	{ | ||||
| 		int versionMajor = header[3]; | ||||
| 		int versionMinor = header[4]; | ||||
| 		int flags = header[5]; | ||||
|  | ||||
| 		// IDv2 size looks like the following: ID3v2 size  4 * %0xxxxxxx. | ||||
| 		// Sick, but that's how it works. | ||||
|  | ||||
| 		int size = 0; | ||||
| 		size  = (header[6] & 0x7f) << (3*7); | ||||
| 		size |= (header[7] & 0x7f) << (2*7); | ||||
| 		size |= (header[8] & 0x7f) << (1*7); | ||||
| 		size |= (header[9] & 0x7f) ; | ||||
|  | ||||
| 		size += 10; // header size | ||||
|  | ||||
| 		FileBegin = size; | ||||
| 		File->seek(FileBegin); | ||||
| 	} | ||||
| 	else | ||||
| 		File->seek(0); | ||||
| } | ||||
|  | ||||
|  | ||||
| } // end namespace irrklang | ||||
		Reference in New Issue
	
	Block a user