ADCに入力する電圧
アンプをDC(Direct - Coupled)構成で設計した。
その構成では入力オーディオ電圧は正負に振れるので,
入力電圧を絶対値回路に通してAVR内蔵10bit-ADCに入力します。
この回路の最大入力電圧 Vm の実効値は VADC が3.3Vなので
$$
V_m = \frac{3.3}{\sqrt 2} = 2.3 Vrms
$$
となる。
入力のラインレベルは民生用音響機器では-10dBVなので
$$
linelevel = 1.0 \times 10^{\frac{-10.0}{20.0}} = 0.316Vrms
$$
余裕があるようだ。
ADCの出力値とADCの入力電圧との関係
AVRのADCに入力される電圧は入力回路から
$$
V_{ADC} = | Vin |
$$
ADCの出力値1bit当たりの電圧は
AREF が 3.3V
ADCの解像度 10bit = 210 = 1024
のときに
$$
V_{step} = \frac{3.3}{1024} = 0.0012695 V \approx 1.27 mV
$$
となる。
入力電圧の実効値を得る処理
周期的に変化する交流入力電圧の実効値を得る処理です。
二乗平均平方根 を交流入力電圧にしたい。
ピークレベルを得る処理
雰囲気だけ演出できたらいいので,レベル値の最大値を更新しながら周期的に減らすだけにしておいた。
ターゲットとする表示画面
オーディオレベルの表示イメージ
フルスケールで30目盛りを表示します.
0vuで28目盛りを表示し,後ろにピークレベル指針を表示します.
-48vu未満でピークレベル指針のみを表示します.
目盛りとADC値の対応
30個ある目盛りに対応するVU値表から10bit-ADCサンプル値表をGNU Octaveに計算させます.
単位の変換
VUメーター - Wikipedia
デシベル - Wikipedia
これを参考に
多分こんな感じ
GNU Octave用オーディオレベルメーター計算スクリプト
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
| % オーディオレベルメータの値を計算する
% 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");
|
レベルメーター表示関数
イメージ通りに表示する関数です。
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
| //
//オーディオレベルメータ表示
//
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;
}
}
}
}
|
現在の入力とボリュームレベル表示
1行目にこのように32段階電子ボリュームの現在指針表示を行ないます,2行目に現在の入力とボリューム数値表示を行ないます
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| //
//現在のボリュームをメーターの形で表現
//
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