decoder/sidplay: subtunes
This commit is contained in:
		 Mike Dawson
					Mike Dawson
				
			
				
					committed by
					
						 Max Kellermann
						Max Kellermann
					
				
			
			
				
	
			
			
			 Max Kellermann
						Max Kellermann
					
				
			
						parent
						
							f2ff2409ad
						
					
				
				
					commit
					85ce9aa7de
				
			
							
								
								
									
										1
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								NEWS
									
									
									
									
									
								
							| @@ -15,6 +15,7 @@ ver 0.16 (20??/??/??) | |||||||
|   - sndfile: new decoder plugin based on libsndfile |   - sndfile: new decoder plugin based on libsndfile | ||||||
|   - flac: load external cue sheet when no internal one |   - flac: load external cue sheet when no internal one | ||||||
|   - mpg123: new decoder plugin based on libmpg123 |   - mpg123: new decoder plugin based on libmpg123 | ||||||
|  |   - sidplay: support sub-tunes | ||||||
| * encoders: | * encoders: | ||||||
|   - twolame: new encoder plugin based on libtwolame |   - twolame: new encoder plugin based on libtwolame | ||||||
| * output: | * output: | ||||||
|   | |||||||
| @@ -21,6 +21,8 @@ extern "C" { | |||||||
| #include "../decoder_api.h" | #include "../decoder_api.h" | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #include <errno.h> | ||||||
|  | #include <stdlib.h> | ||||||
| #include <glib.h> | #include <glib.h> | ||||||
|  |  | ||||||
| #include <sidplay/sidplay2.h> | #include <sidplay/sidplay2.h> | ||||||
| @@ -29,6 +31,72 @@ extern "C" { | |||||||
| #undef G_LOG_DOMAIN | #undef G_LOG_DOMAIN | ||||||
| #define G_LOG_DOMAIN "sidplay" | #define G_LOG_DOMAIN "sidplay" | ||||||
|  |  | ||||||
|  | #define SUBTUNE_PREFIX "tune_" | ||||||
|  |  | ||||||
|  | static GPatternSpec *path_with_subtune; | ||||||
|  |  | ||||||
|  | static bool all_files_are_containers; | ||||||
|  |  | ||||||
|  | static bool | ||||||
|  | sidplay_init(const struct config_param *param) | ||||||
|  | { | ||||||
|  | 	all_files_are_containers=config_get_block_bool(param, | ||||||
|  | 		"all_files_are_containers", true); | ||||||
|  |  | ||||||
|  | 	path_with_subtune=g_pattern_spec_new( | ||||||
|  | 			"*/" SUBTUNE_PREFIX "???.sid"); | ||||||
|  |  | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | sidplay_finish() | ||||||
|  | { | ||||||
|  | 	g_pattern_spec_free(path_with_subtune); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * returns the file path stripped of any /tune_xxx.sid subtune | ||||||
|  |  * suffix | ||||||
|  |  */ | ||||||
|  | static char * | ||||||
|  | get_container_name(const char *path_fs) | ||||||
|  | { | ||||||
|  | 	char *path_container=g_strdup(path_fs); | ||||||
|  |  | ||||||
|  | 	if(!g_pattern_match(path_with_subtune, | ||||||
|  | 		strlen(path_container), path_container, NULL)) | ||||||
|  | 		return path_container; | ||||||
|  |  | ||||||
|  | 	char *ptr=g_strrstr(path_container, "/" SUBTUNE_PREFIX); | ||||||
|  | 	if(ptr) *ptr='\0'; | ||||||
|  |  | ||||||
|  | 	return path_container; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * returns tune number from file.sid/tune_xxx.sid style path or 1 if | ||||||
|  |  * no subtune is appended | ||||||
|  |  */ | ||||||
|  | static int | ||||||
|  | get_song_num(const char *path_fs) | ||||||
|  | { | ||||||
|  | 	if(g_pattern_match(path_with_subtune, | ||||||
|  | 		strlen(path_fs), path_fs, NULL)) { | ||||||
|  | 		char *sub=g_strrstr(path_fs, "/" SUBTUNE_PREFIX); | ||||||
|  | 		if(!sub) return 1; | ||||||
|  |  | ||||||
|  | 		sub+=strlen("/" SUBTUNE_PREFIX); | ||||||
|  | 		int song_num=strtol(sub, NULL, 10); | ||||||
|  |  | ||||||
|  | 		if (errno == EINVAL) | ||||||
|  | 			return 1; | ||||||
|  | 		else | ||||||
|  | 			return song_num; | ||||||
|  | 	} else | ||||||
|  | 		return 1; | ||||||
|  | } | ||||||
|  |  | ||||||
| static void | static void | ||||||
| sidplay_file_decode(struct decoder *decoder, const char *path_fs) | sidplay_file_decode(struct decoder *decoder, const char *path_fs) | ||||||
| { | { | ||||||
| @@ -36,13 +104,16 @@ sidplay_file_decode(struct decoder *decoder, const char *path_fs) | |||||||
|  |  | ||||||
| 	/* load the tune */ | 	/* load the tune */ | ||||||
|  |  | ||||||
| 	SidTune tune(path_fs, NULL, true); | 	char *path_container=get_container_name(path_fs); | ||||||
|  | 	SidTune tune(path_container, NULL, true); | ||||||
|  | 	g_free(path_container); | ||||||
| 	if (!tune) { | 	if (!tune) { | ||||||
| 		g_warning("failed to load file"); | 		g_warning("failed to load file"); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	tune.selectSong(1); | 	int song_num=get_song_num(path_fs); | ||||||
|  | 	tune.selectSong(song_num); | ||||||
|  |  | ||||||
| 	/* initialize the player */ | 	/* initialize the player */ | ||||||
|  |  | ||||||
| @@ -126,22 +197,68 @@ sidplay_file_decode(struct decoder *decoder, const char *path_fs) | |||||||
| static struct tag * | static struct tag * | ||||||
| sidplay_tag_dup(const char *path_fs) | sidplay_tag_dup(const char *path_fs) | ||||||
| { | { | ||||||
| 	SidTune tune(path_fs, NULL, true); | 	int song_num=get_song_num(path_fs); | ||||||
|  | 	char *path_container=get_container_name(path_fs); | ||||||
|  |  | ||||||
|  | 	SidTune tune(path_container, NULL, true); | ||||||
|  | 	g_free(path_container); | ||||||
| 	if (!tune) | 	if (!tune) | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  |  | ||||||
| 	const SidTuneInfo &info = tune.getInfo(); | 	const SidTuneInfo &info = tune.getInfo(); | ||||||
| 	struct tag *tag = tag_new(); | 	struct tag *tag = tag_new(); | ||||||
|  |  | ||||||
|  | 	/* title */ | ||||||
|  | 	const char *title; | ||||||
| 	if (info.numberOfInfoStrings > 0 && info.infoString[0] != NULL) | 	if (info.numberOfInfoStrings > 0 && info.infoString[0] != NULL) | ||||||
| 		tag_add_item(tag, TAG_ITEM_TITLE, info.infoString[0]); | 		title=info.infoString[0]; | ||||||
|  | 	else | ||||||
|  | 		title=""; | ||||||
|  |  | ||||||
|  | 	if(info.songs>1) { | ||||||
|  | 		char *tag_title=g_strdup_printf("%s (%d/%d)", | ||||||
|  | 			title, song_num, info.songs); | ||||||
|  | 		tag_add_item(tag, TAG_ITEM_TITLE, tag_title); | ||||||
|  | 		g_free(tag_title); | ||||||
|  | 	} else | ||||||
|  | 		tag_add_item(tag, TAG_ITEM_TITLE, title); | ||||||
|  |  | ||||||
|  | 	/* artist */ | ||||||
| 	if (info.numberOfInfoStrings > 1 && info.infoString[1] != NULL) | 	if (info.numberOfInfoStrings > 1 && info.infoString[1] != NULL) | ||||||
| 		tag_add_item(tag, TAG_ITEM_ARTIST, info.infoString[1]); | 		tag_add_item(tag, TAG_ITEM_ARTIST, info.infoString[1]); | ||||||
|  |  | ||||||
|  | 	/* track */ | ||||||
|  | 	char *track=g_strdup_printf("%d", song_num); | ||||||
|  | 	tag_add_item(tag, TAG_ITEM_TRACK, track); | ||||||
|  | 	g_free(track); | ||||||
|  |  | ||||||
| 	return tag; | 	return tag; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static char * | ||||||
|  | sidplay_container_scan(const char *path_fs, const unsigned int tnum) | ||||||
|  | { | ||||||
|  | 	SidTune tune(path_fs, NULL, true); | ||||||
|  | 	if (!tune) | ||||||
|  | 		return NULL; | ||||||
|  |  | ||||||
|  | 	const SidTuneInfo &info=tune.getInfo(); | ||||||
|  |  | ||||||
|  | 	/* Don't treat sids containing a single tune | ||||||
|  | 		as containers */ | ||||||
|  | 	if(!all_files_are_containers && info.songs<2) | ||||||
|  | 		return NULL; | ||||||
|  |  | ||||||
|  | 	/* Construct container/tune path names, eg. | ||||||
|  | 		Delta.sid/tune_001.sid */ | ||||||
|  | 	if(tnum<=info.songs) { | ||||||
|  | 		char *subtune= g_strdup_printf( | ||||||
|  | 			SUBTUNE_PREFIX "%03u.sid", tnum); | ||||||
|  | 		return subtune; | ||||||
|  | 	} else | ||||||
|  | 		return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
| static const char *const sidplay_suffixes[] = { | static const char *const sidplay_suffixes[] = { | ||||||
| 	"sid", | 	"sid", | ||||||
| 	NULL | 	NULL | ||||||
| @@ -150,12 +267,12 @@ static const char *const sidplay_suffixes[] = { | |||||||
| extern const struct decoder_plugin sidplay_decoder_plugin; | extern const struct decoder_plugin sidplay_decoder_plugin; | ||||||
| const struct decoder_plugin sidplay_decoder_plugin = { | const struct decoder_plugin sidplay_decoder_plugin = { | ||||||
| 	"sidplay", | 	"sidplay", | ||||||
| 	NULL, /* init() */ | 	sidplay_init, | ||||||
| 	NULL, /* finish() */ | 	sidplay_finish, | ||||||
| 	NULL, /* stream_decode() */ | 	NULL, /* stream_decode() */ | ||||||
| 	sidplay_file_decode, | 	sidplay_file_decode, | ||||||
| 	sidplay_tag_dup, | 	sidplay_tag_dup, | ||||||
| 	NULL, /* container_scan */ | 	sidplay_container_scan, | ||||||
| 	sidplay_suffixes, | 	sidplay_suffixes, | ||||||
| 	NULL, /* mime_types */ | 	NULL, /* mime_types */ | ||||||
| }; | }; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user