changeset 1123:edf2a1f1e58b trunk

[svn] Implemented DAE feature (enabled by default)
author zither
date Sat, 26 May 2007 09:21:13 -0700
parents f1571687dca1
children 7447be3ed29b
files ChangeLog src/cdaudio-ng/cdaudio-ng.c
diffstat 2 files changed, 326 insertions(+), 86 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sat May 26 08:49:57 2007 -0700
+++ b/ChangeLog	Sat May 26 09:21:13 2007 -0700
@@ -1,3 +1,13 @@
+2007-05-26 15:49:57 +0000  Michael Farber <01mf02@gmail.com>
+  revision [2410]
+  - Fix a little spelling error (It's not TiMiDIty just like it's not 
+  FireFox)
+  
+  
+  trunk/src/timidity/src/xmms-timidity.c |    2 +-
+  1 file changed, 1 insertion(+), 1 deletion(-)
+
+
 2007-05-25 09:50:20 +0000  Giacomo Lozito <james@develia.org>
   revision [2408]
   - amidi-plug: small changes
--- a/src/cdaudio-ng/cdaudio-ng.c	Sat May 26 08:49:57 2007 -0700
+++ b/src/cdaudio-ng/cdaudio-ng.c	Sat May 26 09:21:13 2007 -0700
@@ -1,7 +1,13 @@
 
 /*
 	todo: 
-		- if any cdio_* returns an error, stop playing immediately
+		- move stuff into cdaudio-ng.h
+		- vis_pcm...?!
+		- limit cd read speed
+		- cddb
+		- dialogs
+		- remove //'s & todo's
+		- additional comments
 */
 
 #include <string.h>
@@ -22,11 +28,13 @@
 
 #include <audacious/i18n.h>
 #include <audacious/configdb.h>
+#include <audacious/plugin.h>
 #include <audacious/util.h>
-#include <audacious/titlestring.h>
 #include <audacious/output.h>
 
 #define DEF_STRING_LEN	256
+#define CDROM_DIR		"cdda://default"
+#define CDDA_DAE_FRAMES	8
 
 
 typedef struct {
@@ -34,20 +42,32 @@
 	char				performer[DEF_STRING_LEN];
 	char				name[DEF_STRING_LEN];
 	char				genre[DEF_STRING_LEN];
-	int					startlsn;
-	int					endlsn;
+	lsn_t				startlsn;
+	lsn_t				endlsn;
 
 } trackinfo_t;
 
+typedef struct {
+
+	lsn_t				startlsn;
+	lsn_t				endlsn;
+	lsn_t				currlsn;
+	lsn_t				seektime;	/* in miliseconds */
+	InputPlayback		*pplayback;
+	GThread				*thread;
+
+} dae_params_t;
+
 
 static int				firsttrackno = -1;
 static int				lasttrackno = -1;
-static cdrom_drive_t	*pcdrom_drive = NULL;
+static CdIo_t			*pcdio = NULL;
 static trackinfo_t		*trackinfo = NULL;
 static char				album_name[DEF_STRING_LEN];
-static gboolean			use_dao = FALSE;
+static gboolean			use_dae = TRUE;
 static gboolean			is_paused = FALSE;
 static int				playing_track = -1;
+static dae_params_t		*pdae_params = NULL;
 
 
 static void				cdaudio_init();
@@ -67,8 +87,10 @@
 static void				cdaudio_file_info_box(gchar *filename);
 static TitleInput		*cdaudio_get_song_tuple(gchar *filename);
 
+static void				*dae_playing_thread_core(dae_params_t *pdae_params);
 static int				calculate_track_length(int startlsn, int endlsn);
 static int				find_trackno_from_filename(char *filename);
+static void				cleanup_on_error();
 
 /*
 static int				calculate_digit_sum(int n);
@@ -79,7 +101,7 @@
 static InputPlugin inputplugin = {
 	NULL,
 	NULL,
-	"Zither's CD Audio Plugin",
+	"CD Audio Plugin NG",
 	cdaudio_init,
 	cdaudio_about,
 	cdaudio_configure,
@@ -108,9 +130,14 @@
 
 DECLARE_PLUGIN(cdaudio, NULL, NULL, cdaudio_iplist, NULL, NULL, NULL, NULL);
 
+
 void cdaudio_init()
 {
-	cdio_init();
+	if (!cdio_init()) {
+		fprintf(stderr, "cdaudio-ng: failed to initialize cdio subsystem\n");
+		cleanup_on_error();
+		return;
+	}
 }
 
 void cdaudio_about()
@@ -123,49 +150,66 @@
 
 gint cdaudio_is_our_file(gchar *filename)
 {
-	printf("is_our_file(\"%s\")\n", filename);
 	if ((filename != NULL) && strlen(filename) > 4 && (!strcasecmp(filename + strlen(filename) - 4, ".cda"))) {
-		if (pcdrom_drive == NULL) {		/* no CD information yet */
-			printf("No CD information, rescanning\n");
-			cdaudio_scan_dir("/mnt/cdrom");	// todo: :)
+			/* no CD information yet */
+		if (pcdio == NULL) {
+			printf("cdaudio-ng: no cd information, scanning\n");
+			cdaudio_scan_dir(CDROM_DIR);
 		}
-		
-		if (cdio_get_media_changed(pcdrom_drive->p_cdio)) {
-			printf("CD changed, rescanning\n");
-			cdaudio_scan_dir("/mnt/cdrom"); // todo: change the hardcoded path
+
+			/* reload the cd information if the media has changed */
+		if (cdio_get_media_changed(pcdio)) {
+			printf("cdaudio-ng: cd changed, rescanning\n");
+			cdaudio_scan_dir(CDROM_DIR);
 		}
-		
-		return 1;
+
+			/* check if the requested track actually exists on the current audio cd */
+		int trackno = find_trackno_from_filename(filename);
+		if (trackno < firsttrackno || trackno > lasttrackno)
+			return FALSE;
+
+		return TRUE;
 	}
 	else
-		return 0;
+		return FALSE;
 }
 
 GList *cdaudio_scan_dir(gchar *dirname)
 {
-	printf("scan_dir(\"%s\")\n", dirname);
-	
-	if (strstr(dirname, "/mnt/cdrom") == NULL)	// todo: replace this with a more standardised string
+		/* if the given dirname does not belong to us, we return NULL */
+	if (strstr(dirname, CDROM_DIR) == NULL)
 		return NULL;
-	
+
 		/* find the first available, audio capable, cd drive  */
 	char **ppcd_drives = cdio_get_devices_with_cap(NULL, CDIO_FS_AUDIO, false);
 	if (ppcd_drives != NULL) { /* we have at least one audio capable cd drive */
-		pcdrom_drive = cdio_cddap_identify(*ppcd_drives, 1, NULL);
+		pcdio = cdio_open(*ppcd_drives, DRIVER_UNKNOWN);
+		if (pcdio == NULL) {
+			fprintf(stderr, "cdaudio-ng: failed to open cd\n");
+			cleanup_on_error();
+			return NULL;
+		}
 	}
 	else {
-		printf("Unable find or access a CD-ROM drive with an audio CD in it.\n");
+		fprintf(stderr, "cdaudio-ng: unable find or access a cdda capable drive\n");
+		cleanup_on_error();
 		return NULL;
 	}
 	cdio_free_device_list(ppcd_drives);
 
 		/* get track information */
+	cdrom_drive_t *pcdrom_drive = cdio_cddap_identify_cdio(pcdio, 1, NULL);	// todo : check return / NULL
 	firsttrackno = cdio_get_first_track_num(pcdrom_drive->p_cdio);
 	lasttrackno = cdio_get_last_track_num(pcdrom_drive->p_cdio);
+	if (firsttrackno == CDIO_INVALID_TRACK || lasttrackno == CDIO_INVALID_TRACK) {
+		fprintf(stderr, "cdaudio-ng: failed to retrieve first/last track number");
+		cleanup_on_error();
+		return NULL;
+	}
 
 		/* add track "file" names to the list */
 	GList *list = NULL;
-	if (trackinfo != NULL)
+	if (trackinfo != NULL) /* if a previously allocated track information exists, we free it */
 		free(trackinfo);
 	trackinfo = (trackinfo_t *) malloc(sizeof(trackinfo_t) * (lasttrackno + 1));
 	int trackno;
@@ -189,6 +233,13 @@
 
 		trackinfo[trackno].startlsn = cdio_get_track_lsn(pcdrom_drive->p_cdio, trackno);
 		trackinfo[trackno].endlsn = cdio_get_track_last_lsn(pcdrom_drive->p_cdio, trackno);
+		
+		if (trackinfo[trackno].startlsn == CDIO_INVALID_LSN || trackinfo[trackno].endlsn == CDIO_INVALID_LSN) {
+			fprintf(stderr, "cdaudio-ng: failed to retrieve stard/end lsn for track %d\n", trackno);
+			g_list_free(list);
+			cleanup_on_error();
+			return NULL;
+		}
 	}
 
 	return list;
@@ -196,32 +247,60 @@
 
 void cdaudio_play_file(InputPlayback *pinputplayback)
 {	
-	printf("play_file(\"%s\")\n", pinputplayback->filename);
-	
 	if (trackinfo == NULL) {
-		printf("No CD information, rescanning\n");
-		cdaudio_scan_dir("/mnt/cdrom"); // todo: change the hardcoded path
+		printf("cdaudio-ng: no cd information, scanning\n");
+		cdaudio_scan_dir(CDROM_DIR);
 	}
 
-	if (cdio_get_media_changed(pcdrom_drive->p_cdio)) {
-		printf("CD changed, rescanning\n");
-		cdaudio_scan_dir("/mnt/cdrom"); // todo: change the hardcoded path
+	if (cdio_get_media_changed(pcdio)) {
+		printf("cdaudio-ng: cd changed, rescanning\n");
+		cdaudio_scan_dir(CDROM_DIR);
 	}
-	
+
 	int trackno = find_trackno_from_filename(pinputplayback->filename);
-	if (trackno < firsttrackno || trackno > lasttrackno)
+	if (trackno < firsttrackno || trackno > lasttrackno) {
+		fprintf(stderr, "cdaudio-ng: trackno %d should be between %d and %d\n", trackno, firsttrackno, lasttrackno);
+		cleanup_on_error();
 		return;
-
-	msf_t startmsf, endmsf;
-	cdio_lsn_to_msf(trackinfo[trackno].startlsn, &startmsf);
-	cdio_lsn_to_msf(trackinfo[trackno].endlsn, &endmsf);
-	cdio_audio_play_msf(pcdrom_drive->p_cdio, &startmsf, &endmsf);
+	}
 
 	pinputplayback->playing = TRUE;
 	playing_track = trackno;
-	
+	is_paused = FALSE;
+
+	if (use_dae) {
+		if (pdae_params != NULL) {
+			fprintf(stderr, "cdaudio-ng: dae playback seems to be already started\n");
+			return;
+		}
+
+		if (pinputplayback->output->open_audio(FMT_S16_LE, 44100, 2) == 0) {
+			fprintf(stderr, "cdaudio-ng: failed open audio output\n");
+			cleanup_on_error();
+			return;
+		}
+
+		pdae_params = (dae_params_t *) malloc(sizeof(dae_params_t));
+		pdae_params->startlsn = trackinfo[trackno].startlsn;
+		pdae_params->endlsn = trackinfo[trackno].endlsn;
+		pdae_params->pplayback = pinputplayback;
+		pdae_params->seektime = -1;
+		pdae_params->currlsn = trackinfo[trackno].startlsn;
+		pdae_params->thread = g_thread_create((GThreadFunc) dae_playing_thread_core, pdae_params, TRUE, NULL);
+	}
+	else {
+		msf_t startmsf, endmsf;
+		cdio_lsn_to_msf(trackinfo[trackno].startlsn, &startmsf);
+		cdio_lsn_to_msf(trackinfo[trackno].endlsn, &endmsf);
+		if (cdio_audio_play_msf(pcdio, &startmsf, &endmsf) != DRIVER_OP_SUCCESS) {
+			fprintf(stderr, "cdaudio-ng: failed to play analog audio cd\n");
+			cleanup_on_error();
+			return;
+		}
+	}
+
 	char title[DEF_STRING_LEN];
-	
+
 	if (strlen(trackinfo[trackno].performer) > 0) {
 		strcpy(title, trackinfo[trackno].performer);
 		strcat(title, " - ");
@@ -229,44 +308,76 @@
 	else
 		strcpy(title, "");
 	strcat(title, trackinfo[trackno].name);
-	
+
 	inputplugin.set_info(title, calculate_track_length(trackinfo[trackno].startlsn, trackinfo[trackno].endlsn), 128000, 44100, 2);
 }
 
 void cdaudio_stop(InputPlayback *pinputplayback)
 { 
-	printf("stop(\"%s\")\n", pinputplayback->filename);
-
-	cdio_audio_stop(pcdrom_drive->p_cdio);
 	pinputplayback->playing = FALSE;
 	playing_track = -1;
+	is_paused = FALSE;
+
+	if (use_dae) {
+		if (pdae_params != NULL) {
+			g_thread_join(pdae_params->thread);
+			free(pdae_params);
+			pdae_params = NULL;
+		}
+	}
+	else {
+		if (cdio_audio_stop(pcdio) != DRIVER_OP_SUCCESS) {
+			fprintf(stderr, "cdaudio-ng: failed to stop analog cd\n");
+			cleanup_on_error();
+			return;
+		}
+	}
 }
 
 void cdaudio_pause(InputPlayback *pinputplayback, gshort paused)
 {
 	if (!is_paused) {
 		is_paused = TRUE;
-		cdio_audio_pause(pcdrom_drive->p_cdio);
+		if (!use_dae)
+			if (cdio_audio_pause(pcdio) != DRIVER_OP_SUCCESS) {
+				fprintf(stderr, "cdaudio-ng: failed to pause analog cd\n");
+				cleanup_on_error();
+				return;
+			}
 	}
 	else {
 		is_paused = FALSE;
-		cdio_audio_resume(pcdrom_drive->p_cdio);
+		if (!use_dae)
+			if (cdio_audio_resume(pcdio) != DRIVER_OP_SUCCESS) {
+				fprintf(stderr, "cdaudio-ng: failed to resume analog cd\n");
+				cleanup_on_error();
+				return;
+			}
 	}
 }
 
 void cdaudio_seek(InputPlayback *pinputplayback, gint time)
 {
-	printf("seek(%d)\n", time);
 	if (playing_track == -1)
 		return;
 
-	int lsnoffs = (time * 75);
-	int startlsn = trackinfo[playing_track].startlsn + lsnoffs;
-
-	msf_t startmsf, endmsf;
-	cdio_lsn_to_msf(startlsn, &startmsf);
-	cdio_lsn_to_msf(trackinfo[playing_track].endlsn, &endmsf);
-	cdio_audio_play_msf(pcdrom_drive->p_cdio, &startmsf, &endmsf);
+	if (use_dae) {
+		if (pdae_params != NULL) {
+			pdae_params->seektime = time * 1000;
+		}
+	}
+	else {
+		int newstartlsn = trackinfo[playing_track].startlsn + time * 75;
+		msf_t startmsf, endmsf;
+		cdio_lsn_to_msf(newstartlsn, &startmsf);
+		cdio_lsn_to_msf(trackinfo[playing_track].endlsn, &endmsf);
+	
+		if (cdio_audio_play_msf(pcdio, &startmsf, &endmsf) != DRIVER_OP_SUCCESS) {
+			fprintf(stderr, "cdaudio-ng: failed to play analog cd\n");
+			cleanup_on_error();
+			return;
+		}
+	}
 }
 
 gint cdaudio_get_time(InputPlayback *pinputplayback)
@@ -274,62 +385,96 @@
 	if (playing_track == -1)
 		return -1;
 
-	cdio_subchannel_t subchannel;
-	cdio_audio_read_subchannel(pcdrom_drive->p_cdio, &subchannel);
-	int currentlsn = cdio_msf_to_lsn(&subchannel.abs_addr);
+	if (!use_dae) {
+		cdio_subchannel_t subchannel;
+		if (cdio_audio_read_subchannel(pcdio, &subchannel) != DRIVER_OP_SUCCESS) {
+			fprintf(stderr, "cdaudio-ng: failed to read analog cd subchannel\n");
+			cleanup_on_error();
+			return -1;
+		}
+		int currlsn = cdio_msf_to_lsn(&subchannel.abs_addr);
 
-		/* check to see if we have reached the end of the song */
-	if (currentlsn == trackinfo[playing_track].endlsn) {
-		cdaudio_stop(pinputplayback);
-		return -1;
+			/* check to see if we have reached the end of the song */
+		if (currlsn == trackinfo[playing_track].endlsn) {
+			cdaudio_stop(pinputplayback);
+			return -1;
+		}
+
+		return calculate_track_length(trackinfo[playing_track].startlsn, currlsn);
 	}
-
-	int seconds = calculate_track_length(trackinfo[playing_track].startlsn, currentlsn);
-	// printf("%d\n", seconds);
-	return seconds;
+	else {
+		if (pdae_params != NULL)
+			return pinputplayback->output->output_time();
+		else
+			return -1;
+	}
 }
 
 gint cdaudio_get_volume(gint *l, gint *r)
 {
-	// printf("get_volume()\n");
-
-	cdio_audio_volume_t volume;;
-	cdio_audio_set_volume(pcdrom_drive->p_cdio, &volume);
-	*l = volume.level[0];
-	*r = volume.level[1];
-
-	return 0;
+	if (use_dae) {
+		*l = *r = 0;
+		return FALSE;
+	}
+	else {
+		cdio_audio_volume_t volume;
+		if (cdio_audio_get_volume(pcdio, &volume) != DRIVER_OP_SUCCESS) {
+			fprintf(stderr, "cdaudio-ng: failed to retrieve analog cd volume\n");
+			cleanup_on_error();
+			*l = *r = 0;
+			return FALSE;
+		}
+		*l = volume.level[0];
+		*r = volume.level[1];
+	
+		return TRUE;
+	}
 }
 
 gint cdaudio_set_volume(gint l, gint r)
 {
-	printf("set_volume(%d, %d)\n", l, r);
-
-	cdio_audio_volume_t volume = {{l, r, 0, 0}};
-	cdio_audio_set_volume(pcdrom_drive->p_cdio, &volume);
-
-	return 0;
+	if (use_dae) {
+		return FALSE;
+	}
+	else {
+		cdio_audio_volume_t volume = {{l, r, 0, 0}};
+		if (cdio_audio_set_volume(pcdio, &volume) != DRIVER_OP_SUCCESS) {
+			fprintf(stderr, "cdaudio-ng: failed to set analog cd volume\n");
+			cleanup_on_error();
+			return FALSE;
+		}
+	
+		return TRUE;
+	}
 }
 
 void cdaudio_cleanup()
 {
-	cdio_destroy(pcdrom_drive->p_cdio);
+	if (pcdio!= NULL) {
+		if (playing_track != -1 && !use_dae)
+			cdio_audio_stop(pcdio);
+		cdio_destroy(pcdio);
+		pcdio = NULL;
+	}
+	if (trackinfo != NULL) {
+		free(trackinfo);
+		trackinfo = NULL;
+	}
+	playing_track = -1;
 }
 
 void cdaudio_get_song_info(gchar *filename, gchar **title, gint *length)
 {
-	printf("get_song_info(\"%s\")\n", filename);
+	fprintf(stderr, "DEBUG: get_song_info(\"%s\")\n", filename);
 }
 
 void cdaudio_file_info_box(gchar *filename)
 {
-	
+	fprintf(stderr, "DEBUG: file_info_box(\"%s\")\n", filename);	
 }
 
 TitleInput *cdaudio_get_song_tuple(gchar *filename)
 {
-	printf("get_song_tuple(\"%s\")\n", filename);
-
 	TitleInput *tuple = bmp_title_input_new();
 
 		/* return information about the requested track */
@@ -389,6 +534,78 @@
 }
 */
 
+void *dae_playing_thread_core(dae_params_t *pdae_params)
+{
+	unsigned char *buffer = (unsigned char *) malloc(CDDA_DAE_FRAMES * CDIO_CD_FRAMESIZE_RAW);
+
+	cdio_lseek(pcdio, pdae_params->startlsn * CDIO_CD_FRAMESIZE_RAW, SEEK_SET);
+
+	gboolean output_paused = FALSE;
+	
+	while (pdae_params->pplayback->playing) {
+			/* handle pause status */
+		if (is_paused) {
+			if (!output_paused) {
+				pdae_params->pplayback->output->pause(TRUE);
+				output_paused = TRUE;
+			}
+			usleep(1000);
+			continue;
+		}
+		else
+			if (output_paused) {
+				pdae_params->pplayback->output->pause(FALSE);
+				output_paused = FALSE;
+			}
+
+			/* check if we have to seek */
+		if (pdae_params->seektime != -1) {
+			int newlsn = pdae_params->startlsn + pdae_params->seektime * 75 / 1000;
+			cdio_lseek(pcdio, newlsn * CDIO_CD_FRAMESIZE_RAW, SEEK_SET);
+			pdae_params->pplayback->output->flush(pdae_params->seektime);
+			pdae_params->currlsn = newlsn;
+			pdae_params->seektime = -1;
+		}
+
+			/* compute the actual number of sectors to read */
+		int lsncount = CDDA_DAE_FRAMES <= (pdae_params->endlsn - pdae_params->currlsn + 1) ? CDDA_DAE_FRAMES : (pdae_params->endlsn - pdae_params->currlsn + 1);
+			/* check too see if we have reached the end of the song */
+		if (lsncount <= 0)
+			break;
+
+		if (cdio_read_audio_sectors(pcdio, buffer, pdae_params->currlsn, lsncount) != DRIVER_OP_SUCCESS) {
+			fprintf(stderr, "cdaudio-ng: failed to read audio sector\n");
+			/* ok, that's it, we go on */
+		}
+
+		int remainingbytes = lsncount * CDIO_CD_FRAMESIZE_RAW;
+		unsigned char *bytebuff = buffer;
+		while (pdae_params->pplayback->playing && remainingbytes > 0 && pdae_params->seektime == -1) {
+				/* compute the actual number of bytes to play */
+			int bytecount = CDIO_CD_FRAMESIZE_RAW <= remainingbytes ? CDIO_CD_FRAMESIZE_RAW : remainingbytes;
+				/* wait until the output buffer has enough room */
+			while (pdae_params->pplayback->playing && pdae_params->pplayback->output->buffer_free() < bytecount && pdae_params->seektime == -1)
+				usleep(1000);
+				/* play the sound :) */
+			if (pdae_params->pplayback->playing && pdae_params->seektime == -1)
+				produce_audio(pdae_params->pplayback->output->written_time(), FMT_S16_LE, 2, bytecount, bytebuff, &pdae_params->pplayback->playing);
+			remainingbytes -= bytecount;
+			bytebuff += bytecount;
+		}
+		pdae_params->currlsn += lsncount;
+	}
+
+	pdae_params->pplayback->playing = FALSE;
+	playing_track = -1;
+	is_paused = FALSE;
+
+	pdae_params->pplayback->output->close_audio();
+	free(buffer);
+
+	g_thread_exit(NULL);
+	return NULL;
+}
+
 int calculate_track_length(int startlsn, int endlsn)
 {
 	return ((endlsn - startlsn + 1) * 1000) / 75;
@@ -404,3 +621,16 @@
 	tracknostr[2] = '\0';
 	return strtol(tracknostr, NULL, 10);
 }
+
+void cleanup_on_error()
+{
+	if (pcdio != NULL) {
+		if (playing_track != -1 && !use_dae)
+			cdio_audio_stop(pcdio);
+	}
+	if (trackinfo != NULL) {
+		free(trackinfo);
+		trackinfo = NULL;
+	}
+	playing_track = -1;
+}