int visualizer_vumeter(lua_State *L) { long long sample_accumulator[2]; int16_t *ptr; s16_t sample; s32_t sample_sq; size_t i, num_samples, samples_until_wrap; int offs; num_samples = luaL_optinteger(L, 2, VUMETER_DEFAULT_SAMPLE_WINDOW); sample_accumulator[0] = 0; sample_accumulator[1] = 0; vis_check(); if (vis_get_playing()) { vis_lock(); offs = vis_get_buffer_idx() - (num_samples * 2); while (offs < 0) offs += vis_get_buffer_len(); ptr = vis_get_buffer() + offs; samples_until_wrap = vis_get_buffer_len() - offs; for (i=0; i<num_samples; i++) { sample = (*ptr++) >> 7; sample_sq = sample * sample; sample_accumulator[0] += sample_sq; sample = (*ptr++) >> 7; sample_sq = sample * sample; sample_accumulator[1] += sample_sq; samples_until_wrap -= 2; if (samples_until_wrap <= 0) { ptr = vis_get_buffer(); samples_until_wrap = vis_get_buffer_len(); } } vis_unlock(); } sample_accumulator[0] /= num_samples; sample_accumulator[1] /= num_samples; lua_newtable(L); lua_pushinteger(L, sample_accumulator[0]); lua_rawseti(L, -2, 1); lua_pushinteger(L, sample_accumulator[1]); lua_rawseti(L, -2, 2); return 1; }
// --------------------------------------------------------------------------- // Main (functional test). // --------------------------------------------------------------------------- int main( void ) { struct timeval start, end; uint32_t elapsed; // Elapsed time in milliseconds. uint8_t i; struct display_mode_t { bool data; // Data mode (4-bit or 8-bit). bool lines; // Display lines. bool font; // Font. bool display; // Display on/off. bool cursor; // Cursor on/off. bool blink; // Blink (block cursor) on/off. bool counter; // Counter incrementation. bool shift; // Display shift. bool mode; // Cursor mode. bool direction; // Cursor direction. } display_mode = { .data = 1, // 8-bit mode. .lines = 1, // 2 display lines. .font = 1, // 5x8 font. .display = 1, // Display on. .cursor = 0, // Cursor off. .blink = 0, // Blink (block cursor) off. .counter = 1, // Increment DDRAM counter after data write .shift = 0, // Do not shift display after data write. .mode = 0, // Shift cursor. .direction = 0, // Right. }; struct hd44780 *hd44780this; int8_t err; // Initialise MCP23017. err = mcp23017Init( 0x20 ); if ( err < 0 ) { printf( "Couldn't init. Try loading i2c-dev module.\n" ); return -1; } // Set direction of GPIOs. mcp23017WriteByte( mcp23017[0], IODIRA, 0x00 ); // Output. mcp23017WriteByte( mcp23017[0], IODIRB, 0x00 ); // Output. // Writes to latches are the same as writes to GPIOs. mcp23017WriteByte( mcp23017[0], OLATA, 0x00 ); // Clear pins. mcp23017WriteByte( mcp23017[0], OLATB, 0x00 ); // Clear pins. // Set BANK bit for 8-bit mode. mcp23017WriteByte( mcp23017[0], IOCONA, 0x80 ); hd44780this = malloc( sizeof( struct hd44780 )); // Set up hd44780 data. /* +---------------------------------------------------------------+ | GPIOB | GPIOA | |-------------------------------+-------------------------------| | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---| |DB7|DB6|DB5|DB4|DB3|DB2|DB1|DB0|RS |R/W| E |---|---|---|---|---| +---------------------------------------------------------------+ */ hd44780this->rs = 0x80; // HD44780 RS pin. hd44780this->rw = 0x40; // HD44780 R/W pin. hd44780this->en = 0x20; // HD44780 E pin. hd44780[0] = hd44780this; // Initialise display. hd44780Init( mcp23017[0], hd44780[0], display_mode.data, display_mode.lines, display_mode.font, display_mode.display, display_mode.cursor, display_mode.blink, display_mode.counter, display_mode.shift, display_mode.mode, display_mode.direction ); // hd44780WriteString( mcp23017[0], hd44780[0], "Initialised" ); // Custom characters. const uint8_t meter_chars[CUSTOM_MAX][CUSTOM_SIZE] = {{ 0x1f, 0x17, 0x17, 0x17, 0x17, 0x17, 0x11, 0x1f }, { 0x1f, 0x11, 0x15, 0x11, 0x13, 0x15, 0x15, 0x1f }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x1f }, { 0x1f, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x1f }, { 0x1f, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x1f, 0x1d, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f }, { 0x1f, 0x1d, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f }}; hd44780LoadCustom( mcp23017[0], hd44780[0], meter_chars ); vis_check(); pthread_mutex_init( &displayBusy, NULL ); pthread_t threads[1]; // Calculate number of samples for integration time. peak_meter.samples = vis_get_rate() * peak_meter.int_time / 1000; if ( peak_meter.samples < 1 ) peak_meter.samples = 1; peak_meter.samples = 2; // Minimum samples for fastest response but may miss peaks. printf( "Samples for %dms = %d.\n", peak_meter.int_time, peak_meter.samples ); // Do some loops to test response time. gettimeofday( &start, NULL ); for ( i = 0; i < TEST_LOOPS; i++ ) { get_dBfs( &peak_meter ); get_dB_indices( &peak_meter ); get_peak_strings( peak_meter, lcd_meter ); // Write to LCD. hd44780Goto( mcp23017[0], hd44780[0], 0, 0 ); hd44780WriteString( mcp23017[0], hd44780[0], lcd_meter[0], 16 ); hd44780Goto( mcp23017[0], hd44780[0], 1, 0 ); hd44780WriteString( mcp23017[0], hd44780[0], lcd_meter[1], 16 ); usleep( METER_DELAY ); } gettimeofday( &end, NULL ); elapsed = (( end.tv_sec - start.tv_sec ) * 1000 + ( end.tv_usec - start.tv_usec ) / 1000 ) / 10; if ( elapsed < peak_meter.hold_time ) peak_meter.hold_count = peak_meter.hold_time / elapsed; pthread_create( &threads[0], NULL, update_meter, NULL ); while ( 1 ) { }; pthread_mutex_destroy( &displayBusy ); pthread_exit( NULL ); return 0; }