music_modplug.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 13 Jan 2012 03:15:19 -0500
changeset 561 87bdb4c81c0b
parent 542 3de4970b36d4
child 617 87116a42526e
permissions -rw-r--r--
Fixed memory crash loading Ogg Vorbis files on Windows
The pointer to the audio data could come from SDL_LoadWAV_RW() or from our other loaders, and we need to use the correct free() to release the memory. So we'll just use the SDL memory functions for consistency.
This pretty much only matters on Windows where we can't guarantee a certain C runtime so we provide our own malloc() and friends.
     1 #ifdef MODPLUG_MUSIC
     2 
     3 #include "music_modplug.h"
     4 
     5 static int current_output_channels=0;
     6 static int music_swap8=0;
     7 static int music_swap16=0;
     8 static ModPlug_Settings settings;
     9 
    10 int modplug_init(SDL_AudioSpec *spec)
    11 {
    12 	ModPlug_GetSettings(&settings);
    13 	settings.mFlags=MODPLUG_ENABLE_OVERSAMPLING;
    14 	current_output_channels=spec->channels;
    15 	settings.mChannels=spec->channels>1?2:1;
    16 	settings.mBits=spec->format&0xFF;
    17 
    18 	music_swap8 = 0;
    19 	music_swap16 = 0;
    20 
    21 	switch(spec->format)
    22 	{
    23 		case AUDIO_U8:
    24 		case AUDIO_S8: {
    25 			if ( spec->format == AUDIO_S8 ) {
    26 				music_swap8 = 1;
    27 			}
    28 			settings.mBits=8;
    29 		}
    30 		break;
    31 
    32 		case AUDIO_S16LSB:
    33 		case AUDIO_S16MSB: {
    34 			/* See if we need to correct MikMod mixing */
    35 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
    36 			if ( spec->format == AUDIO_S16MSB ) {
    37 #else
    38 			if ( spec->format == AUDIO_S16LSB ) {
    39 #endif
    40 				music_swap16 = 1;
    41 			}
    42 			settings.mBits=16;
    43 		}
    44 		break;
    45 
    46 		default: {
    47 			Mix_SetError("Unknown hardware audio format");
    48 			return -1;
    49 		}
    50 
    51 	}
    52 
    53 	settings.mFrequency=spec->freq; /*TODO: limit to 11025, 22050, or 44100 ? */
    54 	settings.mResamplingMode=MODPLUG_RESAMPLE_FIR;
    55 	settings.mReverbDepth=0;
    56 	settings.mReverbDelay=100;
    57 	settings.mBassAmount=0;
    58 	settings.mBassRange=50;
    59 	settings.mSurroundDepth=0;
    60 	settings.mSurroundDelay=10;
    61 	settings.mLoopCount=0;
    62 	ModPlug_SetSettings(&settings);
    63 	return 0;
    64 }
    65 
    66 /* Uninitialize the music players */
    67 void modplug_exit()
    68 {
    69 }
    70 
    71 /* Set the volume for a modplug stream */
    72 void modplug_setvolume(modplug_data *music, int volume)
    73 {
    74 	ModPlug_SetMasterVolume(music->file, volume*4);
    75 }
    76 
    77 /* Load a modplug stream from an SDL_RWops object */
    78 modplug_data *modplug_new_RW(SDL_RWops *rw, int freerw)
    79 {
    80 	modplug_data *music=NULL;
    81 	long offset,sz;
    82 	char *buf=NULL;
    83 
    84 	offset = SDL_RWtell(rw);
    85 	SDL_RWseek(rw, 0, RW_SEEK_END);
    86 	sz = SDL_RWtell(rw)-offset;
    87 	SDL_RWseek(rw, offset, RW_SEEK_SET);
    88 	buf=(char*)SDL_malloc(sz);
    89 	if(buf)
    90 	{
    91 		if(SDL_RWread(rw, buf, sz, 1)==1)
    92 		{
    93 			music=(modplug_data*)SDL_malloc(sizeof(modplug_data));
    94 			if (music)
    95 			{
    96 				music->playing=0;
    97 				music->file=ModPlug_Load(buf,sz);
    98 				if(!music->file)
    99 				{
   100 					SDL_free(music);
   101 					music=NULL;
   102 				}
   103 			}
   104 			else
   105 			{
   106 				SDL_OutOfMemory();
   107 			}
   108 		}
   109 		SDL_free(buf);
   110 	}
   111 	else
   112 	{
   113 		SDL_OutOfMemory();
   114 	}
   115 	if (freerw) {
   116 		SDL_RWclose(rw);
   117 	}
   118 	return music;
   119 }
   120 
   121 /* Start playback of a given modplug stream */
   122 void modplug_play(modplug_data *music)
   123 {
   124 	ModPlug_Seek(music->file,0);
   125 	music->playing=1;
   126 }
   127 
   128 /* Return non-zero if a stream is currently playing */
   129 int modplug_playing(modplug_data *music)
   130 {
   131 	return music && music->playing;
   132 }
   133 
   134 /* Play some of a stream previously started with modplug_play() */
   135 int modplug_playAudio(modplug_data *music, Uint8 *stream, int len)
   136 {
   137 	if (current_output_channels > 2) {
   138 		int small_len = 2 * len / current_output_channels;
   139 		int i;
   140 		Uint8 *src, *dst;
   141 
   142 		i=ModPlug_Read(music->file, stream, small_len);
   143 		if(i<small_len)
   144 		{
   145 			memset(stream+i,0,small_len-i);
   146 			music->playing=0;
   147 		}
   148 		/* and extend to len by copying channels */
   149 		src = stream + small_len;
   150 		dst = stream + len;
   151 
   152 		switch (settings.mBits) {
   153 			case 8:
   154 				for ( i=small_len/2; i; --i ) {
   155 					src -= 2;
   156 					dst -= current_output_channels;
   157 					dst[0] = src[0];
   158 					dst[1] = src[1];
   159 					dst[2] = src[0];
   160 					dst[3] = src[1];
   161 					if (current_output_channels == 6) {
   162 						dst[4] = src[0];
   163 						dst[5] = src[1];
   164 					}
   165 				}
   166 				break;
   167 			case 16:
   168 				for ( i=small_len/4; i; --i ) {
   169 					src -= 4;
   170 					dst -= 2 * current_output_channels;
   171 					dst[0] = src[0];
   172 					dst[1] = src[1];
   173 					dst[2] = src[2];
   174 					dst[3] = src[3];
   175 					dst[4] = src[0];
   176 					dst[5] = src[1];
   177 					dst[6] = src[2];
   178 					dst[7] = src[3];
   179 					if (current_output_channels == 6) {
   180 						dst[8] = src[0];
   181 						dst[9] = src[1];
   182 						dst[10] = src[2];
   183 						dst[11] = src[3];
   184 					}
   185 				}
   186 				break;
   187 		}
   188 	} else {
   189 		int i=ModPlug_Read(music->file, stream, len);
   190 		if(i<len)
   191 		{
   192 			memset(stream+i,0,len-i);
   193 			music->playing=0;
   194 		}
   195 	}
   196 	if ( music_swap8 ) {
   197 		Uint8 *dst;
   198 		int i;
   199 
   200 		dst = stream;
   201 		for ( i=len; i; --i ) {
   202 			*dst++ ^= 0x80;
   203 		}
   204 	} else
   205 	if ( music_swap16 ) {
   206 		Uint8 *dst, tmp;
   207 		int i;
   208 
   209 		dst = stream;
   210 		for ( i=(len/2); i; --i ) {
   211 			tmp = dst[0];
   212 			dst[0] = dst[1];
   213 			dst[1] = tmp;
   214 			dst += 2;
   215 		}
   216 	}
   217 	return 0;
   218 }
   219 
   220 /* Stop playback of a stream previously started with modplug_play() */
   221 void modplug_stop(modplug_data *music)
   222 {
   223 	music->playing=0;
   224 }
   225 
   226 /* Close the given modplug stream */
   227 void modplug_delete(modplug_data *music)
   228 {
   229 	ModPlug_Unload(music->file);
   230 	SDL_free(music);
   231 }
   232 
   233 /* Jump (seek) to a given position (time is in seconds) */
   234 void modplug_jump_to_time(modplug_data *music, double time)
   235 {
   236 	ModPlug_Seek(music->file,(int)(time*1000));
   237 }
   238 
   239 #endif