Container support for gme decoder.
This commit is contained in:
		 Tony Miller
					Tony Miller
				
			
				
					committed by
					
						 Max Kellermann
						Max Kellermann
					
				
			
			
				
	
			
			
			 Max Kellermann
						Max Kellermann
					
				
			
						parent
						
							188e1b440e
						
					
				
				
					commit
					dadb6747ad
				
			| @@ -1,13 +1,21 @@ | ||||
| #include "config.h" | ||||
| #include "../decoder_api.h" | ||||
| #include "audio_check.h" | ||||
| #include "uri.h" | ||||
|  | ||||
| #include <glib.h> | ||||
| #include <assert.h> | ||||
| #include <errno.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #include <gme/gme.h> | ||||
|  | ||||
| #undef G_LOG_DOMAIN | ||||
| #define G_LOG_DOMAIN "gme" | ||||
|  | ||||
| #define SUBTUNE_PREFIX "tune_" | ||||
|  | ||||
| enum { | ||||
| 	GME_SAMPLE_RATE = 44100, | ||||
| 	GME_CHANNELS = 2, | ||||
| @@ -15,10 +23,91 @@ enum { | ||||
| 	GME_BUFFER_SAMPLES = GME_BUFFER_FRAMES * GME_CHANNELS, | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * returns the file path stripped of any /tune_xxx.* subtune | ||||
|  * suffix | ||||
|  */ | ||||
| static char * | ||||
| get_container_name(const char *path_fs) | ||||
| { | ||||
| 	const char *subtune_suffix = uri_get_suffix(path_fs); | ||||
| 	char *path_container = g_strdup(path_fs); | ||||
| 	char *pat = g_strconcat("*/" SUBTUNE_PREFIX "???.", subtune_suffix, NULL); | ||||
| 	GPatternSpec *path_with_subtune = g_pattern_spec_new(pat); | ||||
| 	g_free(pat); | ||||
| 	if (!g_pattern_match(path_with_subtune, | ||||
| 			     strlen(path_container), path_container, NULL)) { | ||||
| 		g_pattern_spec_free(path_with_subtune); | ||||
| 		return path_container; | ||||
| 	} | ||||
|  | ||||
| 	char *ptr = g_strrstr(path_container, "/" SUBTUNE_PREFIX); | ||||
| 	if (ptr != NULL) | ||||
| 		*ptr='\0'; | ||||
|  | ||||
| 	g_pattern_spec_free(path_with_subtune); | ||||
| 	return path_container; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * returns tune number from file.nsf/tune_xxx.* style path or 0 if no subtune | ||||
|  * is appended. | ||||
|  */ | ||||
| static int | ||||
| get_song_num(const char *path_fs) | ||||
| { | ||||
| 	const char *subtune_suffix = uri_get_suffix(path_fs); | ||||
| 	char *pat = g_strconcat("*/" SUBTUNE_PREFIX "???.", subtune_suffix, NULL); | ||||
| 	GPatternSpec *path_with_subtune = g_pattern_spec_new(pat); | ||||
| 	g_free(pat); | ||||
|  | ||||
| 	if (g_pattern_match(path_with_subtune, | ||||
| 			    strlen(path_fs), path_fs, NULL)) { | ||||
| 		char *sub = g_strrstr(path_fs, "/" SUBTUNE_PREFIX); | ||||
| 		g_pattern_spec_free(path_with_subtune); | ||||
| 		if(!sub) | ||||
| 			return 0; | ||||
|  | ||||
| 		sub += strlen("/" SUBTUNE_PREFIX); | ||||
| 		int song_num = strtol(sub, NULL, 10); | ||||
|  | ||||
| 		return song_num - 1; | ||||
| 	} else { | ||||
| 		g_pattern_spec_free(path_with_subtune); | ||||
| 		return 0; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static char * | ||||
| gme_container_scan(const char *path_fs, const unsigned int tnum) | ||||
| { | ||||
| 	Music_Emu *emu; | ||||
| 	const char* gme_err; | ||||
| 	unsigned int num_songs; | ||||
|  | ||||
| 	gme_err = gme_open_file(path_fs, &emu, GME_SAMPLE_RATE); | ||||
| 	if (gme_err != NULL) { | ||||
| 		g_warning("%s", gme_err); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	num_songs = gme_track_count(emu); | ||||
| 	/* if it only contains a single tune, don't treat as container */ | ||||
| 	if (num_songs < 2) | ||||
| 		return NULL; | ||||
|  | ||||
| 	const char *subtune_suffix = uri_get_suffix(path_fs); | ||||
| 	if (tnum <= num_songs){ | ||||
| 		char *subtune = g_strdup_printf( | ||||
| 			SUBTUNE_PREFIX "%03u.%s", tnum, subtune_suffix); | ||||
| 		return subtune; | ||||
| 	} else | ||||
| 		return NULL; | ||||
| } | ||||
|  | ||||
| static void | ||||
| gme_file_decode(struct decoder *decoder, const char *path_fs) | ||||
| { | ||||
| 	int track = 0; /* index of track to play */ | ||||
| 	float song_len; | ||||
| 	Music_Emu *emu; | ||||
| 	gme_info_t *ti; | ||||
| @@ -26,13 +115,17 @@ gme_file_decode(struct decoder *decoder, const char *path_fs) | ||||
| 	enum decoder_command cmd; | ||||
| 	short buf[GME_BUFFER_SAMPLES]; | ||||
| 	const char* gme_err; | ||||
| 	char *path_container = get_container_name(path_fs); | ||||
| 	int song_num = get_song_num(path_fs); | ||||
|  | ||||
| 	gme_err = gme_open_file(path_fs, &emu, GME_SAMPLE_RATE); | ||||
| 	gme_err = gme_open_file(path_container, &emu, GME_SAMPLE_RATE); | ||||
| 	g_free(path_container); | ||||
| 	if (gme_err != NULL) { | ||||
| 		g_warning("%s", gme_err); | ||||
| 		return; | ||||
| 	} | ||||
| 	if((gme_err = gme_track_info(emu, &ti, 0)) != NULL){ | ||||
|  | ||||
| 	if((gme_err = gme_track_info(emu, &ti, song_num)) != NULL){ | ||||
| 		g_warning("%s", gme_err); | ||||
| 		gme_delete(emu); | ||||
| 		return; | ||||
| @@ -57,7 +150,7 @@ gme_file_decode(struct decoder *decoder, const char *path_fs) | ||||
|  | ||||
| 	decoder_initialized(decoder, &audio_format, true, song_len); | ||||
|  | ||||
| 	if((gme_err = gme_start_track(emu, track)) != NULL) | ||||
| 	if((gme_err = gme_start_track(emu, song_num)) != NULL) | ||||
| 		g_warning("%s", gme_err); | ||||
|  | ||||
| 	/* play */ | ||||
| @@ -90,13 +183,17 @@ gme_tag_dup(const char *path_fs) | ||||
| 	Music_Emu *emu; | ||||
| 	gme_info_t *ti; | ||||
| 	const char* gme_err; | ||||
| 	char *path_container=get_container_name(path_fs); | ||||
| 	int song_num; | ||||
| 	song_num=get_song_num(path_fs); | ||||
|  | ||||
| 	gme_err = gme_open_file(path_fs, &emu, GME_SAMPLE_RATE); | ||||
| 	gme_err = gme_open_file(path_container, &emu, GME_SAMPLE_RATE); | ||||
| 	g_free(path_container); | ||||
| 	if (gme_err != NULL) { | ||||
| 		g_warning("%s", gme_err); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	if((gme_err = gme_track_info(emu, &ti, 0)) != NULL){ | ||||
| 	if((gme_err = gme_track_info(emu, &ti, song_num)) != NULL){ | ||||
| 		g_warning("%s", gme_err); | ||||
| 		gme_delete(emu); | ||||
| 		return NULL; | ||||
| @@ -106,8 +203,16 @@ gme_tag_dup(const char *path_fs) | ||||
| 	if(ti != NULL){ | ||||
| 		if(ti->length > 0) | ||||
| 			tag->time = ti->length / 1000; | ||||
| 		if(ti->song != NULL) | ||||
| 			tag_add_item(tag, TAG_TITLE, ti->song); | ||||
| 		if(ti->song != NULL){ | ||||
| 			if(gme_track_count(emu) > 1){ | ||||
| 				/* start numbering subtunes from 1 */ | ||||
| 				char *tag_title=g_strdup_printf("%s (%d/%d)", | ||||
| 					ti->song, song_num+1, gme_track_count(emu)); | ||||
| 				tag_add_item(tag, TAG_TITLE, tag_title); | ||||
| 				g_free(tag_title); | ||||
| 			}else | ||||
| 				tag_add_item(tag, TAG_TITLE, ti->song); | ||||
| 		} | ||||
| 		if(ti->author != NULL) | ||||
| 			tag_add_item(tag, TAG_ARTIST, ti->author); | ||||
| 		if(ti->game != NULL) | ||||
| @@ -135,4 +240,5 @@ const struct decoder_plugin gme_decoder_plugin = { | ||||
| 	.file_decode = gme_file_decode, | ||||
| 	.tag_dup = gme_tag_dup, | ||||
| 	.suffixes = gme_suffixes, | ||||
| 	.container_scan = gme_container_scan, | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user