music_modplug.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 31 Dec 2011 23:28:23 -0500
changeset 528 bc0dfe8ae026
parent 521 565549e046b0
child 542 3de4970b36d4
permissions -rw-r--r--
Backed out changeset 1eddea51f162
     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 the given file */
    78 modplug_data *modplug_new(const char *file)
    79 {
    80 	SDL_RWops *rw;
    81 
    82 	rw = SDL_RWFromFile(file, "rb");
    83 	if ( rw == NULL ) {
    84 		/* FIXME: Free rw, need to free on delete */
    85 		SDL_SetError("Couldn't open %s", file);
    86 		return NULL;
    87 	}
    88 	return modplug_new_RW(rw, 1);
    89 
    90 }
    91 
    92 /* Load a modplug stream from an SDL_RWops object */
    93 modplug_data *modplug_new_RW(SDL_RWops *rw, int freerw)
    94 {
    95 	modplug_data *music=NULL;
    96 	long offset,sz;
    97 	char *buf=NULL;
    98 
    99 	offset = SDL_RWtell(rw);
   100 	SDL_RWseek(rw, 0, RW_SEEK_END);
   101 	sz = SDL_RWtell(rw)-offset;
   102 	SDL_RWseek(rw, offset, RW_SEEK_SET);
   103 	buf=(char*)malloc(sz);
   104 	if(buf)
   105 	{
   106 		if(SDL_RWread(rw, buf, sz, 1)==1)
   107 		{
   108 			music=(modplug_data*)malloc(sizeof(modplug_data));
   109 			if (music)
   110 			{
   111 				music->playing=0;
   112 				music->file=ModPlug_Load(buf,sz);
   113 				if(!music->file)
   114 				{
   115 					free(music);
   116 					music=NULL;
   117 				}
   118 			}
   119 			else
   120 			{
   121 				SDL_OutOfMemory();
   122 			}
   123 		}
   124 		free(buf);
   125 	}
   126 	else
   127 	{
   128 		SDL_OutOfMemory();
   129 	}
   130 	if (freerw) {
   131 		SDL_RWclose(rw);
   132 	}
   133 	return music;
   134 }
   135 
   136 /* Start playback of a given modplug stream */
   137 void modplug_play(modplug_data *music)
   138 {
   139 	ModPlug_Seek(music->file,0);
   140 	music->playing=1;
   141 }
   142 
   143 /* Return non-zero if a stream is currently playing */
   144 int modplug_playing(modplug_data *music)
   145 {
   146 	return music && music->playing;
   147 }
   148 
   149 /* Play some of a stream previously started with modplug_play() */
   150 int modplug_playAudio(modplug_data *music, Uint8 *stream, int len)
   151 {
   152 	if (current_output_channels > 2) {
   153 		int small_len = 2 * len / current_output_channels;
   154 		int i;
   155 		Uint8 *src, *dst;
   156 
   157 		i=ModPlug_Read(music->file, stream, small_len);
   158 		if(i<small_len)
   159 		{
   160 			memset(stream+i,0,small_len-i);
   161 			music->playing=0;
   162 		}
   163 		/* and extend to len by copying channels */
   164 		src = stream + small_len;
   165 		dst = stream + len;
   166 
   167 		switch (settings.mBits) {
   168 			case 8:
   169 				for ( i=small_len/2; i; --i ) {
   170 					src -= 2;
   171 					dst -= current_output_channels;
   172 					dst[0] = src[0];
   173 					dst[1] = src[1];
   174 					dst[2] = src[0];
   175 					dst[3] = src[1];
   176 					if (current_output_channels == 6) {
   177 						dst[4] = src[0];
   178 						dst[5] = src[1];
   179 					}
   180 				}
   181 				break;
   182 			case 16:
   183 				for ( i=small_len/4; i; --i ) {
   184 					src -= 4;
   185 					dst -= 2 * current_output_channels;
   186 					dst[0] = src[0];
   187 					dst[1] = src[1];
   188 					dst[2] = src[2];
   189 					dst[3] = src[3];
   190 					dst[4] = src[0];
   191 					dst[5] = src[1];
   192 					dst[6] = src[2];
   193 					dst[7] = src[3];
   194 					if (current_output_channels == 6) {
   195 						dst[8] = src[0];
   196 						dst[9] = src[1];
   197 						dst[10] = src[2];
   198 						dst[11] = src[3];
   199 					}
   200 				}
   201 				break;
   202 		}
   203 	} else {
   204 		int i=ModPlug_Read(music->file, stream, len);
   205 		if(i<len)
   206 		{
   207 			memset(stream+i,0,len-i);
   208 			music->playing=0;
   209 		}
   210 	}
   211 	if ( music_swap8 ) {
   212 		Uint8 *dst;
   213 		int i;
   214 
   215 		dst = stream;
   216 		for ( i=len; i; --i ) {
   217 			*dst++ ^= 0x80;
   218 		}
   219 	} else
   220 	if ( music_swap16 ) {
   221 		Uint8 *dst, tmp;
   222 		int i;
   223 
   224 		dst = stream;
   225 		for ( i=(len/2); i; --i ) {
   226 			tmp = dst[0];
   227 			dst[0] = dst[1];
   228 			dst[1] = tmp;
   229 			dst += 2;
   230 		}
   231 	}
   232 	return 0;
   233 }
   234 
   235 /* Stop playback of a stream previously started with modplug_play() */
   236 void modplug_stop(modplug_data *music)
   237 {
   238 	music->playing=0;
   239 }
   240 
   241 /* Close the given modplug stream */
   242 void modplug_delete(modplug_data *music)
   243 {
   244 	ModPlug_Unload(music->file);
   245 	free(music);
   246 }
   247 
   248 /* Jump (seek) to a given position (time is in seconds) */
   249 void modplug_jump_to_time(modplug_data *music, double time)
   250 {
   251 	ModPlug_Seek(music->file,(int)(time*1000));
   252 }
   253 
   254 #endif