changeset 315:2294f3a6f136 trunk

[svn] Metronom (a.k.a. tact generator) input plugin, ported from XMMS.
author chainsaw
date Wed, 29 Nov 2006 14:42:11 -0800
parents 29e5e3b6f1b6
children fb513e10174e
files ChangeLog configure.ac src/metronom/Makefile src/metronom/metronom.c
diffstat 4 files changed, 320 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Nov 28 12:09:34 2006 -0800
+++ b/ChangeLog	Wed Nov 29 14:42:11 2006 -0800
@@ -1,3 +1,11 @@
+2006-11-28 20:09:34 +0000  William Pitcock <nenolod@nenolod.net>
+  revision [688]
+  - MirBSD support from <bsiegert -at gmx.de>
+  
+  trunk/configure.ac |    6 +++---
+  1 file changed, 3 insertions(+), 3 deletions(-)
+
+
 2006-11-28 02:10:41 +0000  William Pitcock <nenolod@nenolod.net>
   revision [682]
   - be more robust
--- a/configure.ac	Tue Nov 28 12:09:34 2006 -0800
+++ b/configure.ac	Wed Nov 29 14:42:11 2006 -0800
@@ -85,7 +85,7 @@
 
 dnl These plugins are always built.
 
-INPUT_PLUGINS="tonegen console sexypsf wav cue alac"
+INPUT_PLUGINS="tonegen console sexypsf wav cue alac metronom"
 OUTPUT_PLUGINS="disk_writer"
 EFFECT_PLUGINS="audiocompress ladspa voice_removal stereo_plugin echo_plugin"
 GENERAL_PLUGINS="song_change alarm"
@@ -1127,6 +1127,7 @@
 echo "  WavPack 4.31+ (wavpack):                $have_wavpack"
 echo "  Musepack support (musepack):            $enable_musepack"
 echo "  TrueAudio (tta):                        $enable_tta"
+echo "  Metronom:                               yes"
 echo
 echo "  General"
 echo "  -------"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/metronom/Makefile	Wed Nov 29 14:42:11 2006 -0800
@@ -0,0 +1,14 @@
+include ../../mk/rules.mk
+include ../../mk/init.mk
+
+OBJECTIVE_LIBS = libmetronom$(SHARED_SUFFIX)
+
+LIBDIR = $(plugindir)/$(INPUT_PLUGIN_DIR)
+
+SOURCES = metronom.c
+
+OBJECTS = ${SOURCES:.c=.o}
+
+CFLAGS += $(PICFLAGS) $(GTK_CFLAGS) -I../../intl -I../..
+
+include ../../mk/objective.mk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/metronom/metronom.c	Wed Nov 29 14:42:11 2006 -0800
@@ -0,0 +1,296 @@
+/*
+ *  Copyright 2000 Martin Strauß <mys@faveve.uni-stuttgart.de>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "audacious/plugin.h"
+#include "audacious/util.h"
+#include <glib.h>
+#include <string.h>
+
+#define MIN_BPM 1 
+#define MAX_BPM 512
+
+static InputPlugin metronom_ip;
+
+static gboolean going;
+static gboolean audio_error;
+static GThread *play_thread;
+
+struct metronom_struct {
+	gint bpm;
+	gint num;
+	gint den;
+	gint id;
+};
+typedef struct metronom_struct metronom_t;
+
+#define tact_id_max 12
+gint tact_id[tact_id_max][2]=
+	{
+		{1,1},
+		{2,2},
+		{3,2},
+		{4,2},
+		{2,4},
+		{3,4},
+		{4,4},
+		{6,4},
+		{2,8},
+		{3,8},
+		{4,8},
+		{6,8}
+	};
+#define tact_form_max 8
+gdouble tact_form[tact_id_max][tact_form_max]=
+	{
+		{1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0},
+		{1.0,0.5,0.0,0.0,0.0,0.0,0.0,0.0},
+		{1.0,0.5,0.5,0.0,0.0,0.0,0.0,0.0},
+		{1.0,0.5,0.6,0.5,0.0,0.0,0.0,0.0},
+		{1.0,0.5,0.0,0.0,0.0,0.0,0.0,0.0},
+		{1.0,0.5,0.5,0.0,0.0,0.0,0.0,0.0},
+		{1.0,0.5,0.6,0.5,0.0,0.0,0.0,0.0},
+		{1.0,0.5,0.5,0.6,0.5,0.5,0.0,0.0},
+		{1.0,0.5,0.0,0.0,0.0,0.0,0.0,0.0},
+		{1.0,0.5,0.5,0.0,0.0,0.0,0.0,0.0},
+		{1.0,0.5,0.6,0.5,0.0,0.0,0.0,0.0},
+		{1.0,0.5,0.5,0.6,0.5,0.5,0.0,0.0}
+	};
+
+static void metronom_about(void)
+{
+	static GtkWidget *box;
+	box = xmms_show_message(
+		"About Metronom",
+		"A Tact Generator by Martin Strauß <mys@faveve.uni-stuttgart.de>\n\nTo use it, add a URL: tact://beats*num/den\ne.g. tact://77 to play 77 beats per minute\nor   tact://60*3/4 to play 60 bpm in 3/4 tacts", "Ok",
+		FALSE, NULL, NULL);
+	gtk_signal_connect(GTK_OBJECT(box), "destroy",
+			   GTK_SIGNAL_FUNC(gtk_widget_destroyed), &box);
+}
+
+static int metronom_is_our_file(char *filename)
+{
+	if (!strncmp(filename, "tact://", 7))
+		return TRUE;
+	return FALSE;
+}
+
+#define BUF_SAMPLES 512
+#define BUF_BYTES BUF_SAMPLES * 2
+#define MAX_AMPL (GINT16_TO_LE((1<<15) - 1))
+
+static void* play_loop(void *arg)
+{
+	gint16 data[BUF_SAMPLES];
+	metronom_t *pmetronom=(metronom_t *)arg;
+	gint i;
+	
+	gint16 t = 0,tact;
+	gint16 datagoal = 0;
+	gint16 datamiddle = 0;
+	gint16 datacurrent = datamiddle;
+	gint16 datalast = datamiddle;
+	gint16 data_form[tact_form_max];
+	gint num;	
+
+	tact = 60*44100/pmetronom->bpm;
+	/* prepare weighted amplitudes */
+	for(num=0;num<pmetronom->num;num++){
+		data_form[num]=MAX_AMPL*tact_form[pmetronom->id][num];
+	}
+
+	num=0;
+	while (going)
+	{
+		for (i = 0; i < BUF_SAMPLES; i++){
+			if(t==tact){
+				t=0;
+				datagoal = data_form[num];
+				}
+			else if(t==10) {
+				datagoal = -data_form[num];
+			}
+			else if(t==25) {
+				datagoal = data_form[num];
+				/* circle through weighted amplitudes */
+				num++;
+				if(num==pmetronom->num)num=0;
+			} 
+			/* makes curve a little bit smoother  */ 
+			data[i]=(datalast+datacurrent+datagoal)/3;
+			datalast=datacurrent;
+			datacurrent=data[i];
+			if(t > 35)
+			datagoal=(datamiddle+7*datagoal)/8;
+			t++;
+		}
+		while(metronom_ip.output->buffer_free() < BUF_BYTES && going)
+			xmms_usleep(30000);
+		if (going)
+			produce_audio(metronom_ip.output->written_time(), FMT_S16_LE, 1, BUF_BYTES, data, &going);
+	}
+	/* Make sure the output plugin stops prebuffering */
+	free(arg);
+	metronom_ip.output->buffer_free();
+	metronom_ip.output->buffer_free();
+	g_thread_exit(NULL);
+}
+
+static void metronom_play(char *filename)
+{
+	gchar *name;
+	size_t count;	
+	metronom_t *pmetronom;
+	gint flag,id;
+
+	pmetronom=(metronom_t *)malloc(sizeof(metronom_t));
+	if(!pmetronom)return;
+
+	count=sscanf(filename, "tact://%d*%d/%d", &pmetronom->bpm,&pmetronom->num,&pmetronom->den);
+	if (count != 1 && count !=3)return;
+	if(!(pmetronom->bpm >= MIN_BPM && pmetronom->bpm <= MAX_BPM))return;
+	pmetronom->id=0;
+	if(count==1){
+		pmetronom->num=1;
+		pmetronom->den=1;
+	} else {
+		if(pmetronom->num==0 || pmetronom->den==0)return;
+		flag=FALSE;
+		for(id=0;(id<tact_id_max && (!flag));id++){
+			if(pmetronom->num==tact_id[id][0] && pmetronom->den==tact_id[id][1]){
+				flag=TRUE;
+				pmetronom->id=id;
+			}
+		}
+		if(!flag)return;
+	}
+	
+	going = TRUE;
+	audio_error = FALSE;
+	if (metronom_ip.output->open_audio(FMT_S16_LE, 44100, 1) == 0)
+	{
+		audio_error = TRUE;
+		going = FALSE;
+		return;
+	}
+	if(pmetronom->num==1 && pmetronom->den==1){
+		name = g_strdup_printf("Tact generator: %d bpm", pmetronom->bpm);
+	} else {
+		name = g_strdup_printf("Tact generator: %d bpm %d/%d", pmetronom->bpm,pmetronom->num,pmetronom->den);
+	}
+	metronom_ip.set_info(name, -1, 16 * 44100, 44100, 1);
+	g_free(name);
+	play_thread = g_thread_create((GThreadFunc)play_loop, pmetronom, TRUE, NULL);
+}
+
+static void metronom_stop(void)
+{
+	if (going)
+	{
+		going = FALSE;
+		g_thread_join(play_thread);
+		metronom_ip.output->close_audio();
+	}
+}
+
+static void metronom_pause(short paused)
+{
+	metronom_ip.output->pause(paused);
+}
+
+static int metronom_get_time(void)
+{
+	if (audio_error)
+		return -2;
+	if (!going && !metronom_ip.output->buffer_playing())
+		return -1;
+	return metronom_ip.output->output_time();
+}
+
+static void metronom_song_info(char *filename, char **title, int *length)
+{
+	metronom_t metronom;
+	metronom_t *pmetronom=&metronom;
+	size_t count;
+	gint flag,id;
+	*length = -1;
+	*title = NULL;
+
+	count=sscanf(filename, "tact://%d*%d/%d", &pmetronom->bpm,&pmetronom->num,&pmetronom->den);
+	if (count != 1 && count !=3)return;
+	if(!(pmetronom->bpm >= MIN_BPM && pmetronom->bpm <= MAX_BPM))return;
+
+	if (count == 1)	{
+		pmetronom->num=1;
+		pmetronom->den=1;
+		pmetronom->id=0;
+	} else {
+		if(pmetronom->num==0 || pmetronom->den==0)return;
+		flag=FALSE;
+		for(id=0;(id<tact_id_max && (!flag));id++){
+			if(pmetronom->num==tact_id[id][0] && pmetronom->den==tact_id[id][1])flag=TRUE;
+		}
+		if(!flag)return;
+		else pmetronom->id=id;
+	}
+
+	if(pmetronom->num==1 && pmetronom->den==1){
+		*title = g_strdup_printf("Tact generator: %d bpm", pmetronom->bpm);
+	} else {
+		*title = g_strdup_printf("Tact generator: %d bpm %d/%d", pmetronom->bpm,pmetronom->num,pmetronom->den);
+	}
+}
+		
+	
+	
+static InputPlugin metronom_ip = 
+{
+	NULL,
+	NULL,
+	"Tact Generator " VERSION,
+	NULL,
+	metronom_about,
+	NULL,
+	metronom_is_our_file,
+	NULL,
+	metronom_play,
+	metronom_stop,
+	metronom_pause,
+	NULL,
+	NULL,
+	metronom_get_time,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	metronom_song_info,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+};
+
+InputPlugin *get_iplugin_info(void)
+{
+	return &metronom_ip;
+}