⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 peakmeter.c

📁 编译后直接运行的MP3播放器全部C语言源代码 一个包含FAT文件系统、系统引导 Boot、FLASH Driver等内容的
💻 C
📖 第 1 页 / 共 2 页
字号:
/*************************************************************************** *             __________               __   ___. *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___ *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  / *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  < *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \ *                     \/            \/     \/    \/            \/ * $Id: peakmeter.c,v 1.9 2003/01/30 15:52:47 edx_fa Exp $ * * Copyright (C) 2002 by Philipp Pertermann * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/#include "config.h"#include "mas.h"#include "thread.h"#include "kernel.h"#include "settings.h"#include "lcd.h"#include "wps-display.h"#include "sprintf.h"#include "button.h"#include "system.h"#include "font.h"#include "icons.h"#include "lang.h"#include "peakmeter.h"/* no inline in simulator mode */#ifdef SIMULATOR#define inline#endif/* buffer the read peak value */static int peak_meter_max_l;static int peak_meter_max_r;/* point in time when peak_meter_max_x becomes invalid */static long peak_meter_timeout_l;static long peak_meter_timeout_r;/* when true a clip has occurred */static bool peak_meter_l_clip = false;static bool peak_meter_r_clip = false;/* point in time when peak_meter_x_oveflow becomes invalid */static long peak_meter_clip_timeout_l;static long peak_meter_clip_timeout_r;static int  peak_meter_clip_hold;/* specifies the value range in peak volume values */static unsigned short peak_meter_range_min;static unsigned short peak_meter_range_max;static unsigned short peak_meter_range;/* if set to true clip timeout is disabled */static bool peak_meter_clip_eternal = false;static bool peak_meter_use_dbfs = true;static unsigned short db_min = 0;static unsigned short db_max = 9000;static unsigned short db_range = 9000;#ifndef SIMULATORstatic int peak_meter_src_l = MAS_REG_DQPEAK_L;static int peak_meter_src_r = MAS_REG_DQPEAK_R;#endif/* temporarily en- / disables peak meter. This is   especially for external applications to detect    if the peak_meter is in use and needs drawing at all */bool peak_meter_enabled = true;/*bool peak_meter_use_thread = false;static char peak_meter_stack[DEFAULT_STACK_SIZE];*//* used in wps.c to set the display frame rate of the peak meter */int peak_meter_fps = 20;static int peak_meter_l;static int peak_meter_r;static int peak_meter_hold = 1;static int peak_meter_release = 8;/* debug only */#ifdef PM_DEBUGstatic int peek_calls = 0;#define PEEKS_PER_DRAW_SIZE 40static unsigned int peeks_per_redraw[PEEKS_PER_DRAW_SIZE];#define TICKS_PER_DRAW_SIZE 20static unsigned int ticks_per_redraw[TICKS_PER_DRAW_SIZE];#endif/* time out values for max */static long max_time_out[] = {    0 * HZ, HZ / 5, 30, HZ / 2, HZ, 2 * HZ,     3 * HZ, 4 * HZ, 5 * HZ, 6 * HZ, 7 * HZ, 8 * HZ,    9 * HZ, 10 * HZ, 15 * HZ, 20 * HZ, 30 * HZ, 60 * HZ};/* time out values for clip */static long clip_time_out[] = {    0 * HZ, 1  * HZ, 2 * HZ, 3 * HZ, 4 * HZ, 5 * HZ,     6 * HZ, 7 * HZ, 8 * HZ, 9 * HZ, 10 * HZ, 15 * HZ,    20 * HZ, 25 * HZ, 30 * HZ, 45 * HZ, 60 * HZ, 90 * HZ,    120 * HZ, 180 * HZ, 300 * HZ, 600 * HZ, 1200 * HZ,    2700 * HZ, 5400 * HZ};/* precalculated peak values that represent magical   dBfs values. Used to draw the scale */#define DB_SCALE_SRC_VALUES_SIZE 11#if 0const static int db_scale_src_values[DB_SCALE_SRC_VALUES_SIZE] = {    32767, /*   0 db */    23197, /* - 3 db */    16422, /* - 6 db */    11626, /* - 9 db */    8231,  /* -12 db */    4125,  /* -18 db */    2067,  /* -24 db */    1036,  /* -30 db */    328,   /* -40 db */    104,   /* -50 db */    33,    /* -60 db */};#elsestatic const int db_scale_src_values[DB_SCALE_SRC_VALUES_SIZE] = {    32752, /*   0 db */    22784, /* - 3 db */    14256, /* - 6 db */    11752, /* - 9 db */    9256,  /* -12 db */    4256,  /* -18 db */    2186,  /* -24 db */    1186,  /* -30 db */    373,   /* -40 db */    102,   /* -50 db */    33,    /* -60 db */};#endifstatic int db_scale_count = DB_SCALE_SRC_VALUES_SIZE;/* if db_scale_valid is false the content of    db_scale_lcd_coord needs recalculation */static bool db_scale_valid = false;/* contains the lcd x coordinates of the magical   scale values in db_scale_src_values */static int db_scale_lcd_coord[sizeof db_scale_src_values / sizeof (int)];/** * Calculates dB Value for the peak meter, uses peak value as input * @param int sample - The input value  *                    Make sure that 0 <= value < SAMPLE_RANGE * * @return int - The 2 digit fixed comma result of the euation *               20 * log (sample / SAMPLE_RANGE) + 90 *               Output range is 0-8961 (that is 0,0 - 89,6 dB). *               Normally 0dB is full scale, here it is shifted +90dB. *               The calculation is based on the results of a linear *               approximation tool written specifically for this problem *               by Andreas Zwirtes (radhard@gmx.de). The result hat an *               accurracy of better than 2%. It is highly runtime optimized, *               the cascading if-clauses do an successive approximation on *               the input value. This avoids big lookup-tables and *               for-loops. */int calc_db (int isample) {    /* return n+m*(isample-istart)/100 */    int n;    long m;    int istart;    /* Range 1-4 */    if (isample < 119) {        /* Range 1-2 */        if (isample < 5) {            /* Range 1 */            if (isample < 1) {                istart = 0;                n = 0;                m = 5900;            }            /* Range 2 */            else {                istart = 1;                n = 59;                m = 34950;            }        }        /* Range 3-4 */        else {            /* Range 3 */            if (isample < 24) {                istart = 5;                n = 1457;                m = 7168;            }            /* Range 4 */            else {                istart = 24;                n = 2819;                m = 1464;            }        }    }    /* Range 5-8 */    else {        /* Range 5-6 */        if (isample < 2918) {            /* Range 5 */            if (isample < 592) {                istart = 119;                n = 4210;                m = 295;            }            /* Range 6 */            else {                istart = 592;                n = 5605;                m = 60;            }        }        /* Range 7-8 */        else {            /* Range 7 */            if (isample < 15352) {                istart = 2918;                n = 7001;                m = 12;            }            /* Range 8 */            else {                istart = 15352;                n = 8439;                m = 3;            }        }    }       return n + (m * (long)(isample - istart)) / 100L;}/** * 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  * 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. * @param int max - The maximum of the value range that is searched. * @param int db  - The value in dBfs * (-100) for which the according *                  minimal peak sample is searched. * @return int - A linear volume value with 0 <= value < MAX_PEAK */static int db_to_sample_bin_search(int min, int max, int db){    int test = min + (max - min) / 2;    if (min < max) {        if (calc_db(test) < db) {            test = db_to_sample_bin_search(test, max, db);        } else {            if (calc_db(test-1) > db) {                test = db_to_sample_bin_search(min, test, db);            }        }    }    return test;}/** * Converts a value representing dBfs to a linear * scaled volume info as it is used by the MAS. * An incredibly inefficiant function which is * the vague inverse of calc_db. This really  * should be replaced by something better soon. *  * @param int db - A dBfs * 100 value with  *                 -9000 < value <= 0 * @return int - The return value is in the range of *               0 <= return value < MAX_PEAK */static int db_to_sample(int db) {    int retval = 0;    /* what is the maximum pseudo db value */    int max_peak_db = calc_db(MAX_PEAK - 1);    /* range check: db value to big */    if (max_peak_db + db < 0) {        retval = 0;    }         /* range check: db value too small */    else if (max_peak_db + db >= max_peak_db) {        retval = MAX_PEAK -1;    }         /* value in range: find the matching linear value */    else {        retval = db_to_sample_bin_search(0, MAX_PEAK, max_peak_db + db);        /* as this is a dirty function anyway, we want to adjust the            full scale hit manually to avoid users complaining that when           they adjust maximum for 0 dBfs and display it in percent it            shows 99%. That is due to precision loss and this is the            optical fix */    }    return retval;}/** * Set the min value for restriction of the value range. * @param int newmin - depending wether dBfs is used * newmin is a value in dBfs * 100 or in linear percent values. * for dBfs: -9000 < newmin <= 0 * for linear: 0 <= newmin <= 100 */void peak_meter_set_min(int newmin) {    if (peak_meter_use_dbfs) {        peak_meter_range_min = db_to_sample(newmin);    } else {        if (newmin < peak_meter_range_max) {            peak_meter_range_min = newmin * MAX_PEAK / 100;        }    }    peak_meter_range = peak_meter_range_max - peak_meter_range_min;    db_min = calc_db(peak_meter_range_min);    db_range = db_max - db_min;    db_scale_valid = false;}/** * Returns the minimum value of the range the meter  * displays. If the scale is set to dBfs it returns * dBfs values * 100 or linear percent values. * @return: using dBfs : -9000 < value <= 0 *          using linear scale: 0 <= value <= 100 */int peak_meter_get_min(void) {    int retval = 0;    if (peak_meter_use_dbfs) {        retval = calc_db(peak_meter_range_min) - calc_db(MAX_PEAK - 1);    } else {        retval = peak_meter_range_min * 100 / MAX_PEAK;    }    return retval;}/** * Set the max value for restriction of the value range. * @param int newmax - depending wether dBfs is used * newmax is a value in dBfs * 100 or in linear percent values. * for dBfs: -9000 < newmax <= 0 * for linear: 0 <= newmax <= 100 */void peak_meter_set_max(int newmax) {    if (peak_meter_use_dbfs) {        peak_meter_range_max = db_to_sample(newmax);    } else {        if (newmax > peak_meter_range_min) {            peak_meter_range_max = newmax * MAX_PEAK / 100;        }    }    peak_meter_range = peak_meter_range_max - peak_meter_range_min;    db_max = calc_db(peak_meter_range_max);    db_range = db_max - db_min;    db_scale_valid = false;}/** * Returns the minimum value of the range the meter  * displays. If the scale is set to dBfs it returns * dBfs values * 100 or linear percent values * @return: using dBfs : -9000 < value <= 0 *          using linear scale: 0 <= value <= 100 */int peak_meter_get_max(void) {    int retval = 0;    if (peak_meter_use_dbfs) {        retval = calc_db(peak_meter_range_max) - calc_db(MAX_PEAK - 1);    } else {        retval = peak_meter_range_max * 100 / MAX_PEAK;    }    return retval;}/** * Returns 1 if the meter currently is * displaying dBfs values, 0 if the meter * displays percent values. * @return int - returns 0 or 1. */int peak_meter_get_use_dbfs(void) {    return peak_meter_use_dbfs ? 1 : 0;}/** * Specifies wether the values displayed are scaled * as dBfs or as linear percent values. * @param int - Set to 0 for linear percent scale. Any other value *              switches on dBfs. */void peak_meter_set_use_dbfs(int use){    peak_meter_use_dbfs = ((use & 1) == 1);    db_scale_valid = false;}/** * Initialize the range of the meter. Only values * that are in the range of [range_min ... range_max] * are displayed. * @param bool dbfs - set to true for dBfs,  *                    set to false for linear scaling in percent  * @param int range_min - Specifies the lower value of the range.  *                        Pass a value dBfs * 100 when dbfs is set to true. *                        Pass a percent value when dbfs is set to false.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -