オーディオレベルとかをディスプレイに表示する

ADCに入力する電圧

アンプをDC(Direct – Coupled)構成で設計したので,入力オーディオ電圧は正負に振れるので,入力を絶対値回路に通してAVR内蔵10bit-ADCに入力します。
アナログ回路図の右上が絶対値回路

この回路の最大入力電圧Vmの実効値はVADCが3.3Vなので

ライン (音響機器) – Wikipediaによると,ラインレベルは民生用音響機器では-10dBVとのことで

になる.
これは特に基準が無いようなので,だいたい2.0Vrmsを取り込めたらいいだろうと思う.

ADCが出力する値

ADC入力電圧は絶対値回路の出力電圧

ADCの出力値1bit当たりの電圧

ADCの出力値とADCの入力電圧との関係

入力電圧の実効値を得る処理

周期的に変化する交流入力電圧の実効値を得る処理です.
二乗平均平方根 – Wikipedia処理を交流入力電圧にしたい.
この中の平均は単純移動平均 – Wikipediaで行ないます.

IRamp-audio-level-flow

ピークレベルを得る処理

雰囲気だけ演出できたらいいので,レベル値の最大値を更新しながら周期的に減らすだけにしておいた。

ターゲットとする表示画面

表示幅(文字数)
16文字
表示行数
2行

オーディオレベルの表示イメージ

フルスケール表示中オーディオレベルメータ
フルスケール表示中オーディオレベルメータ

フルスケールで30目盛りを表示します.

0vu表示中オーディオレベルメータ
0vu表示中オーディオレベルメータ

0vuで28目盛りを表示し,後ろにピークレベル指針を表示します.

-48vu未満表示中オーディオレベルメータ
-48vu未満表示中オーディオレベルメータ

-48vu未満でピークレベル指針のみを表示します.

目盛りと10bit-ADCサンプル値の対応

30個ある目盛りに対応するVU値表から10bit-ADCサンプル値表をGNU Octaveに計算させます.

単位の変換

VUメーター – Wikipedia
デシベル – Wikipedia
これを参考に

多分こんな感じ

GNU Octave用オーディオレベルメーター計算スクリプト

% オーディオレベルメータの値を計算する
% http://ak1211.com
% Copyright (c) 2015 Akihiro Yamamoto
%
%
% This software is released under the MIT License.
% http://opensource.org/licenses/mit-license.php
%

% VU値の表
%               1     2     3     4     5     6     7     8     9    10    11    12    13    14    15    16    17    18    19    20    21    22    23    24    25    26    27    28    29    30
vu_table = [ -48.0 -44.0 -40.0 -36.0 -32.5 -29.0 -25.5 -22.0 -20.0 -18.0 -16.0 -14.0 -13.0 -12.0 -11.0 -10.0 -9.00 -8.00 -7.00 -6.00 -5.00 -4.00 -3.00 -2.00 -1.50 -1.00 -0.50 0.000 +1.50 +3.00 ];

%
% volts[rms]の値に対応したdBuを返す
%
function dBu = dBu_of_volts (vRMS)
    dBu = 20.0 * log10 (vRMS / 0.775);
endfunction

%
% volts[rms]の値に対応したvuを返す
%
function vu = vu_of_volts (vRMS)
    vu = -4 + dBu_of_volts (vRMS);
endfunction

%
% dBuの値に対応したvolts[rms]を返す
%
function volts = volts_of_dBu (dBu)
    volts = 0.775 * 10 .** (dBu / 20.0);
endfunction


%
% VUの値に対応したvolts[rms]を返す
%
function volts = volts_of_vu (vu)
    volts = volts_of_dBu(vu + 4);
endfunction

%
% volts[rms]の値に対応したサンプル値を返す
%
function value = sample_value_of_volts (volts)
    adc_volts   = 3.3;
    sample_bits = 10;
    %
    resolution  = adc_volts / (2^sample_bits);
    value = floor (volts / resolution);
endfunction

%
% 計算結果を出力
%
values = sample_value_of_volts (volts_of_vu (vu_table));

printf ("static const uint16_t level_meter_tbl[LEVEL_METER_TABLE_SIZE] = {n");
printf ("t//最大値 +3vun");
printf("t");
printf ("%3d, ", values(1:15));
printf("n");
printf("t");
printf ("%3d, ", values(16:30));
printf("n");
printf ("};n");

レベルメーター表示関数

イメージ通りに表示する関数です。

//
//オーディオレベルメータ表示
//
static void render_audio_level_meter( audio_level_t* audiolevel )
{
    const char msg[] = "LR";

    for (uint8_t linenum=0 ; linenum 0) {
            //レベル位置のレベルメーターキャラクタ書き込み
            idx = 1 + (level >> 1); //0の位置はLまたはR文字がいるため1から開始
            if ((level & 1) == 0) {
                //2の倍数なら左右表示
                nextDisplayBuffer[linenum].line[idx] = CHAR_LEFT_RIGHT_BAR;
                idx--;
            } else {
                //2の倍数でないなら左表示
                nextDisplayBuffer[linenum].line[idx] = CHAR_LEFT_BAR;
                idx--;
            }
            //レベル位置のレベルメーターキャラクタより下は左右表示
            for (; idx>=1 ; idx--) {
                //左右表示
                nextDisplayBuffer[linenum].line[idx] = CHAR_LEFT_RIGHT_BAR;
            }
        }
        //ピークレベル位置キャラクタ書き込み
        idx = 1 + (peak >> 1);  //0の位置はLまたはR文字がいるために1から開始
        if (peak > 0) {
            idx = idx + 1;      //ピークキャラクタはレベルメーターの右側
        }
        if (idx >= DISPLAY_WIDTH) {
            //over dB
            nextDisplayBuffer[linenum].line[DISPLAY_WIDTH-1] = CHAR_PEAK_LEVEL_OVER_DB;
        } else {
            if ((peak & 1) == 0) {
                //2の倍数なら左表示
                nextDisplayBuffer[linenum].line[idx] = CHAR_LEFT_PEAK_LEVEL;
            } else {
                //2の倍数でないなら右表示
                nextDisplayBuffer[linenum].line[idx] = CHAR_RIGHT_PEAK_LEVEL;
            }
        }
    }
}

現在の入力とボリュームレベル表示

指針によって32段階電子ボリュームのボリューム16表示中
指針によって32段階電子ボリュームのボリューム16表示中

1行目にこのように32段階電子ボリュームの現在指針表示を行ないます,2行目に現在の入力とボリューム数値表示を行ないます

//
//現在のボリュームをメーターの形で表現
//
static void render_volume_meter( display_line_buf_t line, elevol_t volume )
{
    volume = elevol_validate_volume( volume );
    //バックグラウンド
    memset (line, CHAR_VOL_BACKGROUND, DISPLAY_WIDTH );
    //指針を書き込む
    uint8_t idx = volume >> 1;
    line[idx] = (volume & 1) ? CHAR_VOL_RIGHT_BAR : CHAR_VOL_LEFT_BAR;
}

//
//現在の入力とボリューム
//
static void render_input_source_and_volume( display_line_buf_t line, uint8_t src_num,  elevol_t volume )
{
    char buf[DISPLAY_WIDTH + 1];
    snprintf_P (buf, sizeof(buf), PSTR("SOURCE:%-3dVOL:%2d"),  src_num, volume);
    strncpy (line, buf, DISPLAY_WIDTH );
}

ディスプレイ表示ソースコード

オーディオレベル取り込み

audio_level_meter.h
audio_level_meter.c

ディスプレイ表示

display.h
display.c

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください