summaryrefslogtreecommitdiffstats
path: root/apps/recorder
diff options
context:
space:
mode:
Diffstat (limited to 'apps/recorder')
-rw-r--r--apps/recorder/peakmeter.c374
-rw-r--r--apps/recorder/peakmeter.h34
-rw-r--r--apps/recorder/recording.c257
3 files changed, 573 insertions, 92 deletions
diff --git a/apps/recorder/peakmeter.c b/apps/recorder/peakmeter.c
index 41d375e076..0481e25acd 100644
--- a/apps/recorder/peakmeter.c
+++ b/apps/recorder/peakmeter.c
@@ -22,6 +22,7 @@
#include "kernel.h"
#include "settings.h"
#include "lcd.h"
+#include "widgets.h"
#include "wps-display.h"
#include "sprintf.h"
#include "button.h"
@@ -67,6 +68,24 @@ static unsigned short db_min = 0;
static unsigned short db_max = 9000;
static unsigned short db_range = 9000;
+static unsigned short trig_strt_threshold;
+static long trig_strt_duration;
+static long trig_strt_dropout;
+static unsigned short trig_stp_threshold;
+static long trig_stp_hold;
+static long trig_rstrt_gap;
+
+/* point in time when the threshold was exceeded */
+static long trig_hightime;
+
+/* point in time when the volume fell below the threshold*/
+static long trig_lowtime;
+
+/* The output value of the trigger. See TRIG_XXX constants vor valid values */
+static int trig_status = TRIG_OFF;
+
+static void (*trigger_listener)(int) = NULL;
+
#if CONFIG_HWCODEC == MASNONE
#define MAS_REG_DQPEAK_L 0
#define MAS_REG_DQPEAK_R 0
@@ -124,7 +143,7 @@ static const long clip_time_out[] = {
/* precalculated peak values that represent magical
dBfs values. Used to draw the scale */
-#define DB_SCALE_SRC_VALUES_SIZE 11
+#define DB_SCALE_SRC_VALUES_SIZE 12
#if 0
static const int db_scale_src_values[DB_SCALE_SRC_VALUES_SIZE] = {
32767, /* 0 db */
@@ -138,6 +157,7 @@ static const int db_scale_src_values[DB_SCALE_SRC_VALUES_SIZE] = {
328, /* -40 db */
104, /* -50 db */
33, /* -60 db */
+ 1, /* -inf */
};
#else
static const int db_scale_src_values[DB_SCALE_SRC_VALUES_SIZE] = {
@@ -152,9 +172,25 @@ static const int db_scale_src_values[DB_SCALE_SRC_VALUES_SIZE] = {
373, /* -40 db */
102, /* -50 db */
33, /* -60 db */
+ 0, /* -inf */
};
#endif
+const char* peak_meter_dbnames[DB_SCALE_SRC_VALUES_SIZE] = {
+ "0 db",
+ "-3 db",
+ "-6 db",
+ "-9 db",
+ "-12 db",
+ "-18 db",
+ "-24 db",
+ "-30 db",
+ "-40 db",
+ "-50 db",
+ "-60 db",
+ "-inf",
+};
+
static int db_scale_count = DB_SCALE_SRC_VALUES_SIZE;
/* if db_scale_valid is false the content of
@@ -275,8 +311,8 @@ int calc_db (int isample) {
/**
- * A helper function for db_to_sample. Don't call it separately but
- * use db_to_sample. If one or both of min and max are outside the
+ * A helper function for peak_meter_db2sample. Don't call it separately but
+ * use peak_meter_db2sample. If one or both of min and max are outside the
* range 0 <= min (or max) < 8961 the behaviour of this function is
* undefined. It may not return.
* @param int min - The minimum of the value range that is searched.
@@ -312,7 +348,7 @@ static int db_to_sample_bin_search(int min, int max, int db){
* @return int - The return value is in the range of
* 0 <= return value < MAX_PEAK
*/
-static int db_to_sample(int db) {
+int peak_meter_db2sample(int db) {
int retval = 0;
/* what is the maximum pseudo db value */
@@ -351,7 +387,7 @@ static int db_to_sample(int db) {
*/
void peak_meter_set_min(int newmin) {
if (peak_meter_use_dbfs) {
- peak_meter_range_min = db_to_sample(newmin);
+ peak_meter_range_min = peak_meter_db2sample(newmin);
} else {
if (newmin < peak_meter_range_max) {
@@ -392,7 +428,7 @@ int peak_meter_get_min(void) {
*/
void peak_meter_set_max(int newmax) {
if (peak_meter_use_dbfs) {
- peak_meter_range_max = db_to_sample(newmax);
+ peak_meter_range_max = peak_meter_db2sample(newmax);
} else {
if (newmax > peak_meter_range_min) {
peak_meter_range_max = newmax * MAX_PEAK / 100;
@@ -504,6 +540,15 @@ void peak_meter_playback(bool playback)
#endif
}
+static void set_trig_status(int new_state) {
+ if (trig_status != new_state) {
+ trig_status = new_state;
+ if (trigger_listener != NULL) {
+ trigger_listener(trig_status);
+ }
+ }
+}
+
/**
* Reads peak values from the MAS, and detects clips. The
* values are stored in peak_meter_l peak_meter_r for later
@@ -546,6 +591,121 @@ inline void peak_meter_peek(void)
current_tick + clip_time_out[peak_meter_clip_hold];
}
+ switch (trig_status) {
+ case TRIG_READY:
+ /* no more changes, if trigger was activated as release trigger */
+ /* threshold exceeded? */
+ if ((left > trig_strt_threshold) || (right > trig_strt_threshold)) {
+ if (trig_strt_duration) {
+ /* reset trigger duration */
+ trig_hightime = current_tick;
+
+ /* reset dropout duration */
+ trig_lowtime = current_tick;
+
+ /* if trig_duration is set to 0 the user wants to start
+ recording immediately */
+ set_trig_status(TRIG_STEADY);
+ } else {
+ set_trig_status(TRIG_GO);
+ }
+ }
+ break;
+
+ case TRIG_STEADY:
+ case TRIG_RETRIG:
+ /* trigger duration exceeded */
+ if (current_tick - trig_hightime > trig_strt_duration) {
+ set_trig_status(TRIG_GO);
+ } else {
+ /* threshold exceeded? */
+ if ((left > trig_strt_threshold) ||
+ (right > trig_strt_threshold)) {
+ /* reset lowtime */
+ trig_lowtime = current_tick;
+ }
+ /* volume is below threshold */
+ else {
+ /* dropout occurred? */
+ if (current_tick - trig_lowtime > trig_strt_dropout){
+ if (trig_status == TRIG_STEADY){
+ set_trig_status(TRIG_READY);
+ }
+ /* trig_status == TRIG_RETRIG */
+ else {
+ /* the gap has already expired */
+ trig_lowtime = current_tick - trig_rstrt_gap - 1;
+ set_trig_status(TRIG_POSTREC);
+ }
+ }
+ }
+ }
+ break;
+
+ case TRIG_GO:
+ case TRIG_CONTINUE:
+ /* threshold exceeded? */
+ if ((left > trig_stp_threshold) || (right > trig_stp_threshold)) {
+ /* restart hold time countdown */
+ trig_lowtime = current_tick;
+ } else {
+ set_trig_status(TRIG_POSTREC);
+ trig_hightime = current_tick;
+ }
+ break;
+
+ case TRIG_POSTREC:
+ /* gap time expired? */
+ if (current_tick - trig_lowtime > trig_rstrt_gap){
+ /* start threshold exceeded? */
+ if ((left > trig_strt_threshold) ||
+ (right > trig_strt_threshold)) {
+
+ set_trig_status(TRIG_RETRIG);
+ trig_hightime = current_tick;
+ }
+ else
+
+ /* stop threshold exceeded */
+ if ((left > trig_stp_threshold) ||
+ (right > trig_stp_threshold)) {
+ if (current_tick - trig_hightime > trig_stp_hold){
+ trig_lowtime = current_tick;
+ set_trig_status(TRIG_CONTINUE);
+ } else {
+ trig_lowtime = current_tick - trig_rstrt_gap - 1;
+ }
+ }
+
+ /* below any threshold */
+ else {
+ if (current_tick - trig_lowtime > trig_stp_hold){
+ set_trig_status(TRIG_READY);
+ } else {
+ trig_hightime = current_tick;
+ }
+ }
+ }
+
+ /* still within the gap time */
+ else {
+ /* stop threshold exceeded */
+ if ((left > trig_stp_threshold) ||
+ (right > trig_stp_threshold)) {
+ set_trig_status(TRIG_CONTINUE);
+ trig_lowtime = current_tick;
+ }
+
+ /* hold time expired */
+ else if (current_tick - trig_lowtime > trig_stp_hold){
+ trig_hightime = current_tick;
+ trig_lowtime = current_tick;
+ set_trig_status(TRIG_READY);
+ }
+ }
+ break;
+ }
+
/* peaks are searched -> we have to find the maximum. When
many calls of peak_meter_peek the maximum value will be
stored in peak_meter_x. This maximum is reset by the
@@ -558,37 +718,6 @@ inline void peak_meter_peek(void)
#endif
}
-
-/**
- * The thread function for the peak meter calls peak_meter_peek
- * to reas out the mas and find maxima, clips, etc. No display
- * is performed.
- */
-/*
-void peak_meter_thread(void) {
- sleep(5000);
- while (1) {
- if (peak_meter_enabled && peak_meter_use_thread){
- peak_meter_peek();
- }
- yield();
- }
-}
-*/
-
-/**
- * Creates the peak meter thread
- */
-/*
-void peak_meter_init(void) {
- create_thread(
- peak_meter_thread,
- peak_meter_stack,
- sizeof peak_meter_stack,
- "peakmeter");
-}
-*/
-
/**
* Reads out the peak volume of the left channel.
* @return int - The maximum value that has been detected
@@ -842,6 +971,22 @@ void peak_meter_draw(int x, int y, int width, int height) {
lcd_invertpixel(db_scale_lcd_coord[i], y + height / 2 - 1);
}
+ if (trig_status != TRIG_OFF) {
+ int start_trigx, stop_trigx, ycenter;
+
+ ycenter = y + height / 2;
+ /* display threshold value */
+ start_trigx = x+peak_meter_scale_value(trig_strt_threshold,meterwidth);
+ lcd_drawline(start_trigx, ycenter - 2, start_trigx, ycenter);
+ start_trigx ++;
+ if (start_trigx < LCD_WIDTH) lcd_drawpixel(start_trigx, ycenter - 1);
+
+ stop_trigx = x + peak_meter_scale_value(trig_stp_threshold,meterwidth);
+ lcd_drawline(stop_trigx, ycenter - 2, stop_trigx, ycenter);
+ if (stop_trigx > 0) lcd_drawpixel(stop_trigx - 1, ycenter - 1);
+
+ }
+
#ifdef PM_DEBUG
/* display a bar to show how many calls to peak_meter_peek
have ocurred since the last display */
@@ -866,6 +1011,161 @@ void peak_meter_draw(int x, int y, int width, int height) {
last_right = right;
}
+/**
+ * Defines the parameters of the trigger. After these parameters are defined
+ * the trigger can be started either by peak_meter_attack_trigger or by
+ * peak_meter_release_trigger. Note that you can pass either linear (%) or
+ * logarithmic (db) values to the thresholds. Positive values are intepreted as
+ * percent (0 is 0% .. 100 is 100%). Negative values are interpreted as db.
+ * To avoid ambiguosity of the value 0 the negative values are shifted by -1.
+ * Thus -75 is -74db .. -1 is 0db.
+ * @param start_threshold - The threshold used for attack trigger. Negative
+ * values are interpreted as db -1, positive as %.
+ * @param start_duration - The minimum time span within which start_threshold
+ * must be exceeded to fire the attack trigger.
+ * @param start_dropout - The maximum time span the level may fall below
+ * start_threshold without releasing the attack trigger.
+ * @param stop_threshold - The threshold the volume must fall below to release
+ * the release trigger.Negative values are
+ * interpreted as db -1, positive as %.
+ * @param stop_hold - The minimum time the volume must fall below the
+ * stop_threshold to release the trigger.
+ * @param
+ */
+void peak_meter_define_trigger(
+ int start_threshold,
+ long start_duration,
+ long start_dropout,
+ int stop_threshold,
+ long stop_hold_time,
+ long restart_gap
+ )
+{
+ if (start_threshold < 0) {
+ /* db */
+ if (start_threshold < -89) {
+ trig_strt_threshold = 0;
+ } else {
+ trig_strt_threshold =peak_meter_db2sample((start_threshold+1)*100);
+ }
+ } else {
+ /* linear percent */
+ trig_strt_threshold = start_threshold * MAX_PEAK / 100;
+ }
+ trig_strt_duration = start_duration;
+ trig_strt_dropout = start_dropout;
+ if (stop_threshold < 0) {
+ /* db */
+ trig_stp_threshold = peak_meter_db2sample((stop_threshold + 1) * 100);
+ } else {
+ /* linear percent */
+ trig_stp_threshold = stop_threshold * MAX_PEAK / 100;
+ }
+ trig_stp_hold = stop_hold_time;
+ trig_rstrt_gap = restart_gap;
+}
+
+/**
+ * Enables or disables the trigger.
+ * @param on - If true the trigger is turned on.
+ */
+void peak_meter_trigger(bool on) {
+ /* don't use set_trigger here as that would fire an undesired event */
+ trig_status = on ? TRIG_READY : TRIG_OFF;
+}
+
+/**
+ * Registers the listener function that listenes on trig_status changes.
+ * @param listener - The function that is called with each change of
+ * trig_status. May be set to NULL if no callback is desired.
+ */
+void peak_meter_set_trigger_listener(void (*listener)(int status)) {
+ trigger_listener = listener;
+}
+
+/**
+ * Fetches the status of the trigger.
+ * TRIG_OFF: the trigger is inactive
+ * TRIG_RELEASED: The volume level is below the threshold
+ * TRIG_ACTIVATED: The volume level has exceeded the threshold, but the trigger
+ * hasn't been fired yet.
+ * TRIG_FIRED: The volume exceeds the threshold
+ *
+ * To activate the trigger call either peak_meter_attack_trigger or
+ * peak_meter_release_trigger. To turn the trigger off call
+ * peak_meter_trigger_off.
+ */
+int peak_meter_trigger_status(void) {
+ return trig_status; /* & TRIG_PIT_MASK;*/
+}
+
+void peak_meter_draw_trig(int xpos, int ypos) {
+ int x = xpos + ICON_PLAY_STATE_WIDTH + 1;
+ switch (trig_status) {
+ long time_left;
+
+ case TRIG_READY:
+ scrollbar(x, ypos + 1, TRIGBAR_WIDTH, TRIG_HEIGHT - 2,
+ TRIGBAR_WIDTH, 0, 0, HORIZONTAL);
+ lcd_bitmap(bitmap_icons_7x8[Icon_Stop], xpos, ypos,
+ ICON_PLAY_STATE_WIDTH, STATUSBAR_HEIGHT, false);
+ break;
+
+ case TRIG_STEADY:
+ case TRIG_RETRIG:
+ time_left = trig_strt_duration - (current_tick - trig_hightime);
+ time_left = time_left * TRIGBAR_WIDTH / trig_strt_duration;
+ scrollbar(x, ypos + 1, TRIGBAR_WIDTH, TRIG_HEIGHT - 2,
+ TRIGBAR_WIDTH, 0, TRIGBAR_WIDTH - time_left, HORIZONTAL);
+ lcd_bitmap(bitmap_icons_7x8[Icon_Stop], xpos, ypos,
+ ICON_PLAY_STATE_WIDTH, STATUSBAR_HEIGHT, false);
+ break;
+
+ case TRIG_GO:
+ case TRIG_CONTINUE:
+ scrollbar(x, ypos + 1, TRIGBAR_WIDTH, TRIG_HEIGHT - 2,
+ TRIGBAR_WIDTH, TRIGBAR_WIDTH, TRIGBAR_WIDTH, HORIZONTAL);
+ lcd_bitmap(bitmap_icons_7x8[Icon_Record],
+ TRIG_WIDTH - ICON_PLAY_STATE_WIDTH, ypos,
+ ICON_PLAY_STATE_WIDTH, STATUSBAR_HEIGHT, false);
+ break;
+
+ case TRIG_POSTREC:
+ time_left = trig_stp_hold - (current_tick - trig_lowtime);
+ time_left = time_left * TRIGBAR_WIDTH / trig_stp_hold;
+ scrollbar(x, ypos + 1, TRIGBAR_WIDTH, TRIG_HEIGHT - 2,
+ TRIGBAR_WIDTH, time_left, TRIGBAR_WIDTH, HORIZONTAL);
+ lcd_bitmap(bitmap_icons_7x8[Icon_Record],
+ TRIG_WIDTH - ICON_PLAY_STATE_WIDTH, ypos,
+ ICON_PLAY_STATE_WIDTH, STATUSBAR_HEIGHT, false);
+ break;
+ }
+
+}
+
+int peak_meter_draw_get_btn(int x, int y, int width, int height)
+{
+ int button;
+ long next_refresh = current_tick;
+ long next_big_refresh = current_tick + HZ / 10;
+ button = BUTTON_NONE;
+ while (!TIME_AFTER(current_tick, next_big_refresh)) {
+ button = button_get(false);
+ if (button != BUTTON_NONE) {
+ break;
+ }
+ peak_meter_peek();
+ yield();
+
+ if (TIME_AFTER(current_tick, next_refresh)) {
+ peak_meter_draw(x, y, width, height);
+ lcd_update_rect(x, y, width, height);
+ next_refresh = current_tick + HZ / peak_meter_fps;
+ }
+ }
+ return button;
+}
+
#ifdef PM_DEBUG
static void peak_meter_clear_histogram(void) {
int i = 0;
diff --git a/apps/recorder/peakmeter.h b/apps/recorder/peakmeter.h
index db419a0afa..3c0a28bf3b 100644
--- a/apps/recorder/peakmeter.h
+++ b/apps/recorder/peakmeter.h
@@ -24,12 +24,12 @@
extern bool peak_meter_histogram(void);
#endif
-
extern bool peak_meter_enabled;
extern int peak_meter_fps;
extern void peak_meter_playback(bool playback);
extern void peak_meter_draw(int x, int y, int width, int height);
+extern int peak_meter_draw_get_btn(int x, int y, int width, int height);
extern void peak_meter_set_clip_hold(int time);
extern void peak_meter_peek(void);
extern void peak_meter_init_range( bool dbfs, int range_min, int range_max);
@@ -42,8 +42,40 @@ extern int peak_meter_get_max(void);
extern void peak_meter_set_use_dbfs(int use);
extern int peak_meter_get_use_dbfs(void);
extern int calc_db (int isample);
+extern int peak_meter_db2sample(int db);
extern unsigned short peak_meter_scale_value(unsigned short val, int meterwidth);
+/* valid values for trigger_status */
+#define TRIG_OFF 0x00
+#define TRIG_READY 0x01
+#define TRIG_STEADY 0x02
+#define TRIG_GO 0x03
+#define TRIG_POSTREC 0x04
+#define TRIG_RETRIG 0x05
+#define TRIG_CONTINUE 0x06
+
+extern void peak_meter_define_trigger(
+ int start_threshold,
+ long start_duration,
+ long start_dropout,
+ int stop_threshold,
+ long stop_hold_time,
+ long restart_gap
+ );
+
+extern void peak_meter_trigger(bool on);
+extern int peak_meter_trigger_status(void);
+extern void peak_meter_set_trigger_listener(void (*listener)(int status));
+
+//#define TRIG_WIDTH 12
+//#define TRIG_HEIGHT 14
+
+#define TRIG_WIDTH 112
+#define TRIG_HEIGHT 8
+#define TRIGBAR_WIDTH (TRIG_WIDTH - (2 * (ICON_PLAY_STATE_WIDTH + 1)))
+
+extern void peak_meter_draw_trig(int x, int y);
+
extern unsigned short peak_meter_range_min;
extern unsigned short peak_meter_range_max;
diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c
index 7aa6aba98c..39e94739b5 100644
--- a/apps/recorder/recording.c
+++ b/apps/recorder/recording.c
@@ -50,6 +50,7 @@
#include "talk.h"
#include "atoi.h"
#include "sound.h"
+#include "ata.h"
#ifdef HAVE_RECORDING
@@ -240,6 +241,56 @@ int rec_create_directory(void)
return 0;
}
+static char path_buffer[MAX_PATH];
+
+/* used in trigger_listerner and recording_screen */
+static unsigned int last_seconds = 0;
+
+/**
+ * Callback function so that the peak meter code can send an event
+ * to this application. This function can be passed to
+ * peak_meter_set_trigger_listener in order to activate the trigger.
+ */
+static void trigger_listener(int trigger_status)
+{
+ switch (trigger_status)
+ {
+ case TRIG_GO:
+ if((mpeg_status() & MPEG_STATUS_RECORD) != MPEG_STATUS_RECORD)
+ {
+ talk_buffer_steal(); /* we use the mp3 buffer */
+ mpeg_record(rec_create_filename(path_buffer));
+
+ /* give control to mpeg thread so that it can start recording */
+ yield(); yield(); yield();
+ }
+
+ /* if we're already recording this is a retrigger */
+ else
+ {
+ mpeg_new_file(rec_create_filename(path_buffer));
+ /* tell recording_screen to reset the time */
+ last_seconds = 0;
+ }
+ break;
+
+ /* A _change_ to TRIG_READY means the current recording has stopped */
+ case TRIG_READY:
+ if(mpeg_status() & MPEG_STATUS_RECORD)
+ {
+ mpeg_stop();
+ if (global_settings.rec_trigger_mode != TRIG_MODE_REARM)
+ {
+ peak_meter_set_trigger_listener(NULL);
+ peak_meter_trigger(false);
+ }
+ }
+ break;
+ }
+}
+
+#define BLINK_MASK 0x10
+
bool recording_screen(void)
{
long button;
@@ -252,12 +303,11 @@ bool recording_screen(void)
int update_countdown = 1;
bool have_recorded = false;
unsigned int seconds;
- unsigned int last_seconds = 0;
int hours, minutes;
char path_buffer[MAX_PATH];
bool been_in_usb_mode = false;
- bool led_state;
- int led_delay;
+ int last_mpeg_stat = -1;
+ bool last_led_stat = false;
const unsigned char *byte_units[] = {
ID2P(LANG_BYTE),
@@ -267,6 +317,9 @@ bool recording_screen(void)
};
cursor = 0;
+#ifndef SIMULATOR
+ ata_set_led_enabled(false);
+#endif
mpeg_init_recording();
sound_set(SOUND_VOLUME, global_settings.volume);
@@ -288,6 +341,8 @@ bool recording_screen(void)
set_gain();
+ settings_apply_trigger();
+
lcd_setfont(FONT_SYSFIXED);
lcd_getstringsize("M", &w, &h);
lcd_setmargins(global_settings.invert_cursor ? 0 : w, 8);
@@ -295,45 +350,93 @@ bool recording_screen(void)
if(rec_create_directory() > 0)
have_recorded = true;
- led_state = false;
- led_delay = 0;
-
while(!done)
{
+ int mpeg_stat = mpeg_status();
+
/*
* Flash the LED while waiting to record. Turn it on while
* recording.
*/
- if(mpeg_status() != MPEG_STATUS_RECORD)
+ if(mpeg_stat & MPEG_STATUS_RECORD)
{
- if(led_delay++ >= 4)
+ if (mpeg_stat & MPEG_STATUS_PAUSE)
+ {
+ /*
+ This is supposed to be the same as
+ led(current_tick & BLINK_MASK)
+ But we do this hubub to prevent unnecessary hardware
+ communication when the led already has the desired state.
+ */
+ if (last_led_stat != ((current_tick & BLINK_MASK) == BLINK_MASK))
+ {
+ /* trigger is on in status TRIG_READY (no check needed) */
+ last_led_stat = !last_led_stat;
+ led(last_led_stat);
+ }
+ }
+ else
{
- led_state = !led_state;
- invert_led(led_state);
- led_delay = 0;
+ /* trigger is on in status TRIG_READY (no check needed) */
+ led(true);
}
}
else
{
- if(!led_state)
+ int trigStat = peak_meter_trigger_status();
+
+ // other trigger stati than trig_off and trig_steady
+ // already imply that we are recording.
+ if (trigStat == TRIG_STEADY)
{
- led_state = true;
- invert_led(true);
+ /* This is supposed to be the same as
+ led(current_tick & BLINK_MASK)
+ But we do this hubub to prevent unnecessary hardware
+ communication when the led already has the desired state.
+ */
+ if (last_led_stat != ((current_tick & BLINK_MASK) == BLINK_MASK))
+ {
+ /* trigger is on in status TRIG_READY (no check needed) */
+ last_led_stat = !last_led_stat;
+ led(last_led_stat);
+ }
+ }
+ else
+ {
+ /* trigger is on in status TRIG_READY (no check needed) */
+ led(false);
}
}
- button = button_get_w_tmo(HZ / peak_meter_fps);
+ /* Wait for a button while drawing the peak meter */
+ button = peak_meter_draw_get_btn(0, 8 + h*2, LCD_WIDTH, h);
+
+ if (last_mpeg_stat != mpeg_stat)
+ {
+ if (mpeg_stat == MPEG_STATUS_RECORD)
+ {
+ have_recorded = true;
+ }
+ last_mpeg_stat = mpeg_stat;
+ }
+
switch(button)
{
case REC_STOPEXIT:
- if(mpeg_status() & MPEG_STATUS_RECORD)
+ if(mpeg_stat & MPEG_STATUS_RECORD)
{
+ /* turn off the trigger */
+ peak_meter_trigger(false);
+ peak_meter_set_trigger_listener(NULL);
mpeg_stop();
}
else
{
peak_meter_playback(true);
peak_meter_enabled = false;
+ /* turn off the trigger */
+ peak_meter_set_trigger_listener(NULL);
+ peak_meter_trigger(false);
done = true;
}
update_countdown = 1; /* Update immediately */
@@ -341,8 +444,13 @@ bool recording_screen(void)
case REC_RECPAUSE:
/* Only act if the mpeg is stopped */
- if(!(mpeg_status() & MPEG_STATUS_RECORD))
+ if(!(mpeg_stat & MPEG_STATUS_RECORD))
+ {
+ /* is this manual or triggered recording? */
+ if ((global_settings.rec_trigger_mode == TRIG_MODE_OFF) ||
+ (peak_meter_trigger_status() != TRIG_OFF))
{
+ /* manual recording */
have_recorded = true;
talk_buffer_steal(); /* we use the mp3 buffer */
mpeg_record(rec_create_filename(path_buffer));
@@ -353,9 +461,22 @@ bool recording_screen(void)
mpeg_beep(HZ/2); /* longer beep on start */
}
}
+
+ /* this is triggered recording */
+ else
+ {
+ update_countdown = 1; /* Update immediately */
+
+ /* we don't start recording now, but enable the
+ trigger and let the callback function
+ trigger_listener control when the recording starts */
+ peak_meter_trigger(true);
+ peak_meter_set_trigger_listener(&trigger_listener);
+ }
+ }
else
{
- if(mpeg_status() & MPEG_STATUS_PAUSE)
+ if(mpeg_stat & MPEG_STATUS_PAUSE)
{
mpeg_resume_recording();
if (global_settings.talk_menu)
@@ -473,11 +594,14 @@ bool recording_screen(void)
#ifdef REC_SETTINGS
case REC_SETTINGS:
- if(mpeg_status() != MPEG_STATUS_RECORD)
+ if(mpeg_stat != MPEG_STATUS_RECORD)
{
- invert_led(false);
+ /* led is restored at begin of loop / end of function */
+ led(false);
if (recording_menu(false))
+ {
return SYS_USB_CONNECTED;
+ }
settings_save();
if (global_settings.rec_prerecord_time)
@@ -491,7 +615,6 @@ bool recording_screen(void)
global_settings.rec_prerecord_time);
set_gain();
-
update_countdown = 1; /* Update immediately */
lcd_setfont(FONT_SYSFIXED);
@@ -502,9 +625,10 @@ bool recording_screen(void)
#ifdef REC_F2
case REC_F2:
- if(mpeg_status() != MPEG_STATUS_RECORD)
+ if(mpeg_stat != MPEG_STATUS_RECORD)
{
- invert_led(false);
+ /* led is restored at begin of loop / end of function */
+ led(false);
if (f2_rec_screen())
{
have_recorded = true;
@@ -518,16 +642,17 @@ bool recording_screen(void)
#ifdef REC_F3
case REC_F3:
- if(mpeg_status() & MPEG_STATUS_RECORD)
+ if(mpeg_stat & MPEG_STATUS_RECORD)
{
mpeg_new_file(rec_create_filename(path_buffer));
last_seconds = 0;
}
else
{
- if(mpeg_status() != MPEG_STATUS_RECORD)
+ if(mpeg_stat != MPEG_STATUS_RECORD)
{
- invert_led(false);
+ /* led is restored at begin of loop / end of function */
+ led(false);
if (f3_rec_screen())
{
have_recorded = true;
@@ -542,7 +667,7 @@ bool recording_screen(void)
case SYS_USB_CONNECTED:
/* Only accept USB connection when not recording */
- if(mpeg_status() != MPEG_STATUS_RECORD)
+ if(mpeg_stat != MPEG_STATUS_RECORD)
{
default_event_handler(SYS_USB_CONNECTED);
done = true;
@@ -555,8 +680,6 @@ bool recording_screen(void)
break;
}
- peak_meter_peek();
-
if(TIME_AFTER(current_tick, timeout))
{
lcd_setfont(FONT_SYSFIXED);
@@ -585,7 +708,7 @@ bool recording_screen(void)
dseconds = rec_timesplit_seconds();
- if(mpeg_status() & MPEG_STATUS_PRERECORD)
+ if(mpeg_stat & MPEG_STATUS_PRERECORD)
{
snprintf(buf, 32, "%s...", str(LANG_RECORD_PRERECORD));
}
@@ -618,15 +741,13 @@ bool recording_screen(void)
/* We will do file splitting regardless, since the OFF
setting really means 24 hours. This is to make sure
that the recorded files don't get too big. */
- if (mpeg_status() && (seconds >= dseconds))
+ if (mpeg_stat && (seconds >= dseconds))
{
mpeg_new_file(rec_create_filename(path_buffer));
update_countdown = 1;
last_seconds = 0;
}
- peak_meter_draw(0, 8 + h*2, LCD_WIDTH, h);
-
/* Show mic gain if input source is Mic */
if(global_settings.rec_source == 0)
{
@@ -635,9 +756,9 @@ bool recording_screen(void)
global_settings.rec_mic_gain,
buf2, sizeof(buf2)));
if (global_settings.invert_cursor && (pos++ == cursor))
- lcd_puts_style(0, 3, buf, STYLE_INVERT);
+ lcd_puts_style(0, 4, buf, STYLE_INVERT);
else
- lcd_puts(0, 3, buf);
+ lcd_puts(0, 4, buf);
}
else
{
@@ -650,53 +771,58 @@ bool recording_screen(void)
fmt_gain(SOUND_LEFT_GAIN, gain,
buf2, sizeof(buf2)));
if (global_settings.invert_cursor && (pos++ == cursor))
- lcd_puts_style(0, 3, buf, STYLE_INVERT);
+ lcd_puts_style(0, 4, buf, STYLE_INVERT);
else
- lcd_puts(0, 3, buf);
+ lcd_puts(0, 4, buf);
snprintf(buf, 32, "%s: %s", str(LANG_RECORDING_LEFT),
fmt_gain(SOUND_LEFT_GAIN,
global_settings.rec_left_gain,
buf2, sizeof(buf2)));
if (global_settings.invert_cursor && (pos++ == cursor))
- lcd_puts_style(0, 4, buf, STYLE_INVERT);
+ lcd_puts_style(0, 5, buf, STYLE_INVERT);
else
- lcd_puts(0, 4, buf);
+ lcd_puts(0, 5, buf);
snprintf(buf, 32, "%s: %s", str(LANG_RECORDING_RIGHT),
fmt_gain(SOUND_RIGHT_GAIN,
global_settings.rec_right_gain,
buf2, sizeof(buf2)));
if (global_settings.invert_cursor && (pos++ == cursor))
- lcd_puts_style(0, 5, buf, STYLE_INVERT);
+ lcd_puts_style(0, 6, buf, STYLE_INVERT);
else
- lcd_puts(0, 5, buf);
+ lcd_puts(0, 6, buf);
}
}
if(global_settings.rec_source != SOURCE_SPDIF)
- put_cursorxy(0, 3 + cursor, true);
-
- snprintf(buf, 32, "%s %s [%d]",
- freq_str[global_settings.rec_frequency],
- global_settings.rec_channels?
- str(LANG_CHANNEL_MONO):str(LANG_CHANNEL_STEREO),
- global_settings.rec_quality);
- lcd_puts(0, 6, buf);
+ put_cursorxy(0, 4 + cursor, true);
+
+ if (global_settings.rec_source != SOURCE_LINE) {
+ snprintf(buf, 32, "%s %s [%d]",
+ freq_str[global_settings.rec_frequency],
+ global_settings.rec_channels?
+ str(LANG_CHANNEL_MONO):str(LANG_CHANNEL_STEREO),
+ global_settings.rec_quality);
+ lcd_puts(0, 6, buf);
+ }
status_draw(true);
+ peak_meter_draw(0, 8 + h*2, LCD_WIDTH, h);
lcd_update();
}
- else
+
+ /* draw the trigger status */
+ if (peak_meter_trigger_status() != TRIG_OFF)
{
- lcd_clearrect(0, 8 + h*2, LCD_WIDTH, h);
- peak_meter_draw(0, 8 + h*2, LCD_WIDTH, h);
- lcd_update_rect(0, 8 + h*2, LCD_WIDTH, h);
+ peak_meter_draw_trig(LCD_WIDTH - TRIG_WIDTH, 4 * h);
+ lcd_update_rect(LCD_WIDTH - (TRIG_WIDTH + 2), 4 * h,
+ TRIG_WIDTH + 2, TRIG_HEIGHT);
}
}
- if(mpeg_status() & MPEG_STATUS_ERROR)
+ if(mpeg_stat & MPEG_STATUS_ERROR)
{
done = true;
}
@@ -721,6 +847,10 @@ bool recording_screen(void)
mpeg_init_playback();
+ /* make sure the trigger is really turned off */
+ peak_meter_trigger(false);
+ peak_meter_set_trigger_listener(NULL);
+
sound_settings_apply();
lcd_setfont(FONT_UI);
@@ -728,6 +858,9 @@ bool recording_screen(void)
if (have_recorded)
reload_directory();
+#ifndef SIMULATOR
+ ata_set_led_enabled(true);
+#endif
return been_in_usb_mode;
/*
#endif
@@ -883,10 +1016,26 @@ bool f3_rec_screen(void)
lcd_bitmap(bitmap_icons_7x8[Icon_FastBackward],
LCD_WIDTH/2 - 16, LCD_HEIGHT/2 - 4, 7, 8, true);
+ /* trigger setup */
+ ptr = str(LANG_RECORD_TRIGGER);
+ lcd_getstringsize(ptr,&w,&h);
+ lcd_putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT - h*2, ptr);
+ lcd_bitmap(bitmap_icons_7x8[Icon_DownArrow],
+ LCD_WIDTH/2 - 3, LCD_HEIGHT - h*3, 7, 8, true);
+
lcd_update();
button = button_get(true);
switch (button) {
+ case BUTTON_DOWN:
+ case BUTTON_F3 | BUTTON_DOWN:
+#ifndef SIMULATOR
+ rectrigger();
+ settings_apply_trigger();
+#endif
+ exit = true;
+ break;
+
case BUTTON_LEFT:
case BUTTON_F3 | BUTTON_LEFT:
global_settings.rec_source++;