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