SDL_MixAudioFormat making a complete f-ing mess of my audio

For some reason, if I use SDL_MixAudioFormat, it completely makes a mess of my audio. Crackly, etc.

No idea why. Here’s my code:

int VIDEO_ReadSmackerFile(char* dir, char* filename)
{
	char	filepath[256];
	int failed = 0;

	// Build a string for the path name
	sprintf(filepath, "%s\\%s", dir, filename);

	FILE* file = fopen(filepath, "rb");
	if (file == NULL)
		return 0;

	smk smkData = smk_open_filepointer(file, SMK_MODE_DISK);

	// Video data
	unsigned char* palette_data;
	unsigned char* image_data;
	unsigned char y_scale_mode;
	unsigned long width;
	unsigned long height;
	unsigned long currentFrame;
	unsigned long frameCount;
	double microSecPerFrame;

	// Audio data
	unsigned char* audio_data;
	unsigned char   a_trackmask, a_channels[7], a_depth[7];
	unsigned long   a_rate[7];
	unsigned long  audio_size;

	smk_info_all(smkData, &currentFrame, &frameCount, &microSecPerFrame);
	smk_info_video(smkData, &width, &height, &y_scale_mode);
	smk_info_audio(smkData, &a_trackmask, a_channels, a_depth, a_rate);
	smk_enable_video(smkData, 1);
	smk_enable_audio(smkData, 0, 1);

	SDL_AudioSpec audioFormat;
	SDL_zero(audioFormat);
	audioFormat.freq = a_rate[0];
	audioFormat.format = a_depth[0] == 16 ? AUDIO_S16 : AUDIO_U8;
	audioFormat.channels = a_channels[0];

	SDL_AudioSpec audioFormatObtained;

	SDL_AudioDeviceID deviceId = SDL_OpenAudioDevice(NULL, 0, &audioFormat, &audioFormatObtained, 0);

	if (deviceId == 0)
	{
		SDL_Log("SDL_OpenAudioDevice: %s\n", SDL_GetError());
		goto die;
	}
	else
	{
		SDL_PauseAudioDevice(deviceId, 0);
	}

	SDL_Log("Smacker Info - Res: %dx%d, Y Scale Mode: %d, Frame Count: %d, FPS: %lf, Sample Depth: %d, Sample Rate: %d", width, height, y_scale_mode, frameCount, 1000000.0 / microSecPerFrame, a_depth[0], a_rate[0]);

	smk_first(smkData);
	palette_data = (unsigned char*)smk_get_palette(smkData);
	image_data = (unsigned char*)smk_get_video(smkData);

	int videoTex = RENDER_GenTextureFromRAWData("VIDYA.RAW", width, height, image_data, palette_data);
	
	double lastFrameTime = 0;
#if 1
	while (1)
	{
		if ((getMicroseconds() - lastFrameTime) < microSecPerFrame)
		{
			if (INPUT_CheckAction(INPUT_FIRE))
			{
				INPUT_ClearAction(INPUT_FIRE);
				break;
			}

			idleCheck();
			continue;
		}

		smk_info_all(smkData, &currentFrame, NULL, NULL);
		palette_data = (unsigned char*)smk_get_palette(smkData);
		image_data = (unsigned char*)smk_get_video(smkData);

		audio_data = (unsigned char*)smk_get_audio(smkData, 0);
		audio_size = smk_get_audio_size(smkData, 0);

		unsigned char* audio_mixed = malloc(audio_size);
		memset(audio_mixed, 0, audio_size);
		SDL_MixAudioFormat(audio_mixed, audio_data, audioFormatObtained.format, audio_size, remapVolume(soundVolume));

		if (deviceId && SDL_QueueAudio(deviceId, audio_mixed, audio_size) == -1)
		{
			SDL_Log("SDL_QueueAudio: %s\n", SDL_GetError());
			failed = 1;
			goto die;
		}

		free(audio_mixed);
		
		RENDER_ClearAll();
		updateTextureData("VIDYA.RAW", image_data, palette_data);
		RENDER_DrawHUDTexture("VIDYA.RAW", width, height, HUDTEXF_ASPECTCORRECT, 0, 0, width, height, width, height);
		toggle();

		lastFrameTime = getMicroseconds();

		if (currentFrame == frameCount-1)
			break;
		else
			smk_next(smkData);
	}
#endif

die: // Free resources and die.
	if (deviceId)
	{
		SDL_ClearQueuedAudio(deviceId);
		SDL_CloseAudioDevice(deviceId);
		deviceId = 0;
	}

	RENDER_FreeTexture(&textures[videoTex], 1);

	smk_close(smkData);
	fclose(file);

	return (!failed);
}

If I use audio_data directly, it sounds perfect, but I need to adjust the volume, so I’m using this function. But, if I use it, the result is a garbage pile.

Here’s a video of what happens:

Instead of using SDL_MixAudioFormat, I did the following to adjust volume on the buffer in-place and it sorta works (has the occasional pop), but I want to know why the former wouldn’t work whatsoever, because if I can fix the audio distortions there, and also get rid of the pops, that’d be great.

		for (int i = 0; i < audio_size; i++)
		{
			audio_data[i] *= fix16_to_float(soundVolume);
		}

Whenever I’ve used SDL_MixAudioFormat() it’s worked fine. The only suspicious thing I can see in your code is that the audio can seemingly be either AUDIO_S16 or AUDIO_U8 format, but you always initialise the audio_mixed buffer to zero. That’s correct for AUDIO_S16 but not for AUDIO_U8 (you need to initialise it to 128 for that format).

3 Likes

That was exactly the problem. Thank you so very much.

2 Likes