audio.c.500d_under_construction.c
/** \file
* Onscreen audio meters
*/
/*
* Copyright (C) 2009 Trammell Hudson <hudson+ml@osresearch.net>
*
* 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.,
* 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
// include files
#include "dryos.h"
#include "bmp.h"
#include "config.h"
#include "property.h"
#include "menu.h"
#include "gui.h"
// ML config variables - stored in magic.cfg on the card.
CONFIG_INT( "audio.mgain", mgain, 5 );
CONFIG_INT( "audio.alc-enable", alc_enable, 0 );
CONFIG_INT("audio.draw-meters", cfg_draw_meters, 2);
CONFIG_INT( "audio.lovl", lovl, 0 );
CONFIG_INT("audio.monitoring", audio_monitoring, 1);
CONFIG_INT( "audio.mic-power", mic_power, 1 );
int loopback = 1;
// Declare some stuff.
static void audio_configure(int force);
void sounddev_task();
static int audio_cmd_to_gain_x1000(int cmd);
static void audio_monitoring_display_headphones_connected_or_not();
static void audio_menus_init();
int do_draw_meters = 0;
char label[10] = "RIGHT ";
PROP_INT(PROP_USBRCA_MONITOR, rca_monitor);
// declare audio_thresholds here since it doesn't exist in the 500d ROM (thanks Alex).
int audio_thresholds[] = { 0x7fff, 0x7213, 0x65ab, 0x5a9d, 0x50c2, 0x47fa, 0x4026, 0x392c, 0x32f4, 0x2d6a, 0x2879, 0x2412, 0x2026, 0x1ca7, 0x1989, 0x16c2, 0x1449, 0x1214, 0x101d, 0xe5c, 0xccc, 0xb68, 0xa2a, 0x90f, 0x813, 0x732, 0x66a, 0x5b7, 0x518, 0x48a, 0x40c, 0x39b, 0x337, 0x2dd, 0x28d, 0x246, 0x207, 0x1ce, 0x19c, 0x16f, 0x147 };
/****************************
* Structure declerations
****************************/
struct gain_struct
{
struct semaphore * sem;
unsigned alc1;
unsigned sig1;
unsigned sig2;
};
static struct gain_struct gain = {
.sem = (void*) 1,
};
struct audio_level audio_levels[2];
struct audio_level *get_audio_levels(void)
{
return audio_levels;
}
/*--------------------------------*/
/*****************************************************************************
* A function that isn't used, but I want to include it because it could be
* useful to someone else. Taken from original Audio.c file.
* -From Morgan Look
*****************************************************************************/
void masked_audio_ic_write(
unsigned reg, // the register we wish to manipulate (eg AUDIO_IC_SIG1)
unsigned mask, // the range of bits we want to manipulate (eg 0x05 or b0000111) to only allow changes to b3,b2,b0
unsigned bits // the bits we wish to set (eg 0x02 or b000010 to set b1, while clearing others within scope of the mask)
)
{
unsigned old; // variable to store current register value
old = audio_ic_read(reg); // read current register value
old &= ~mask; // bitwise AND old value against inverted mask
bits &= mask; // limit scope of new bits with mask
_audio_ic_write(reg | bits | old); // bitwise OR everything together and call _audio_ic_write function
}
/*----------------------------------------------------------------------------*/
///////////////////////////////////////////
// Some functions that will be used later.
///////////////////////////////////////////
int ext_cfg_draw_meters(void)
{
return cfg_draw_meters;
}
/** Returns a dB translated from the raw level
*
* Range is -40 to 0 dB
*/
static int
audio_level_to_db(
int raw_level
)
{
int db;
for( db = 40 ; db ; db-- )
{
if( audio_thresholds[db] > raw_level )
return -db;
}
return 0;
}
static uint8_t
db_to_color(int db)
{
if( db < -25 )
return 0x2F; // white
if( db < -12 )
return 0x06; // dark green
if( db < -3 )
return 0x0F; // yellow
return 0x0c; // dull red
}
static uint8_t
db_peak_to_color(int db)
{
if( db < -25 )
return 11; // dark blue
if( db < -12 )
return 11; // dark blue
if( db < -3 )
return 15; // bright yellow
return 0x08; // bright red
}
static void
draw_meter(int x_origin, int y_origin, int meter_height, struct audio_level *level, char *label)
{
const uint32_t width = 560; // bmp_width();
const uint32_t pitch = BMPPITCH;
uint32_t * row = (uint32_t*) bmp_vram();
if( !row )
return;
// Skip to the desired y coord and over the
// space for the numerical levels
// .. and the space for showing the channel and source.
row += (pitch/4) * y_origin + AUDIO_METER_OFFSET + x_origin/4;
const int db_peak_fast = audio_level_to_db( level->peak_fast );
const int db_peak = audio_level_to_db( level->peak );
// levels go from -40 to 0, so -40 * 14 == 560 (=width)
const uint32_t x_db_peak_fast = (width + db_peak_fast * 14) / 4;
const uint32_t x_db_peak = (width + db_peak * 14) / 4;
const uint8_t bar_color = db_to_color( db_peak_fast );
const uint8_t peak_color = db_peak_to_color( db_peak );
const uint32_t bar_color_word = color_word( bar_color );
const uint32_t peak_color_word = color_word( peak_color );
const uint32_t bg_color_word = color_word(COLOR_BLACK);
// Write the meter an entire scan line at a time
int y;
for( y=0 ; y<meter_height ; y++, row += pitch/4 )
{
uint32_t x;
for( x=0 ; x<width/4 ; x++ )
{
if( x < x_db_peak_fast )
row[x] = bar_color_word;
else
if( x < x_db_peak )
row[x] = bg_color_word;
else
if( x < x_db_peak + 4 )
row[x] = peak_color_word;
else
row[x] = bg_color_word;
}
}
// Write the current level
bmp_printf( FONT(FONT_SMALL, COLOR_WHITE, COLOR_BLACK), x_origin, y_origin, "%s %02d", label, MIN(db_peak, -1) );
}
static void
draw_ticks(int x, int y, int tick_height)
{
const uint32_t width = 560 + 8; // bmp_width();
const uint32_t pitch = BMPPITCH;
uint32_t * row = (uint32_t*) bmp_vram();
if( !row )
return;
row += (pitch/4) * y + AUDIO_METER_OFFSET - 2 + x/4;//seems to need less of an offset
const uint32_t white_word = 0
| ( COLOR_WHITE << 24 )
| ( COLOR_WHITE << 16 )
| ( COLOR_WHITE << 8 )
| ( COLOR_WHITE << 0 );
for( ; tick_height > 0 ; tick_height--, row += pitch/4 )
{
int db;
for( db=-40; db<= 0 ; db+=5 )
{
const uint32_t x_db = width + db * 14;
row[x_db/4] = white_word;
}
}
}
/* Normal VU meter */
static void draw_meters(void)
{
int screen_layout = get_screen_layout();
// The db values are multiplied by 8 to make them
// smoother.
int erase = 0;
int hs = get_halfshutter_pressed();
static int prev_hs = 0;
if (hs != prev_hs) erase = 1;
prev_hs = hs;
int x0 = 0;
int y0 = 0;
int small = 0;
if (gui_menu_shown())
{
x0 = os.x0 + os.x_ex/2 - 360;
y0 = os.y0 + os.y_ex/2 - 240;
y0 += 350;
x0 += 10;
}
else
{
small = hs;
x0 = os.x0 + os.x_ex/2 - 360;
if (screen_layout == SCREENLAYOUT_3_2) y0 = os.y0; // just above the 16:9 frame
else if (screen_layout == SCREENLAYOUT_16_9) { small = 1; y0 = os.y0 + os.off_169; } // meters just below 16:9 border
else if (screen_layout == SCREENLAYOUT_16_10) {small = 1; y0 = os.y0 + os.off_1610; } // meters just below 16:10 border
else if (screen_layout == SCREENLAYOUT_UNDER_3_2) y0 = MIN(os.y_max, vram_bm.height - 54);
else if (screen_layout == SCREENLAYOUT_UNDER_16_9) y0 = MIN(os.y_max - os.off_169, vram_bm.height - 54);
if (hdmi_code) small = 1;
}
if (erase)
{
bmp_fill(
screen_layout >= SCREENLAYOUT_UNDER_3_2 ? BOTTOMBAR_BGCOLOR : TOPBAR_BGCOLOR,
x0, y0, 720, small ? 20 : 34
);
}
else if (hs) return; // will draw top bar instead
else if (!small)
{
// mono mic on 500d :(
draw_ticks( x0, y0 + 10, 3 );
draw_meter( x0, y0 + 12, 10, &audio_levels[0], label);
draw_ticks( x0, y0 + 20, 3 );
}
else
{
draw_ticks( x0, y0 + 7, 2 );
draw_meter( x0, y0 + 8, 7, &audio_levels[0], label);
draw_ticks( x0, y0 + 17, 2 );
}
if (gui_menu_shown() && alc_enable)
{
int dgain_x1000 = audio_cmd_to_gain_x1000(audio_ic_read(AUDIO_IC_ALCVOL));
bmp_printf(FONT_MED, 10, 340, "AGC:%s%d.%03d dB", dgain_x1000 < 0 ? "-" : " ", ABS(dgain_x1000) / 1000, ABS(dgain_x1000) % 1000);
}
}
static void
compute_audio_levels(int ch)
{
struct audio_level * const level = &audio_levels[ch];
int raw = audio_read_level( ch );
if( raw < 0 )
raw = -raw;
level->last = raw;
level->avg = (level->avg * 15 + raw) / 16;
if( raw > level->peak )
level->peak = raw;
if( raw > level->peak_fast )
level->peak_fast = raw;
// Decay the peak to the average
level->peak = ( level->peak * 63 + level->avg ) / 64;
level->peak_fast = ( level->peak_fast * 7 + level->avg ) / 8;
}
void audio_monitoring_display_headphones_connected_or_not()
{
NotifyBoxHide();
NotifyBox(2000,
"Headphones %s",
AUDIO_MONITORING_HEADPHONES_CONNECTED ?
"connected" :
"disconnected");
}
static void audio_monitoring_force_display(int x)
{
prop_deliver(*(int*)(HOTPLUG_VIDEO_OUT_PROP_DELIVER_ADDR), &x, 4, 0x0);
}
static void audio_monitoring_update()
{
// kill video connect/disconnect event... or not
*(int*)HOTPLUG_VIDEO_OUT_STATUS_ADDR = audio_monitoring ? 2 : 0;
if (audio_monitoring && rca_monitor)
{
audio_monitoring_force_display(0);
msleep(1000);
audio_monitoring_display_headphones_connected_or_not();
}
}
int audio_meters_are_drawn()
{
return
(
is_movie_mode() && cfg_draw_meters && do_draw_meters && get_global_draw() && !gui_menu_shown() && lv_dispsize == 1
)
||
(
gui_menu_shown() && is_menu_active("Audio") && cfg_draw_meters
);
}
static inline unsigned mgain_index2gain(int index) // sorted mgain values
{
static uint8_t gains[] = { 0, 3, 6, 10, 17, 20, 23, 26, 29, 32 };
return gains[COERCE(index, 0, 10)];
}
static int
audio_cmd_to_gain_x1000(
int cmd
)
{
int gain_x1000 = (cmd - 145) * 375;
return gain_x1000;
}
static void
enable_meters(int mode)
{
loopback = do_draw_meters = !mode;
audio_configure( 1 );
}
/*-------------------------------------------*/
/******************************
* Dummy functions for now.
******************************/
void volume_up()
{
}
void volume_down()
{
}
/*--------------------------------*/
/**************************************
* Property stuff goes here.
**************************************/
PROP_HANDLER( PROP_LV_ACTION )
{
const unsigned mode = buf[0];
enable_meters( mode );
return prop_cleanup( token, property );
}
/*---------------------------------------*/
/*********************************************************************
* Analog gain control function.
*
* This is messy I know, but it's the only way I know how to do it.
* The problem is that the 500d has to change 3 bits in AUDIO_IC_SIG1,
* but the other cameras only have to change 2, so I can't use Trammell's
* routine here, I had to write my own. Also, this way we get to use all
* of the extra gain settings the 500d has :).
*
* This basically writes the required bits one at a time (in seperate statements),
* which is easier to read and understand, but probably not very efficient.
*
* I used the PDF on the AK4346 audio chip from here:
* http://www.asahi-kasei.co.jp/akm/en/product/ak4636/ak4636_f01e.pdf
*
* -Coutts
*********************************************************************/
static inline void
audio_ic_set_mgain(
unsigned mgain
)
{
unsigned sig1 = audio_ic_read( AUDIO_IC_SIG1 ); // Read the value of register 'Signal Select 1', store it in sig1.
// We will use this later when we set individual bits on/off for
// different gain values.
unsigned sig2 = audio_ic_read( AUDIO_IC_SIG2 ); // Read the value of register 'Signal Select 2', store it in sig2.
// Setting the bits for each possible gain setting in the 500d, individually so it's easy to understand.
// - 24 hours ago I didn't even understand how to configure the audio chip, so I think this is pretty good
// for my first implemenation :)
//
// Basically, different gain settings use different combinations of the MGAIN0, MGAIN1, MGAIN2, and MGAIN3 bits being set/cleared.
// Here's a reference table for the settings, taken from the pdf linked from line 201 above:
//
//---------------------------------------------------------
// MGAIN3 | MGAIN2 | MGAIN1 | MGAIN0 || Gain Value
//---------------------------------------------------------
// 0 | 0 | 0 | 0 || 0 dB
// 0 | 0 | 0 | 1 || +20 dB (default setting)
// 0 | 0 | 1 | 0 || +26 dB
// 0 | 0 | 1 | 1 || +32 dB
// 0 | 1 | 0 | 0 || +10 dB
// 0 | 1 | 0 | 1 || +17 dB
// 0 | 1 | 1 | 0 || +23 dB
// 0 | 1 | 1 | 1 || +29 dB
// 1 | 0 | 0 | 0 || +3 dB
// 1 | 0 | 0 | 1 || +6 dB
//---------------------------------------------------------
//
// So my switch statement below looks at the value of the mgain variable (which is changed by the gain setting in the ML menu),
// and sets the correct combination of bits accordingly.
//
// &= ~(1 << x) means clear bit x
// |= 1 << x means set bit x
//
// That should be enough to bring anybody up to speed on things.
// -Coutts
switch (mgain)
{
case 0: // 0 dB
sig1 &= ~(1 << 0); //clear bit1 [MGAIN0] in register 'Signal Select 1'
sig1 &= ~(1 << 1); //clear bit2 [MGAIN2] "
sig1 &= ~(1 << 3); //clear bit3 [MGAIN3] "
sig2 &= ~(1 << 5); //clear bit4 [MGAIN1] in register 'Signal Select 2'
break;
case 1: // 3 dB
sig1 &= ~(1 << 0); //clear MGAIN0
sig1 &= ~(1 << 1); //clear MGAIN2
sig1 |= 1 << 3; //set MGAIN3
sig2 &= ~(1 << 5); //clear MGAIN1
break;
case 2: // 6 dB
sig1 &= ~(1 << 1); // [etc, etc, etc]
sig1 |= 1 << 0; // | |
sig1 |= 1 << 3; // | |
sig2 &= ~(1 << 5); // V V
break;
case 3: // 10 dB
sig1 &= ~(1 << 0);
sig1 &= ~(1 << 3);
sig1 |= 1 << 1;
sig2 &= ~(1 << 5);
break;
case 4: // 17 dB
sig1 &= ~(1 << 3);
sig1 |= 1 << 0;
sig1 |= 1 << 1;
sig2 &= ~(1 << 5);
break;
case 5: // 20 dB
sig1 &= ~(1 << 1);
sig1 &= ~(1 << 3);
sig1 |= 1 << 0;
sig2 &= ~(1 << 5);
break;
case 6: // 23 dB
sig1 &= ~(1 << 0);
sig1 &= ~(1 << 3);
sig1 |= 1 << 1;
sig2 |= 1 << 5;
break;
case 7: // 26 dB
sig1 &= ~(1 << 0);
sig1 &= ~(1 << 1);
sig1 &= ~(1 << 3);
sig2 |= 1 << 5;
break;
case 8: // 29 dB
sig1 &= ~(1 << 3);
sig1 |= 1 << 0;
sig1 |= 1 << 1;
sig2 |= 1 << 5;
break;
case 9: // 32 dB
sig1 &= ~(1 << 1);
sig1 &= ~(1 << 3);
sig1 |= 1 << 0;
sig2 |= 1 << 5;
break;
}
audio_ic_write( AUDIO_IC_SIG1 | sig1 ); // Now that the correct bits in sig1 and sig2 have been set/cleared for whatever
gain.sig1 = sig1; // gain setting we want, now it's time to write our new values for 'Signal Select 1'
// and 'Signal Select 2' to their respective registers in the audio chip.
audio_ic_write( AUDIO_IC_SIG2 | sig2 );
gain.sig2 = sig2;
}
/*-------------------------------------------------------*/
/************************************************************************
* Reconfigure the audio chip registers to toggle things like AGC.
************************************************************************/
static void
audio_configure( int force )
{
// No need to worry about input source, we only have one option on the 500d.
snprintf(label, sizeof(label), " INT ");
bmp_printf(FONT_MED, 0, 200, "gain.alc: %x", gain.alc1);
bmp_printf(FONT_MED, 0, 220, "gain.sig1: %x", gain.sig1);
bmp_printf(FONT_MED, 0, 240, "gain.sig2: %x", gain.sig2);
if( !force )
{
//////////////////////////////////////////////////////////////////////////
// Check if AGC or analog gain settings have changed, if they are still
// the same, then don't do anything - no need to set things that are
// already set :)
// -Coutts
//////////////////////////////////////////////////////////////////////////
if( audio_ic_read( AUDIO_IC_ALC1 ) == gain.alc1
&& audio_ic_read( AUDIO_IC_SIG1 ) == gain.sig1
&& audio_ic_read( AUDIO_IC_SIG2 ) == gain.sig2
)
return;
}
///////////////////////////////////////////////////////////////////
// Power up some modules used for line out and stuff - not sure
// about much behind this, but this register seems to be identical
// between the AK4346 and AK4646 chips, so I guess it's okay.
// -Coutts
///////////////////////////////////////////////////////////////////
//audio_ic_write( AUDIO_IC_PM1 | 0x6D );
/*------------------------------------------------------------------*/
audio_ic_write( AUDIO_IC_SIG1 | 0x14 ); // enables headphone loopback in play mode.
////////////////////////////////////////////////////////////////////////////////////
////////////// Set the bits in 'Signal Select 2' for line out *only* ///////////////
////////////////////////////////////////////////////////////////////////////////////
// Only set the third bit, in binary it's '100', this is just to set the BEEPA bit.
//
// In the AK4646 chip it's called BEEPL, but they appear to be the same thing.
// The purpose of this is to switch the BEEP signal to the mono-amp, which I guess
// means mono line out?
//
// Also, we don't need to set bits 1 and 2 like in the AK4646 chip. These bits are for
// LOVL0 and LOVL1, which control stereo line out gain, with either +0db, +2db, +4db, or +6db.
//
// The 500d only uses one bit for this, which means we only have 2 options. +0db or +3db.
// Our bit is located in register 'Signal Select 4'. In the AK4646 chip, the register in this location
// is 'Power Management 3'. This register is named simply 'LOVL'.
//
// So, instead of setting bits 1 and 2 in AUDIO_IC_SIG2, we actually need to set bit 7 in 'Signal Select 4'.
//
// -Coutts
////////////////////////////////////////////////////////////////////////////////////
audio_ic_write( AUDIO_IC_SIG2 | 0x4 ); // 0x4 == 00000100.
// Set the mono line gain to +3db (max).
audio_ic_write( AUDIO_IC_SIG4 | 0x40 ); // 0x40 == 01000000.
/*-----------------------------------*/
gain.alc1 = alc_enable ? (1<<5) : 0;
audio_ic_write( AUDIO_IC_ALC1 | gain.alc1 ); // disable all ALC
// Update the analog gain settings.
audio_ic_set_mgain( mgain );
}
/*------------------------------------------------------------------------*/
/**********************************************
* Toggling functions for menu settings.
**********************************************/
static void
audio_mgain_toggle( void * priv ) //toggle forward for analog gain.
{
unsigned * ptr = priv;
*ptr = MOD((*ptr + 1), 10);
audio_configure( 1 );
}
static void
audio_mgain_toggle_reverse( void * priv ) //toggle reverse for analog gain.
{
unsigned * ptr = priv;
*ptr = MOD((*ptr - 1), 10);
audio_configure( 1 );
}
static void
audio_monitoring_toggle( void * priv)
{
audio_monitoring = !audio_monitoring;
audio_monitoring_update();
}
/*----------------------------------------*/
/******************************************
* Display functions for menus.
******************************************/
static void
audio_alc_display( void * priv, int x, int y, int selected )
{
unsigned fnt = selected ? MENU_FONT_SEL : MENU_FONT;
bmp_printf(
FONT(fnt, alc_enable ? COLOR_RED : FONT_FG(fnt), FONT_BG(fnt)),
x, y,
"AGC : %s",
alc_enable ? "ON " : "OFF"
);
}
static void
audio_mgain_display( void * priv, int x, int y, int selected )
{
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Analog Gain : %d dB",
mgain_index2gain(mgain)
);
menu_draw_icon(x, y, MNI_PERCENT, mgain_index2gain(mgain) * 100 / 32);
}
static void
audio_meter_display( void * priv, int x, int y, int selected )
{
unsigned v = *(unsigned*) priv;
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Audio Meters : %s",
v ? "ON" : "OFF"
);
menu_draw_icon(x, y, MNI_BOOL_GDR(v));
}
static void
audio_monitoring_display( void * priv, int x, int y, int selected )
{
bmp_printf(
selected ? MENU_FONT_SEL : MENU_FONT,
x, y,
"Monitoring-USB: %s",
audio_monitoring ? "ON" : "OFF"
);
}
/*----------------------------------------*/
/******************************************
* Audio menu order / layout
******************************************/
static struct menu_entry audio_menus[] = {
{
.name = "Audio Meters",
.priv = &cfg_draw_meters,
.select = menu_binary_toggle,
.display = audio_meter_display,
.help = "Bar peak decay, from -40 dB to 0 dB, yellow at -12dB."
},
{
.name = "AGC",
.priv = &alc_enable,
.select = menu_binary_toggle,
.display = audio_alc_display,
.help = "Automatic Gain Control - turn it off :)"
},
{
.name = "Analog Gain (dB)",
.priv = &mgain,
.select = audio_mgain_toggle,
.select_reverse = audio_mgain_toggle_reverse,
.display = audio_mgain_display,
.help = "Gain applied to both inputs in analog domain (preferred)."
},
{
.name = "Monitoring-USB",
.priv = &audio_monitoring,
.select = audio_monitoring_toggle,
.display = audio_monitoring_display,
.help = "Audio monitoring via USB. Disable if you use a SD display."
},
};
/*----------------------------------------*/
/******************************************
* Display the Audio menu section.
******************************************/
static void audio_menus_init()
{
menu_add( "Audio", audio_menus, COUNT(audio_menus) );
}
/*----------------------------------------*/
/*********************************************************
*--------------------------------------------------------
* ALL TASKS AFTER THIS
*--------------------------------------------------------
*********************************************************/
/******************************************************************************
* Our version of canon's sounddev task. We override canon's task
* so that we can change things like AGC and analog/digital gain.
*
* If this is a magic_off boot, then just call canon's built-in
* task and don't do anything.
******************************************************************************/
static void
my_sounddev_task()
{
msleep( 2000 );
// If this is a magic_off boot, don't start our task, just call canon's task.
if (magic_is_off()) { sounddev_task(); return; }
// Wait until ML has started up.
hold_your_horses(1);
// Semaphores
gain.sem = create_named_semaphore( "audio_gain", 1);
sounddev.sem_alc = CreateBinarySemaphore( 0, 0 );
audio_configure( 1 ); // force it to run this first time to re-configure the sound device.
msleep(500);
audio_monitoring_update(); // Update audio monitoring stuff.
while(1) //time to loop!!
{
int rc = take_semaphore( gain.sem, 1000 );
if(gui_state != GUISTATE_PLAYMENU || (audio_monitoring && AUDIO_MONITORING_HEADPHONES_CONNECTED)) {
audio_configure( rc == 0 ); // force it if we got the semaphore
}
}
}
// override canon's sounddev task with our own.
TASK_OVERRIDE( sounddev_task, my_sounddev_task );
/*--------------------------------------------------------------------------------*/
/******************************************************************************
* Task to monitor the audio levels.
*
* Compute the average and peak level, periodically calling
* the draw_meters() function to display the results on screen.
* \todo Check that we have live-view enabled and the TFT is on
* before drawing.
******************************************************************************/
static void
meter_task( void* unused )
{
audio_menus_init();
while(1)
{
msleep( 50 );
if (is_menu_help_active()) continue;
if (audio_meters_are_drawn())
{
if (!is_mvr_buffer_almost_full())
BMP_LOCK( draw_meters(); )
}
if (audio_monitoring)
{
static int hp = 0;
int h = AUDIO_MONITORING_HEADPHONES_CONNECTED;
if (h != hp)
{
audio_monitoring_display_headphones_connected_or_not();
}
hp = h;
}
}
}
/*------------------------------------------------------------*/
TASK_CREATE( "meter_task", meter_task, 0, 0x18, 0x1000 );
/****************************************************
* Monitor the audio levels very quickly
****************************************************/
static void
compute_audio_level_task( void* unused )
{
audio_levels[0].peak = audio_levels[1].peak = 0;
audio_levels[0].avg = audio_levels[1].avg = 0;
while(1)
{
msleep( 10 );
compute_audio_levels( 0 );
compute_audio_levels( 1 );
}
}
TASK_CREATE( "audio_level_task", compute_audio_level_task, 0, 0x18, 0x1000 );