ft2-clone

Fasttracker 2 clone
Log | Files | Refs | README | LICENSE

ft2_audioselector.c (11751B)


      1 // for finding memory leaks in debug mode with Visual Studio
      2 #if defined _DEBUG && defined _MSC_VER
      3 #include <crtdbg.h>
      4 #endif
      5 
      6 #include <stdio.h>
      7 #include <stdint.h>
      8 #include "ft2_header.h"
      9 #include "ft2_config.h"
     10 #include "ft2_audio.h"
     11 #include "ft2_gui.h"
     12 #include "ft2_mouse.h"
     13 #include "ft2_audioselector.h"
     14 #include "ft2_structs.h"
     15 
     16 enum
     17 {
     18 	INPUT_DEVICE = 0,
     19 	OUTPUT_DEVICE = 1
     20 };
     21 
     22 #define MAX_DEV_STR_LEN 256
     23 
     24 // hide POSIX warnings
     25 #ifdef _MSC_VER
     26 #pragma warning(disable: 4996)
     27 #endif
     28 
     29 char *getAudioOutputDeviceFromConfig(void)
     30 {
     31 	bool audioDeviceRead = false;
     32 	char *devString = NULL;
     33 
     34 	FILE *f = UNICHAR_FOPEN(editor.audioDevConfigFileLocationU, "r");
     35 	if (f != NULL)
     36 	{
     37 		devString = (char *)malloc(MAX_DEV_STR_LEN+1);
     38 		if (devString == NULL)
     39 		{
     40 			fclose(f);
     41 			return NULL; // out of memory
     42 		}
     43 
     44 		devString[0] = '\0';
     45 		fgets(devString, MAX_DEV_STR_LEN, f);
     46 		fclose(f);
     47 
     48 		const int32_t devStringLen = (int32_t)strlen(devString);
     49 		if (devStringLen > 0)
     50 		{
     51 			if (devString[devStringLen-1] == '\n')
     52 				devString[devStringLen-1] = '\0';
     53 
     54 			if (!(devStringLen == 1 && devString[0] == ' ')) // space only = no device
     55 				audioDeviceRead = true;
     56 		}
     57 	}
     58 
     59 	if (!audioDeviceRead)
     60 	{
     61 		if (devString != NULL)
     62 			free(devString);
     63 
     64 		devString = strdup(DEFAULT_AUDIO_DEV_STR);
     65 	}
     66 
     67 	// SDL_OpenAudioDevice() doesn't seem to like an empty audio device string
     68 	if (devString != NULL && devString[0] == '\0')
     69 	{
     70 		free(devString);
     71 		return NULL;
     72 	}
     73 
     74 	return devString;
     75 }
     76 
     77 char *getAudioInputDeviceFromConfig(void)
     78 {
     79 	bool audioDeviceRead = false;
     80 	char *devString = NULL;
     81 
     82 	FILE *f = UNICHAR_FOPEN(editor.audioDevConfigFileLocationU, "r");
     83 	if (f != NULL)
     84 	{
     85 		devString = (char *)malloc(MAX_DEV_STR_LEN+1);
     86 		if (devString == NULL)
     87 		{
     88 			fclose(f);
     89 			return NULL; // out of memory
     90 		}
     91 
     92 		devString[0] = '\0';
     93 		fgets(devString, MAX_DEV_STR_LEN, f); // skip first line (we want the input device)
     94 		fgets(devString, MAX_DEV_STR_LEN, f);
     95 		fclose(f);
     96 
     97 		const int32_t devStringLen = (int32_t)strlen(devString);
     98 		if (devStringLen > 0)
     99 		{
    100 			if (devString[devStringLen-1] == '\n')
    101 				devString[devStringLen-1] = '\0';
    102 
    103 			if (!(devStringLen == 1 && devString[0] == ' ')) // space only = no device
    104 				audioDeviceRead = true;
    105 		}
    106 	}
    107 
    108 	if (!audioDeviceRead)
    109 	{
    110 		if (devString != NULL)
    111 			free(devString);
    112 
    113 		devString = strdup(DEFAULT_AUDIO_DEV_STR);
    114 	}
    115 
    116 	// SDL_OpenAudioDevice() doesn't seem to like an empty audio device string
    117 	if (devString != NULL && devString[0] == '\0')
    118 	{
    119 		free(devString);
    120 		return NULL;
    121 	}
    122 
    123 	return devString;
    124 }
    125 
    126 bool saveAudioDevicesToConfig(const char *outputDevice, const char *inputDevice)
    127 {
    128 	FILE *f = UNICHAR_FOPEN(editor.audioDevConfigFileLocationU, "w");
    129 	if (f == NULL)
    130 		return false;
    131 
    132 	if (outputDevice != NULL)
    133 		fputs(outputDevice, f);
    134 	else
    135 		fputc(' ', f);
    136 
    137 	fputc('\n', f);
    138 
    139 	if (inputDevice != NULL)
    140 		fputs(inputDevice, f);
    141 	else
    142 		fputc(' ', f);
    143 
    144 	fclose(f);
    145 	return true;
    146 }
    147 
    148 void drawAudioOutputList(void)
    149 {
    150 	clearRect(114, 18, AUDIO_SELECTORS_BOX_WIDTH, 66);
    151 
    152 	if (audio.outputDeviceNum == 0)
    153 	{
    154 		textOut(114, 18, PAL_FORGRND, "No audio output devices found!");
    155 		return;
    156 	}
    157 
    158 	for (int32_t i = 0; i < 6; i++)
    159 	{
    160 		const int32_t deviceEntry = getScrollBarPos(SB_AUDIO_OUTPUT_SCROLL) + i;
    161 		if (deviceEntry < audio.outputDeviceNum)
    162 		{
    163 			if (audio.outputDeviceNames[deviceEntry] == NULL)
    164 				continue;
    165 
    166 			const uint16_t y = 18 + (uint16_t)(i * 11);
    167 
    168 			if (audio.currOutputDevice != NULL)
    169 			{
    170 				if (strcmp(audio.currOutputDevice, audio.outputDeviceNames[deviceEntry]) == 0)
    171 					fillRect(114, y, AUDIO_SELECTORS_BOX_WIDTH, 10, PAL_BOXSLCT); // selection background color
    172 			}
    173 			else if (i == 0) // default audio device (always on top)
    174 			{
    175 				fillRect(114, y, AUDIO_SELECTORS_BOX_WIDTH, 10, PAL_BOXSLCT); // selection background color
    176 			}
    177 
    178 			char *tmpString = utf8ToCp850(audio.outputDeviceNames[deviceEntry], true);
    179 			if (tmpString != NULL)
    180 			{
    181 				textOutClipX(114, y, PAL_FORGRND, tmpString, 114 + AUDIO_SELECTORS_BOX_WIDTH);
    182 				free(tmpString);
    183 			}
    184 		}
    185 	}
    186 }
    187 
    188 void drawAudioInputList(void)
    189 {
    190 	clearRect(114, 105, AUDIO_SELECTORS_BOX_WIDTH, 44);
    191 
    192 	if (audio.inputDeviceNum == 0)
    193 	{
    194 		textOut(114, 105, PAL_FORGRND, "No audio input devices found!");
    195 		return;
    196 	}
    197 
    198 	for (int32_t i = 0; i < 4; i++)
    199 	{
    200 		const int32_t deviceEntry = getScrollBarPos(SB_AUDIO_INPUT_SCROLL) + i;
    201 		if (deviceEntry < audio.inputDeviceNum)
    202 		{
    203 			if (audio.inputDeviceNames[deviceEntry] == NULL)
    204 				continue;
    205 
    206 			const uint16_t y = 105 + (uint16_t)(i * 11);
    207 
    208 			if (audio.currInputDevice != NULL)
    209 			{
    210 				if (strcmp(audio.currInputDevice, audio.inputDeviceNames[deviceEntry]) == 0)
    211 					fillRect(114, y, AUDIO_SELECTORS_BOX_WIDTH, 10, PAL_BOXSLCT); // selection background color
    212 			}
    213 			else if (i == 0) // default audio device (always on top)
    214 			{
    215 				fillRect(114, y, AUDIO_SELECTORS_BOX_WIDTH, 10, PAL_BOXSLCT); // selection background color
    216 			}
    217 
    218 			char *tmpString = utf8ToCp850(audio.inputDeviceNames[deviceEntry], true);
    219 			if (tmpString != NULL)
    220 			{
    221 				textOutClipX(114, y, PAL_FORGRND, tmpString, 114 + AUDIO_SELECTORS_BOX_WIDTH);
    222 				free(tmpString);
    223 			}
    224 		}
    225 	}
    226 }
    227 
    228 bool testAudioDeviceListsMouseDown(void)
    229 {
    230 	if (!ui.configScreenShown || editor.currConfigScreen != CONFIG_SCREEN_AUDIO)
    231 		return false;
    232 
    233 	const int32_t mx = mouse.x;
    234 	const int32_t my = mouse.y;
    235 
    236 	if (my < 18 || my > 149 || mx < 114 || mx >= 114+AUDIO_SELECTORS_BOX_WIDTH)
    237 		return false;
    238 
    239 	if (my < 84)
    240 	{
    241 		// output device list
    242 
    243 		const int32_t deviceNum = (int32_t)scrollBars[SB_AUDIO_OUTPUT_SCROLL].pos + ((my - 18) / 11);
    244 		if (audio.outputDeviceNum <= 0 || deviceNum >= audio.outputDeviceNum)
    245 			return true;
    246 
    247 		char *devString = audio.outputDeviceNames[deviceNum];
    248 		if (devString != NULL && (audio.currOutputDevice == NULL || strcmp(audio.currOutputDevice, devString) != 0))
    249 		{
    250 			if (audio.currOutputDevice != NULL)
    251 				free(audio.currOutputDevice);
    252 
    253 			const uint32_t devStringLen = (uint32_t)strlen(devString);
    254 
    255 			audio.currOutputDevice = (char *)malloc(devStringLen+1);
    256 			if (audio.currOutputDevice == NULL)
    257 				return true;
    258 
    259 			audio.currOutputDevice[0] = '\0';
    260 
    261 			if (devStringLen > 0)
    262 				strcpy(audio.currOutputDevice, devString);
    263 
    264 			if (!setNewAudioSettings())
    265 				okBox(0, "System message", "Couldn't open audio output device!", NULL);
    266 			else
    267 				drawAudioOutputList();
    268 		}
    269 
    270 		return true;
    271 	}
    272 	else if (my >= 105)
    273 	{
    274 		// input device list
    275 
    276 		const int32_t deviceNum = (int32_t)scrollBars[SB_AUDIO_INPUT_SCROLL].pos + ((my - 105) / 11);
    277 		if (audio.inputDeviceNum <= 0 || deviceNum >= audio.inputDeviceNum)
    278 			return true;
    279 
    280 		char *devString = audio.inputDeviceNames[deviceNum];
    281 		if (devString != NULL && (audio.currInputDevice == NULL || strcmp(audio.currInputDevice, devString) != 0))
    282 		{
    283 			if (audio.currInputDevice != NULL)
    284 				free(audio.currInputDevice);
    285 
    286 			const uint32_t devStringLen = (uint32_t)strlen(devString);
    287 
    288 			audio.currInputDevice = (char *)malloc(devStringLen+1);
    289 			if (audio.currInputDevice == NULL)
    290 				return true;
    291 
    292 			audio.currInputDevice[0] = '\0';
    293 
    294 			if (devStringLen > 0)
    295 				strcpy(audio.currInputDevice, devString);
    296 
    297 			drawAudioInputList();
    298 		}
    299 
    300 		return true;
    301 	}
    302 
    303 	return false;
    304 }
    305 
    306 void freeAudioDeviceLists(void)
    307 {
    308 	for (int32_t i = 0; i < MAX_AUDIO_DEVICES; i++)
    309 	{
    310 		if (audio.outputDeviceNames[i] != NULL)
    311 		{
    312 			free(audio.outputDeviceNames[i]);
    313 			audio.outputDeviceNames[i] = NULL;
    314 		}
    315 
    316 		if (audio.inputDeviceNames[i] != NULL)
    317 		{
    318 			free(audio.inputDeviceNames[i]);
    319 			audio.inputDeviceNames[i] = NULL;
    320 		}
    321 
    322 		audio.outputDeviceNum = 0;
    323 		audio.inputDeviceNum  = 0;
    324 	}
    325 }
    326 
    327 void freeAudioDeviceSelectorBuffers(void)
    328 {
    329 	if (editor.audioDevConfigFileLocationU != NULL)
    330 	{
    331 		free(editor.audioDevConfigFileLocationU);
    332 		editor.audioDevConfigFileLocationU = NULL;
    333 	}
    334 
    335 	if (audio.currOutputDevice != NULL)
    336 	{
    337 		free(audio.currOutputDevice);
    338 		audio.currOutputDevice = NULL;
    339 	}
    340 
    341 	if (audio.currInputDevice != NULL)
    342 	{
    343 		free(audio.currInputDevice);
    344 		audio.currInputDevice = NULL;
    345 	}
    346 
    347 	if (audio.lastWorkingAudioDeviceName != NULL)
    348 	{
    349 		free(audio.lastWorkingAudioDeviceName);
    350 		audio.lastWorkingAudioDeviceName = NULL;
    351 	}
    352 
    353 	freeAudioDeviceLists();
    354 }
    355 
    356 void setToDefaultAudioOutputDevice(void)
    357 {
    358 	if (audio.currOutputDevice != NULL)
    359 	{
    360 		free(audio.currOutputDevice);
    361 		audio.currOutputDevice = NULL;
    362 	}
    363 
    364 	/* If we have more than one device, we can't know which one
    365 	** is the default (and thus not get its device name).
    366 	** SDL2 ought to have a function for this!
    367 	*/
    368 	if (SDL_GetNumAudioDevices(false) == 1)
    369 	{
    370 		const char *devName = SDL_GetAudioDeviceName(0, false);
    371 		if (devName != NULL)
    372 			audio.currOutputDevice = strdup(devName);
    373 	}
    374 }
    375 
    376 void setToDefaultAudioInputDevice(void)
    377 {
    378 	if (audio.currInputDevice != NULL)
    379 	{
    380 		free(audio.currInputDevice);
    381 		audio.currInputDevice = NULL;
    382 	}
    383 
    384 	/* If we have more than one device, we can't know which one
    385 	** is the default (and thus not get its device name).
    386 	** SDL2 ought to have a function for this!
    387 	*/
    388 	if (SDL_GetNumAudioDevices(true) == 1)
    389 	{
    390 		const char *devName = SDL_GetAudioDeviceName(0, true);
    391 		if (devName != NULL)
    392 			audio.currInputDevice = strdup(devName);
    393 	}
    394 }
    395 
    396 void rescanAudioDevices(void)
    397 {
    398 	const bool listShown = (ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_AUDIO);
    399 
    400 	freeAudioDeviceLists();
    401 
    402 	// GET AUDIO OUTPUT DEVICES
    403 
    404 	audio.outputDeviceNum = 1 + SDL_GetNumAudioDevices(false);
    405 	if (audio.outputDeviceNum > MAX_AUDIO_DEVICES)
    406 		audio.outputDeviceNum = MAX_AUDIO_DEVICES;
    407 
    408 	audio.outputDeviceNames[0] = strdup(DEFAULT_AUDIO_DEV_STR);
    409 
    410 	for (int32_t i = 1; i < audio.outputDeviceNum; i++)
    411 	{
    412 		const char *deviceName = SDL_GetAudioDeviceName(i-1, false);
    413 		if (deviceName == NULL)
    414 		{
    415 			audio.outputDeviceNum--; // hide device
    416 			continue;
    417 		}
    418 
    419 		const uint32_t stringLen = (uint32_t)strlen(deviceName);
    420 
    421 		audio.outputDeviceNames[i] = (char *)malloc(stringLen + 1);
    422 		if (audio.outputDeviceNames[i] == NULL)
    423 			break;
    424 
    425 		if (stringLen > 0)
    426 			strcpy(audio.outputDeviceNames[i], deviceName);
    427 	}
    428 
    429 	// GET AUDIO INPUT DEVICES
    430 
    431 	audio.inputDeviceNum = 1 + SDL_GetNumAudioDevices(true);
    432 	if (audio.inputDeviceNum > MAX_AUDIO_DEVICES)
    433 		audio.inputDeviceNum = MAX_AUDIO_DEVICES;
    434 
    435 	audio.inputDeviceNames[0] = strdup(DEFAULT_AUDIO_DEV_STR);
    436 
    437 	for (int32_t i = 1; i < audio.inputDeviceNum; i++)
    438 	{
    439 		const char *deviceName = SDL_GetAudioDeviceName(i-1, true);
    440 		if (deviceName == NULL)
    441 		{
    442 			audio.inputDeviceNum--; // hide device
    443 			continue;
    444 		}
    445 
    446 		const uint32_t stringLen = (uint32_t)strlen(deviceName);
    447 
    448 		audio.inputDeviceNames[i] = (char *)malloc(stringLen + 1);
    449 		if (audio.inputDeviceNames[i] == NULL)
    450 			break;
    451 
    452 		if (stringLen > 0)
    453 			strcpy(audio.inputDeviceNames[i], deviceName);
    454 	}
    455 
    456 	setScrollBarEnd(SB_AUDIO_OUTPUT_SCROLL, audio.outputDeviceNum);
    457 	setScrollBarPos(SB_AUDIO_OUTPUT_SCROLL, 0, false);
    458 	setScrollBarEnd(SB_AUDIO_INPUT_SCROLL, audio.inputDeviceNum);
    459 	setScrollBarPos(SB_AUDIO_INPUT_SCROLL, 0, false);
    460 
    461 	// DRAW LISTS
    462 
    463 	if (listShown)
    464 	{
    465 		drawAudioOutputList();
    466 		drawAudioInputList();
    467 		drawScrollBar(SB_AUDIO_OUTPUT_SCROLL);
    468 		drawScrollBar(SB_AUDIO_INPUT_SCROLL);
    469 	}
    470 }
    471 
    472 void scrollAudInputDevListUp(void)
    473 {
    474 	scrollBarScrollUp(SB_AUDIO_INPUT_SCROLL, 1);
    475 }
    476 
    477 void scrollAudInputDevListDown(void)
    478 {
    479 	scrollBarScrollDown(SB_AUDIO_INPUT_SCROLL, 1);
    480 }
    481 
    482 void scrollAudOutputDevListUp(void)
    483 {
    484 	scrollBarScrollUp(SB_AUDIO_OUTPUT_SCROLL, 1);
    485 }
    486 
    487 void scrollAudOutputDevListDown(void)
    488 {
    489 	scrollBarScrollDown(SB_AUDIO_OUTPUT_SCROLL, 1);
    490 }
    491 
    492 void sbAudOutputSetPos(uint32_t pos)
    493 {
    494 	if (ui.configScreenShown && (editor.currConfigScreen == CONFIG_SCREEN_AUDIO))
    495 		drawAudioOutputList();
    496 
    497 	(void)pos;
    498 }
    499 
    500 void sbAudInputSetPos(uint32_t pos)
    501 {
    502 	if (ui.configScreenShown && (editor.currConfigScreen == CONFIG_SCREEN_AUDIO))
    503 		drawAudioInputList();
    504 
    505 	(void)pos;
    506 }