<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1,5 +1,7 @@
 /*
  *  Copyright (C) 2004 Steve Harris
+ *  Copyright (C) 2006 Garett Shulman
+ *  Copyright (C) 2009 Adam Sampson
  *
  *  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
@@ -49,8 +51,6 @@ lash_client_t *lash_client;
 #include &quot;support.h&quot;
 #include &quot;main.h&quot;
 
-#define DEFAULT_BUF_LENGTH 10 /* in seconds */
-
 #define DEBUG(lvl, txt...) \
     if (verbosity &gt;= lvl) fprintf(stderr, PACKAGE &quot;: &quot; txt)
 
@@ -69,6 +69,10 @@ char *prefix = DEFAULT_PREFIX;
 char *format_name = DEFAULT_FORMAT;
 int format_sf = 0;
 int safe_filename = 0;
+int auto_record = 0;
+float auto_begin_threshold = 0.0;
+float auto_end_threshold = 0.0;
+unsigned int auto_end_time = DEFAULT_AUTO_END_TIME;
 
 jack_port_t *ports[MAX_PORTS];
 jack_client_t *client;
@@ -96,7 +100,10 @@ int main(int argc, char *argv[])
      lash_event_t *event;
 #endif
 
-    while ((opt = getopt(argc, argv, &quot;hic:t:n:p:f:s&quot;)) != -1) {
+    auto_begin_threshold = db2lin(DEFAULT_AUTO_BEGIN_THRESHOLD);
+    auto_end_threshold = db2lin(DEFAULT_AUTO_END_THRESHOLD);
+
+    while ((opt = getopt(argc, argv, &quot;hic:t:n:p:f:sab:e:T:&quot;)) != -1) {
 	switch (opt) {
 	case 'h':
 	    help = 1;
@@ -126,6 +133,18 @@ int main(int argc, char *argv[])
 	case 's':
 	    safe_filename = 1;
 	    break;
+	case 'a':
+	    auto_record = 1;
+	    break;
+	case 'b':
+	    auto_begin_threshold = db2lin(atof(optarg));
+	    break;
+	case 'e':
+	    auto_end_threshold = db2lin(atof(optarg));
+	    break;
+	case 'T':
+	    auto_end_time = atoi(optarg);
+	    break;
 	default:
 	    num_ports = 0;
 	    break;
@@ -138,7 +157,8 @@ int main(int argc, char *argv[])
 
     if (num_ports &lt; 1 || num_ports &gt; MAX_PORTS || help) {
 	fprintf(stderr, &quot;Usage %s: [-h] [-i] [-c channels] [-n jack-name]\n\t&quot;
-			&quot;[-t buffer-length] [-p file prefix] [-f format] &quot;
+			&quot;[-t buffer-length] [-p file prefix] [-f format]\n\t&quot;
+			&quot;[-a] [-b begin-threshold] [-e end-threshold] [-T end-time]\n\t&quot;
 			&quot;[port-name ...]\n\n&quot;, argv[0]);
 	fprintf(stderr, &quot;\t-h\tshow this help\n&quot;);
 	fprintf(stderr, &quot;\t-i\tinteractive mode (console instead of X11) also enabled\n\t\tif DISPLAY is unset\n&quot;);
@@ -148,6 +168,10 @@ int main(int argc, char *argv[])
 	fprintf(stderr, &quot;\t-p\tspecify the saved file prefix, may include path\n&quot;);
 	fprintf(stderr, &quot;\t-s\tuse safer characters in filename (windows compatibility)\n&quot;);
 	fprintf(stderr, &quot;\t-f\tspecify the saved file format\n&quot;);
+	fprintf(stderr, &quot;\t-a\tenable automatic sound-triggered recording\n&quot;);
+	fprintf(stderr, &quot;\t-b\tspecify threshold above which automatic recording will begin\n&quot;);
+	fprintf(stderr, &quot;\t-e\tspecify threshold below which automatic recording will end\n&quot;);
+	fprintf(stderr, &quot;\t-T\tspecify silence length before automatic recording ends\n&quot;);
 	fprintf(stderr, &quot;\n&quot;);
 	fprintf(stderr, &quot;\tchannels must be in the range 1-8, default %d\n&quot;,
 			DEFAULT_NUM_PORTS);
@@ -155,6 +179,9 @@ int main(int argc, char *argv[])
 	fprintf(stderr, &quot;\tfile-prefix, default \&quot;%s\&quot;\n&quot;, DEFAULT_PREFIX);
 	fprintf(stderr, &quot;\tbuffer-length, default %d secs\n&quot;, DEFAULT_BUF_LENGTH);
 	fprintf(stderr, &quot;\tformat, default '%s', options: wav, w64\n&quot;, DEFAULT_FORMAT);
+	fprintf(stderr, &quot;\tbegin-threshold, default %.1f dB\n&quot;, DEFAULT_AUTO_BEGIN_THRESHOLD);
+	fprintf(stderr, &quot;\tend-threshold, default %.1f dB\n&quot;, DEFAULT_AUTO_END_THRESHOLD);
+	fprintf(stderr, &quot;\tend-time, default %d secs\n&quot;, DEFAULT_AUTO_END_TIME);
 	fprintf(stderr, &quot;\n&quot;);
 	fprintf(stderr, &quot;specifying port names to connect to on the command line overrides -c\n\n&quot;);
 	exit(1);
@@ -170,7 +197,7 @@ int main(int argc, char *argv[])
 #endif
 
     if (format_sf == 0) {
-	fprintf(stderr, &quot;Unkown format '%s'\n&quot;, format_name);
+	fprintf(stderr, &quot;Unknown format '%s'\n&quot;, format_name);
     }
 
     /* Register with jack */</diff>
      <filename>src/main.c</filename>
    </modified>
    <modified>
      <diff>@@ -9,6 +9,7 @@
 #define MAX_PORTS 		8
 #define MAX_TIME		3600
 
+#define DEFAULT_BUF_LENGTH	10 /* in seconds */
 #define DEFAULT_NUM_PORTS 	2
 #define DEFAULT_CLIENT_NAME 	&quot;TimeMachine&quot;
 #define DEFAULT_PREFIX 		&quot;tm-&quot;
@@ -21,6 +22,10 @@
 
 #define OSC_PORT &quot;7133&quot;
 
+#define DEFAULT_AUTO_BEGIN_THRESHOLD	-35.0
+#define DEFAULT_AUTO_END_THRESHOLD	DEFAULT_AUTO_BEGIN_THRESHOLD
+#define DEFAULT_AUTO_END_TIME		DEFAULT_BUF_LENGTH
+
 extern GtkWidget *main_window;
 
 extern GdkPixbuf *img_on, *img_off, *img_busy;
@@ -31,6 +36,10 @@ extern char *prefix;
 extern char *format_name;
 extern int format_sf;
 extern int safe_filename;
+extern int auto_record;
+extern float auto_begin_threshold;
+extern float auto_end_threshold;
+extern unsigned int auto_end_time;
 extern jack_client_t *client;
 extern jack_port_t *ports[MAX_PORTS];
 </diff>
      <filename>src/main.h</filename>
    </modified>
    <modified>
      <diff>@@ -24,8 +24,8 @@
 #include &quot;gtkmeter.h&quot;
 #include &quot;threads.h&quot;
 #include &quot;support.h&quot;
+#include &quot;meters.h&quot;
 
-#define lin2db(lin) (20.0f * log10(lin))
 static GtkAdjustment *meter_adj[MAX_PORTS];
 
 void bind_meters()</diff>
      <filename>src/meters.c</filename>
    </modified>
    <modified>
      <diff>@@ -1,8 +1,11 @@
 #ifndef METERS_H
 #define METERS_H
 
-void bind_meters();
+#define lin2db(lin) (20.0f * log10(lin))
+#define db2lin(db)  (pow(10, db / 20.0f))
 
-void update_meters(volatile float amp[]);
+void bind_meters(void);
+
+void update_meters(float amp[]);
 
 #endif</diff>
      <filename>src/meters.h</filename>
    </modified>
    <modified>
      <diff>@@ -36,9 +36,10 @@ float *pre_buffer[MAX_PORTS];
 float *disk_buffer[MAX_PORTS];
 
 static int recording = 0;	    /* recording yes/no */
+static int user_recording = 0;	    /* recording initiated by user yes/no */
 static int quiting = 0;		    /* quit pending yes/no */
-volatile int recording_done = 0;    /* quit pending yes/no */
-volatile int syncing_done = 0;      /* finsihed writing pre-buffer */
+volatile int recording_done = 0;    /* recording completed after quit */
+volatile int need_ui_sync = 0;      /* need to update record button */
 
 static unsigned int pre_time = 0;
 static unsigned int pre_size = 0;
@@ -49,10 +50,13 @@ static unsigned int disk_write_pos = 0;
 /* Peak data for meters */
 static volatile float peak[MAX_PORTS];
 
+static unsigned int silent_count = 0;
+
 int process(jack_nframes_t nframes, void *arg)
 {
     unsigned int i, port, pos = 0;
     const unsigned int rec = recording;
+    const jack_nframes_t sample_rate = jack_get_sample_rate(client);
 
     for (port = 0; port &lt; num_ports; port++) {
 	jack_default_audio_sample_t *in;
@@ -70,6 +74,29 @@ int process(jack_nframes_t nframes, void *arg)
 	    break;
 	}
 
+	if (auto_record) {
+	    if (rec &amp;&amp; !user_recording) {
+		for (i = 0; i &lt; nframes; i++) {
+		    if (fabsf(in[i]) &lt;= auto_end_threshold) {
+			silent_count++;
+		    } else {
+			silent_count = 0;
+		    }
+		}
+		if (silent_count &gt; (auto_end_time * sample_rate * num_ports)) {
+		    recording = 0;
+		}
+	    } else {
+		for (i = 0; i &lt; nframes; i++) {
+		    if (fabsf(in[i]) &gt; auto_begin_threshold) {
+			recording = 1;
+			silent_count = 0;
+			break;
+		    }
+		}
+	    }
+	}
+
 	for (i = 0; i &lt; nframes; i++) {
 	    if (fabsf(in[i]) &gt; peak[port]) {
 		peak[port] = fabsf(in[i]);
@@ -176,7 +203,7 @@ int writer_thread(void *d)
     }
 
     /* This tells the UI that were ready to go again, it will reset it */
-    syncing_done = 1;
+    need_ui_sync = 1;
 
     if (recording) printf(&quot;writing realtime data...\n&quot;);
 
@@ -196,6 +223,8 @@ int writer_thread(void *d)
     }
     sf_close(out);
 
+    need_ui_sync = 1;
+
     printf(&quot;done writing...\n&quot;);
 
     /* Just make sure everythings reset */
@@ -217,7 +246,8 @@ void process_init(unsigned int time)
 	fprintf(stderr, &quot;timemachine: buffer time must be 1 second or &quot;
 			&quot;greater\n&quot;);
 	exit(1);
-    } if (time &gt; MAX_TIME) {
+    }
+    if (time &gt; MAX_TIME) {
 	fprintf(stderr, &quot;timemachine: buffer time must be %d seconds or &quot;
 			&quot;less\nthis is for your own good, it really will not&quot;
 			&quot;work well with buffers that size\n&quot;, MAX_TIME);
@@ -241,11 +271,13 @@ void process_init(unsigned int time)
 void recording_start()
 {
     recording = 1;
+    user_recording = 1;
 }
 
 void recording_stop()
 {
     recording = 0;
+    user_recording = 0;
 }
 
 void recording_quit()
@@ -259,12 +291,19 @@ gboolean meter_tick(gpointer user_data)
     float data[MAX_PORTS];
     unsigned int i;
 
-    if (syncing_done &amp;&amp; !recording) {
+    if (need_ui_sync) {
 	GtkWidget *img = lookup_widget(main_window, &quot;toggle_image&quot;);
 
-	syncing_done = 0;
-	gtk_image_set_from_pixbuf(GTK_IMAGE(img), img_off);
+	if (recording) {
+	    gtk_image_set_from_pixbuf(GTK_IMAGE(img), img_on);
+	    gtk_window_set_icon(GTK_WINDOW(main_window), icon_on);
+	} else {
+	    gtk_image_set_from_pixbuf(GTK_IMAGE(img), img_off);
+	    gtk_window_set_icon(GTK_WINDOW(main_window), icon_off);
+	}
 	gtk_widget_set_sensitive(img, TRUE);
+
+	need_ui_sync = 0;
     }
 
     for (i=0; i&lt;MAX_PORTS; i++) {</diff>
      <filename>src/threads.c</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>a94a0877289f6aa003ae5fa6b1eae1dd4baa4de0</id>
    </parent>
  </parents>
  <author>
    <name>Steve Harris</name>
    <email>steve.harris@garlik.com</email>
  </author>
  <url>http://github.com/swh/timemachine/commit/0bddb47e2a1d6585a5b80f6775007e3808cb142c</url>
  <id>0bddb47e2a1d6585a5b80f6775007e3808cb142c</id>
  <committed-date>2009-09-22T07:08:46-07:00</committed-date>
  <authored-date>2009-09-22T07:08:46-07:00</authored-date>
  <message>Integrated &quot;autorecord&quot; patch from Adam Sampson</message>
  <tree>54660200c9371b30d7e7159169a9ba7011c92703</tree>
  <committer>
    <name>Steve Harris</name>
    <email>steve.harris@garlik.com</email>
  </committer>
</commit>
