⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gameswf_sound.cpp

📁 一个开源的Flash 播放器,可以在Windows/Linux 上运行
💻 CPP
字号:
// gameswf_sound.cpp	-- Thatcher Ulrich <tu@tulrich.com> 2003// This source code has been donated to the Public Domain.  Do// whatever you want with it.// Code to handle SWF sound-related tags.#include "gameswf_sound.h"#include "gameswf_stream.h"#include "gameswf_impl.h"#include "gameswf_log.h"namespace gameswf{	// Callback interface to host, for handling sounds.  If it's NULL,	// sound is ignored.	static sound_handler*	s_sound_handler = 0;	void	set_sound_handler(sound_handler* s)	// Called by host, to set a handler for all sounds.	// Can pass in 0 to disable sound.	{		s_sound_handler = s;	}	sound_handler*	get_sound_handler()	{		return s_sound_handler;	}	sound_sample_impl::~sound_sample_impl()	{		if (s_sound_handler)		{			s_sound_handler->delete_sound(m_sound_handler_id);		}	}	// Utility function to uncompress ADPCM.	static void	adpcm_expand(		void* data_out,		stream* in,		int sample_count,	// in stereo, this is number of *pairs* of samples		bool stereo);	void	define_sound_loader(stream* in, int tag_type, movie_definition_sub* m)	// Load a DefineSound tag.	{		assert(tag_type == 14);		Uint16	character_id = in->read_u16();		sound_handler::format_type	format = (sound_handler::format_type) in->read_uint(4);		int	sample_rate = in->read_uint(2);	// multiples of 5512.5		bool	sample_16bit = in->read_uint(1) ? true : false;		bool	stereo = in->read_uint(1) ? true : false;		int	sample_count = in->read_u32();		static int	s_sample_rate_table[] = { 5512, 11025, 22050, 44100 };		IF_VERBOSE_PARSE(log_msg("define sound: ch=%d, format=%d, rate=%d, 16=%d, stereo=%d, ct=%d\n",					 character_id, int(format), sample_rate, int(sample_16bit), int(stereo), sample_count));		// If we have a sound_handler, ask it to init this sound.		if (s_sound_handler)		{			int	data_bytes = 0;			unsigned char*	data = NULL;			if (format == sound_handler::FORMAT_ADPCM)			{				// Uncompress the ADPCM before handing data to host.				data_bytes = sample_count * (stereo ? 4 : 2);				data = new unsigned char[data_bytes];				adpcm_expand(data, in, sample_count, stereo);				format = sound_handler::FORMAT_NATIVE16;			}			else			{				// @@ This is pretty awful -- lots of copying, slow reading.				data_bytes = in->get_tag_end_position() - in->get_position();				data = new unsigned char[data_bytes];				for (int i = 0; i < data_bytes; i++)				{					data[i] = in->read_u8();				}				// Swap bytes on behalf of the host, to make it easier for the handler.				// @@ I'm assuming this is a good idea?	 Most sound handlers will prefer native endianness?				if (format == sound_handler::FORMAT_UNCOMPRESSED				    && sample_16bit)				{					#ifndef _TU_LITTLE_ENDIAN_					// Swap sample bytes to get big-endian format.					for (int i = 0; i < data_bytes - 1; i += 2)					{						swap(&data[i], &data[i+1]);					}					#endif // not _TU_LITTLE_ENDIAN_					format = sound_handler::FORMAT_NATIVE16;				}			}						int	handler_id = s_sound_handler->create_sound(				data,				data_bytes,				sample_count,				format,				s_sample_rate_table[sample_rate],				stereo);			sound_sample*	sam = new sound_sample_impl(handler_id);			m->add_sound_sample(character_id, sam);			delete [] data;		}	}	struct start_sound_tag : public execute_tag	{		Uint16	m_handler_id;		int	m_loop_count;		bool	m_stop_playback;		start_sound_tag()			:			m_handler_id(0),			m_loop_count(0),			m_stop_playback(false)		{		}		void	read(stream* in, int tag_type, movie_definition_sub* m, const sound_sample_impl* sam)		// Initialize this StartSound tag from the stream & given sample.		// Insert ourself into the movie.		{			assert(sam);			in->read_uint(2);	// skip reserved bits.			m_stop_playback = in->read_uint(1) ? true : false;			bool	no_multiple = in->read_uint(1) ? true : false;			bool	has_envelope = in->read_uint(1) ? true : false;			bool	has_loops = in->read_uint(1) ? true : false;			bool	has_out_point = in->read_uint(1) ? true : false;			bool	has_in_point = in->read_uint(1) ? true : false;			UNUSED(no_multiple);			UNUSED(has_envelope);						Uint32	in_point = 0;			Uint32	out_point = 0;			if (has_in_point) { in_point = in->read_u32(); }			if (has_out_point) { out_point = in->read_u32(); }			if (has_loops) { m_loop_count = in->read_u16(); }			// if (has_envelope) { env_count = read_uint8(); read envelope entries; }			m_handler_id = sam->m_sound_handler_id;			m->add_execute_tag(this);		}		void	execute(movie* m)		{			if (s_sound_handler)			{				if (m_stop_playback)				{					s_sound_handler->stop_sound(m_handler_id);				}				else				{					s_sound_handler->play_sound(m_handler_id, m_loop_count);				}			}		}	};	void	start_sound_loader(stream* in, int tag_type, movie_definition_sub* m)	// Load a StartSound tag.	{		assert(tag_type == 15);		Uint16	sound_id = in->read_u16();		sound_sample_impl*	sam = (sound_sample_impl*) m->get_sound_sample(sound_id);		if (sam)		{			start_sound_tag*	sst = new start_sound_tag();			sst->read(in, tag_type, m, sam);			IF_VERBOSE_PARSE(log_msg("start_sound tag: id=%d, stop = %d, loop ct = %d\n",						 sound_id, int(sst->m_stop_playback), sst->m_loop_count));		}		else		{			if (s_sound_handler)			{				log_error("start_sound_loader: sound_id %d is not defined\n", sound_id);			}		}			}	// void	define_button_sound(...) ???// @@ currently not implemented//	void	sound_stream_loader(stream* in, int tag_type, movie_definition_sub* m)//	// Load the various stream-related tags: SoundStreamHead,//	// SoundStreamHead2, SoundStreamBlock.//	{//	}	//	// ADPCM	//	// Data from Alexis' SWF reference	static int	s_index_update_table_2bits[2] = { -1,  2 };	static int	s_index_update_table_3bits[4] = { -1, -1,  2,  4 };	static int	s_index_update_table_4bits[8] = { -1, -1, -1, -1,  2,  4,  6,  8 };	static int	s_index_update_table_5bits[16] = { -1, -1, -1, -1, -1, -1, -1, -1, 1,  2,  4,  6,  8, 10, 13, 16 };	static int*	s_index_update_tables[4] = {		s_index_update_table_2bits,		s_index_update_table_3bits,		s_index_update_table_4bits,		s_index_update_table_5bits,	};	// Data from Jansen.  http://homepages.cwi.nl/~jack/	// Check out his Dutch retro punk songs, heh heh :)	const int STEPSIZE_CT = 89;	static int s_stepsize[STEPSIZE_CT] = {		7, 8, 9, 10, 11, 12, 13, 14, 16, 17,		19, 21, 23, 25, 28, 31, 34, 37, 41, 45,		50, 55, 60, 66, 73, 80, 88, 97, 107, 118,		130, 143, 157, 173, 190, 209, 230, 253, 279, 307,		337, 371, 408, 449, 494, 544, 598, 658, 724, 796,		876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,		2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,		5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,		15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767	};	// Algo from http://www.circuitcellar.com/pastissues/articles/richey110/text.htm	// And also Jansen.	// Here's another reference: http://www.geocities.com/SiliconValley/8682/aud3.txt	// Original IMA spec doesn't seem to be on the web :(	// @@ lots of macros here!  It seems that VC6 can't correctly	// handle integer template args, although it's happy to	// compile them?!//	void DO_SAMPLE(int n_bits, int& sample, int& stepsize_index, int raw_code)#define DO_SAMPLE(n_bits, sample, stepsize_index, raw_code)									\	{															\		assert(raw_code >= 0 && raw_code < (1 << n_bits));								\																\		static const int	HI_BIT = (1 << (n_bits - 1));								\		int*	index_update_table = s_index_update_tables[n_bits - 2];							\																\		/* Core of ADPCM. */												\																\		int	code_mag = raw_code & (HI_BIT - 1);									\		bool	code_sign_bit = (raw_code & HI_BIT) ? 1 : 0;								\		int	mag = (code_mag << 1) + 1;	/* shift in LSB (they do this so that pos & neg zero are different)*/	\																\		int	stepsize = s_stepsize[stepsize_index];									\																\		/* Compute the new sample.  It's the predicted value			*/					\		/* (i.e. the previous value), plus a delta.  The delta			*/					\		/* comes from the code times the stepsize.  going for			*/					\		/* something like: delta = stepsize * (code * 2 + 1) >> code_bits	*/					\		int	delta = (stepsize * mag) >> (n_bits - 1);								\		if (code_sign_bit) delta = -delta;										\																\		sample += delta;												\		sample = iclamp(sample, -32768, 32767);										\																\		/* Update our stepsize index.  Use a lookup table. */								\		stepsize_index += index_update_table[code_mag];									\		stepsize_index = iclamp(stepsize_index, 0, STEPSIZE_CT - 1);							\	}	struct in_stream	{		const unsigned char*	m_in_data;		int	m_current_bits;		int	m_unused_bits;		in_stream(const unsigned char* data)			:			m_in_data(data),			m_current_bits(0),			m_unused_bits(0)		{		}	};//	void DO_MONO_BLOCK(Sint16** out_data, int n_bits, int sample_count, stream* in, int sample, int stepsize_index)#define DO_MONO_BLOCK(out_data, n_bits, sample_count, in, sample, stepsize_index)						\	{															\		/* First sample doesn't need to be decompressed. */								\		sample_count--;													\		*(*out_data)++ = (Sint16) sample;										\																\		while (sample_count--)												\		{														\			int	raw_code = in->read_uint(n_bits);								\			DO_SAMPLE(n_bits, sample, stepsize_index, raw_code);	/* sample & stepsize_index are in/out params */	\			*(*out_data)++ = (Sint16) sample;									\		}														\	}//	void do_stereo_block(//		Sint16** out_data,	// in/out param//		int n_bits,//		int sample_count,//		stream* in,//		int left_sample,//		int left_stepsize_index,//		int right_sample,//		int right_stepsize_index//		)#define DO_STEREO_BLOCK(out_data, n_bits, sample_count, in, left_sample, left_stepsize_index, right_sample, right_stepsize_index) \	/* Uncompress 4096 stereo sample pairs of ADPCM. */									  \	{															  \		/* First samples don't need to be decompressed. */								  \		sample_count--;													  \		*(*out_data)++ = (Sint16) left_sample;										  \		*(*out_data)++ = (Sint16) right_sample;										  \																  \		while (sample_count--)												  \		{														  \			int	left_raw_code = in->read_uint(n_bits);								  \			DO_SAMPLE(n_bits, left_sample, left_stepsize_index, left_raw_code);					  \			*(*out_data)++ = (Sint16) left_sample;									  \																  \			int	right_raw_code = in->read_uint(n_bits);								  \			DO_SAMPLE(n_bits, right_sample, right_stepsize_index, right_raw_code);					  \			*(*out_data)++ = (Sint16) right_sample;									  \		}														  \	}	void	adpcm_expand(		void* out_data_void,		stream* in,		int sample_count,	// in stereo, this is number of *pairs* of samples		bool stereo)	// Utility function: uncompress ADPCM data from in stream to	// out_data[].	The output buffer must have (sample_count*2)	// bytes for mono, or (sample_count*4) bytes for stereo.	{		Sint16*	out_data = (Sint16*) out_data_void;		// Read header.		int	n_bits = in->read_uint(2) + 2;	// 2 to 5 bits		while (sample_count)		{			// Read initial sample & index values.			int	sample = in->read_sint(16);			int	stepsize_index = in->read_uint(6);			assert(STEPSIZE_CT >= (1 << 6));	// ensure we don't need to clamp.			int	samples_this_block = imin(sample_count, 4096);			sample_count -= samples_this_block;			if (stereo == false)			{#define DO_MONO(n) DO_MONO_BLOCK(&out_data, n, samples_this_block, in, sample, stepsize_index)				switch (n_bits)				{				default: assert(0); break;				case 2: DO_MONO(2); break;				case 3: DO_MONO(3); break;				case 4: DO_MONO(4); break;				case 5: DO_MONO(5); break;				}			}			else			{				// Stereo.				// Got values for left channel; now get initial sample				// & index for right channel.				int	right_sample = in->read_sint(16);				int	right_stepsize_index = in->read_uint(6);				assert(STEPSIZE_CT >= (1 << 6));	// ensure we don't need to clamp.#define DO_STEREO(n)					\	DO_STEREO_BLOCK(				\		&out_data, n, samples_this_block,	\		in, sample, stepsize_index,		\		right_sample, right_stepsize_index)							switch (n_bits)				{				default: assert(0); break;				case 2: DO_STEREO(2); break;				case 3: DO_STEREO(3); break;				case 4: DO_STEREO(4); break;				case 5: DO_STEREO(5); break;				}			}		}	}};	// end namespace gameswf// Local Variables:// mode: C++// c-basic-offset: 8 // tab-width: 8// indent-tabs-mode: t// End:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -