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

📄 music.c

📁 SDL_mixer 是一个基于 SDL 的混音器
💻 C
📖 第 1 页 / 共 3 页
字号:
/*    SDL_mixer:  An audio mixer library based on the SDL library    Copyright (C) 1997-2004 Sam Lantinga    This library is free software; you can redistribute it and/or    modify it under the terms of the GNU Library General Public    License as published by the Free Software Foundation; either    version 2 of the License, or (at your option) any later version.    This library is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    Library General Public License for more details.    You should have received a copy of the GNU Library General Public    License along with this library; if not, write to the Free    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA    Sam Lantinga    slouken@libsdl.org*//* $Id: music.c 2408 2006-05-12 09:42:24Z slouken $ */#include <stdlib.h>#include <string.h>#include <ctype.h>#include <assert.h>#include "SDL_endian.h"#include "SDL_audio.h"#include "SDL_timer.h"#include "SDL_mixer.h"#define SDL_SURROUND#ifdef SDL_SURROUND#define MAX_OUTPUT_CHANNELS 6#else#define MAX_OUTPUT_CHANNELS 2#endif/* The music command hack is UNIX specific */#ifndef unix#undef CMD_MUSIC#endif#ifdef CMD_MUSIC#include "music_cmd.h"#endif#ifdef WAV_MUSIC#include "wavestream.h"#endif#if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)#  include "mikmod.h"#  if defined(LIBMIKMOD_VERSION)                /* libmikmod 3.1.8 */#    define UNIMOD			MODULE#    define MikMod_Init()		MikMod_Init(NULL)#    define MikMod_LoadSong(a,b)	Player_Load(a,b,0)#    ifndef LIBMIKMOD_MUSIC#    define MikMod_LoadSongRW(a,b)	Player_LoadRW(a,b,0)#    endif#    define MikMod_FreeSong		Player_Free     extern int MikMod_errno;#  else                                        /* old MikMod 3.0.3 */#    define MikMod_strerror(x)		_mm_errmsg[x])#    define MikMod_errno		_mm_errno#  endif#endif#ifdef MID_MUSIC#  ifdef USE_TIMIDITY_MIDI#    include "timidity.h"#  endif#  ifdef USE_NATIVE_MIDI#    include "native_midi.h"#  endif#  if defined(USE_TIMIDITY_MIDI) && defined(USE_NATIVE_MIDI)#    define MIDI_ELSE	else#  else#    define MIDI_ELSE#  endif#endif#ifdef OGG_MUSIC#include "music_ogg.h"#endif#ifdef MP3_MUSIC#include "dynamic_mp3.h"static SDL_AudioSpec used_mixer;#endifint volatile music_active = 1;static int volatile music_stopped = 0;static int music_loops = 0;static char *music_cmd = NULL;static Mix_Music * volatile music_playing = NULL;static int music_volume = MIX_MAX_VOLUME;static int music_swap8;static int music_swap16;struct _Mix_Music {	Mix_MusicType type;	union {#ifdef CMD_MUSIC		MusicCMD *cmd;#endif#ifdef WAV_MUSIC		WAVStream *wave;#endif#if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)		UNIMOD *module;#endif#ifdef MID_MUSIC#ifdef USE_TIMIDITY_MIDI		MidiSong *midi;#endif#ifdef USE_NATIVE_MIDI		NativeMidiSong *nativemidi;#endif#endif#ifdef OGG_MUSIC		OGG_music *ogg;#endif#ifdef MP3_MUSIC		SMPEG *mp3;#endif	} data;	Mix_Fading fading;	int fade_step;	int fade_steps;	int error;};#ifdef MID_MUSIC#ifdef USE_TIMIDITY_MIDIstatic int timidity_ok;static int samplesize;#endif#ifdef USE_NATIVE_MIDIstatic int native_midi_ok;#endif#endif/* Reference for converting mikmod output to 4/6 channels */static int current_output_channels;static Uint16 current_output_format;/* Used to calculate fading steps */static int ms_per_step;/* Local low-level functions prototypes */static void music_internal_initialize_volume(void);static void music_internal_volume(int volume);static int  music_internal_play(Mix_Music *music, double position);static int  music_internal_position(double position);static int  music_internal_playing();static void music_internal_halt(void);/* Support for hooking when the music has finished */static void (*music_finished_hook)(void) = NULL;void Mix_HookMusicFinished(void (*music_finished)(void)){	SDL_LockAudio();	music_finished_hook = music_finished;	SDL_UnlockAudio();}/* If music isn't playing, halt it if no looping is required, restart it *//* otherwhise. NOP if the music is playing */static int music_halt_or_loop (void){	/* Restart music if it has to loop */		if (!music_internal_playing()) 	{		/* Restart music if it has to loop at a high level */		if (music_loops && --music_loops)		{			Mix_Fading current_fade = music_playing->fading;			music_internal_play(music_playing, 0.0);			music_playing->fading = current_fade;		} 		else 		{			music_internal_halt();			if (music_finished_hook)				music_finished_hook();						return 0;		}	}		return 1;}/* Mixing function */void music_mixer(void *udata, Uint8 *stream, int len){	if ( music_playing && music_active ) {		/* Handle fading */		if ( music_playing->fading != MIX_NO_FADING ) {			if ( music_playing->fade_step++ < music_playing->fade_steps ) {				int volume;				int fade_step = music_playing->fade_step;				int fade_steps = music_playing->fade_steps;				if ( music_playing->fading == MIX_FADING_OUT ) {					volume = (music_volume * (fade_steps-fade_step)) / fade_steps;				} else { /* Fading in */					volume = (music_volume * fade_step) / fade_steps;				}				music_internal_volume(volume);			} else {				if ( music_playing->fading == MIX_FADING_OUT ) {					music_internal_halt();					if ( music_finished_hook ) {						music_finished_hook();					}					return;				}				music_playing->fading = MIX_NO_FADING;			}		}				if (music_halt_or_loop() == 0)			return;						switch (music_playing->type) {#ifdef CMD_MUSIC			case MUS_CMD:				/* The playing is done externally */				break;#endif#ifdef WAV_MUSIC			case MUS_WAV:				WAVStream_PlaySome(stream, len);				break;#endif#if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)			case MUS_MOD:				if (current_output_channels > 2) {					int small_len = 2 * len / current_output_channels;					int i;					Uint8 *src, *dst;					VC_WriteBytes((SBYTE *)stream, small_len);					/* and extend to len by copying channels */					src = stream + small_len;					dst = stream + len;					switch (current_output_format & 0xFF) {						case 8:							for ( i=small_len/2; i; --i ) {								src -= 2;								dst -= current_output_channels;								dst[0] = src[0];								dst[1] = src[1];								dst[2] = src[0];								dst[3] = src[1];								if (current_output_channels == 6) {									dst[4] = src[0];									dst[5] = src[1];								}							}							break;						case 16:							for ( i=small_len/4; i; --i ) {								src -= 4;								dst -= 2 * current_output_channels;								dst[0] = src[0];								dst[1] = src[1];								dst[2] = src[2];								dst[3] = src[3];								dst[4] = src[0];								dst[5] = src[1];								dst[6] = src[2];								dst[7] = src[3];								if (current_output_channels == 6) {									dst[8] = src[0];									dst[9] = src[1];									dst[10] = src[2];									dst[11] = src[3];								}							}							break;					}				}				else VC_WriteBytes((SBYTE *)stream, len);				if ( music_swap8 ) {					Uint8 *dst;					int i;					dst = stream;					for ( i=len; i; --i ) {						*dst++ ^= 0x80;					}				} else				if ( music_swap16 ) {					Uint8 *dst, tmp;					int i;					dst = stream;					for ( i=(len/2); i; --i ) {						tmp = dst[0];						dst[0] = dst[1];						dst[1] = tmp;						dst += 2;					}				}				break;#endif#ifdef MID_MUSIC#ifdef USE_TIMIDITY_MIDI			case MUS_MID:				if ( timidity_ok ) {					int samples = len / samplesize;  					Timidity_PlaySome(stream, samples);				}				break;#endif#endif#ifdef OGG_MUSIC			case MUS_OGG:								len = OGG_playAudio(music_playing->data.ogg, stream, len);				if (len > 0 && music_halt_or_loop())					OGG_playAudio(music_playing->data.ogg, stream, len);							break;#endif#ifdef MP3_MUSIC			case MUS_MP3:				smpeg.SMPEG_playAudio(music_playing->data.mp3, stream, len);				break;#endif			default:				/* Unknown music type?? */				break;		}	}}/* Initialize the music players with a certain desired audio format */int open_music(SDL_AudioSpec *mixer){	int music_error;#ifdef LIBMIKMOD_MUSIC	CHAR *list;#endif	music_error = 0;#ifdef WAV_MUSIC	if ( WAVStream_Init(mixer) < 0 ) {		++music_error;	}#endif#if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)	/* Set the MikMod music format */	music_swap8 = 0;	music_swap16 = 0;	switch (mixer->format) {		case AUDIO_U8:		case AUDIO_S8: {			if ( mixer->format == AUDIO_S8 ) {				music_swap8 = 1;			}			md_mode = 0;		}		break;		case AUDIO_S16LSB:		case AUDIO_S16MSB: {			/* See if we need to correct MikMod mixing */#if SDL_BYTEORDER == SDL_LIL_ENDIAN			if ( mixer->format == AUDIO_S16MSB ) {#else			if ( mixer->format == AUDIO_S16LSB ) {#endif				music_swap16 = 1;			}			md_mode = DMODE_16BITS;		}		break;		default: {			Mix_SetError("Unknown hardware audio format");			++music_error;		}	}	current_output_channels = mixer->channels;	current_output_format = mixer->format;	if ( mixer->channels > 1 ) {		if ( mixer->channels > MAX_OUTPUT_CHANNELS ) {			Mix_SetError("Hardware uses more channels than mixer");			++music_error;		}		md_mode |= DMODE_STEREO;	}	md_mixfreq = mixer->freq;	md_device  = 0;	md_volume  = 96;	md_musicvolume = 128;	md_sndfxvolume = 128;	md_pansep  = 128;	md_reverb  = 0;	md_mode    |= DMODE_HQMIXER|DMODE_SOFT_MUSIC|DMODE_SURROUND;#ifdef LIBMIKMOD_MUSIC	list = MikMod_InfoDriver();	if ( list )	  free(list);	else#endif	MikMod_RegisterDriver(&drv_nos);#ifdef LIBMIKMOD_MUSIC	list = MikMod_InfoLoader();	if ( list )	  free(list);	else#endif	MikMod_RegisterAllLoaders();	if ( MikMod_Init() ) {		Mix_SetError("%s", MikMod_strerror(MikMod_errno));		++music_error;	}#endif#ifdef MID_MUSIC#ifdef USE_TIMIDITY_MIDI	samplesize = mixer->size / mixer->samples;	if ( Timidity_Init(mixer->freq, mixer->format,	                    mixer->channels, mixer->samples) == 0 ) {		timidity_ok = 1;	} else {		timidity_ok = 0;	}#endif#ifdef USE_NATIVE_MIDI#ifdef USE_TIMIDITY_MIDI	native_midi_ok = !timidity_ok;	if ( native_midi_ok )#endif		native_midi_ok = native_midi_detect();#endif#endif#ifdef OGG_MUSIC	if ( OGG_init(mixer) < 0 ) {		++music_error;	}#endif#ifdef MP3_MUSIC	/* Keep a copy of the mixer */	used_mixer = *mixer;#endif	music_playing = NULL;	music_stopped = 0;	if ( music_error ) {		return(-1);	}	Mix_VolumeMusic(SDL_MIX_MAXVOLUME);	/* Calculate the number of ms for each callback */	ms_per_step = (int) (((float)mixer->samples * 1000.0) / mixer->freq);	return(0);}/* Portable case-insensitive string compare function */int MIX_string_equals(const char *str1, const char *str2){	while ( *str1 && *str2 ) {		if ( toupper((unsigned char)*str1) !=		     toupper((unsigned char)*str2) )			break;		++str1;		++str2;	}	return (!*str1 && !*str2);}/* Load a music file */

⌨️ 快捷键说明

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