2016-07-03 2 views
0

私は現在raspberry pi 3を使用してをicecast streamにリダイレクトすることができます。現在、Raspbian Jessie Liteのpipe arecord from USB audio hw input to avconv(ffmpeg相当)の小さなテストでうまく動作します。ALSA arecord関数を変更して、オーディオレベルをRaspberry Pi 3 RGB LEDに出力する

Arecordには、冗長設定を使用するとオーディオレベル用のテキストvuメーターが組み込まれています。

私はコードが付属の機能に位置していると思います。それはラズベリーパイ3 RGB LEDに出力するように、この機能を書き換えることが可能だ場合、私は思ったんだけど - 関数のピーク変数を使用して - 何とか音量レベルに基づいて、赤/黄/緑を送信しますか?

私は機能全体と印刷機能を含んでいます。できる場合は、コードがおそらく置き換えられる可能性がありますprint_vu_meter(perc, maxperc);

パイプの処理中にRaspi 3に処理させるためにarecordを変更することはできますか?別のスレッドを使用する方法はありますか?ここに私のリーグのうち

道 - ちょうど私の頭のうちのアイデアを得るためにか、それが可能だと言ってスタートを探している、またはいくつかのアイデア。

ピークハンドラ

static void compute_max_peak(u_char *data, size_t count) 
{ 
    signed int val, max, perc[2], max_peak[2]; 
    static int run = 0; 
    size_t ocount = count; 
    int format_little_endian = snd_pcm_format_little_endian(hwparams.format); 
    int ichans, c; 

    if (vumeter == VUMETER_STEREO) 
     ichans = 2; 
    else 
     ichans = 1; 

    memset(max_peak, 0, sizeof(max_peak)); 
    switch (bits_per_sample) { 
    case 8: { 
     signed char *valp = (signed char *)data; 
     signed char mask = snd_pcm_format_silence(hwparams.format); 
     c = 0; 
     while (count-- > 0) { 
      val = *valp++^mask; 
      val = abs(val); 
      if (max_peak[c] < val) 
       max_peak[c] = val; 
      if (vumeter == VUMETER_STEREO) 
       c = !c; 
     } 
     break; 
    } 
    case 16: { 
     signed short *valp = (signed short *)data; 
     signed short mask = snd_pcm_format_silence_16(hwparams.format); 
     signed short sval; 

     count /= 2; 
     c = 0; 
     while (count-- > 0) { 
      if (format_little_endian) 
       sval = __le16_to_cpu(*valp); 
      else 
       sval = __be16_to_cpu(*valp); 
      sval = abs(sval)^mask; 
      if (max_peak[c] < sval) 
       max_peak[c] = sval; 
      valp++; 
      if (vumeter == VUMETER_STEREO) 
       c = !c; 
     } 
     break; 
    } 
    case 24: { 
     unsigned char *valp = data; 
     signed int mask = snd_pcm_format_silence_32(hwparams.format); 

     count /= 3; 
     c = 0; 
     while (count-- > 0) { 
      if (format_little_endian) { 
       val = valp[0] | (valp[1]<<8) | (valp[2]<<16); 
      } else { 
       val = (valp[0]<<16) | (valp[1]<<8) | valp[2]; 
      } 
      /* Correct signed bit in 32-bit value */ 
      if (val & (1<<(bits_per_sample-1))) { 
       val |= 0xff<<24; /* Negate upper bits too */ 
      } 
      val = abs(val)^mask; 
      if (max_peak[c] < val) 
       max_peak[c] = val; 
      valp += 3; 
      if (vumeter == VUMETER_STEREO) 
       c = !c; 
     } 
     break; 
    } 
    case 32: { 
     signed int *valp = (signed int *)data; 
     signed int mask = snd_pcm_format_silence_32(hwparams.format); 

     count /= 4; 
     c = 0; 
     while (count-- > 0) { 
      if (format_little_endian) 
       val = __le32_to_cpu(*valp); 
      else 
       val = __be32_to_cpu(*valp); 
      val = abs(val)^mask; 
      if (max_peak[c] < val) 
       max_peak[c] = val; 
      valp++; 
      if (vumeter == VUMETER_STEREO) 
       c = !c; 
     } 
     break; 
    } 
    default: 
     if (run == 0) { 
      fprintf(stderr, _("Unsupported bit size %d.\n"), (int)bits_per_sample); 
      run = 1; 
     } 
     return; 
    } 
    max = 1 << (bits_per_sample-1); 
    if (max <= 0) 
     max = 0x7fffffff; 

    for (c = 0; c < ichans; c++) { 
     if (bits_per_sample > 16) 
      perc[c] = max_peak[c]/(max/100); 
     else 
      perc[c] = max_peak[c] * 100/max; 
    } 

    if (interleaved && verbose <= 2) { 
     static int maxperc[2]; 
     static time_t t=0; 
     const time_t tt=time(NULL); 
     if(tt>t) { 
      t=tt; 
      maxperc[0] = 0; 
      maxperc[1] = 0; 
     } 
     for (c = 0; c < ichans; c++) 
      if (perc[c] > maxperc[c]) 
       maxperc[c] = perc[c]; 

     putchar('\r'); 
     print_vu_meter(perc, maxperc); 
     fflush(stdout); 
    } 
    else if(verbose==3) { 
     printf(_("Max peak (%li samples): 0x%08x "), (long)ocount, max_peak[0]); 
     for (val = 0; val < 20; val++) 
      if (val <= perc[0]/5) 
       putchar('#'); 
      else 
       putchar(' '); 
     printf(" %i%%\n", perc[0]); 
     fflush(stdout); 
    } 
} 

print_vu_meter

static void print_vu_meter_mono(int perc, int maxperc) 
{ 
    const int bar_length = 50; 
    char line[80]; 
    int val; 

    for (val = 0; val <= perc * bar_length/100 && val < bar_length; val++) 
     line[val] = '#'; 
    for (; val <= maxperc * bar_length/100 && val < bar_length; val++) 
     line[val] = ' '; 
    line[val] = '+'; 
    for (++val; val <= bar_length; val++) 
     line[val] = ' '; 
    if (maxperc > 99) 
     sprintf(line + val, "| MAX"); 
    else 
     sprintf(line + val, "| %02i%%", maxperc); 
    fputs(line, stdout); 
    if (perc > 100) 
     printf(_(" !clip ")); 
} 
+0

質問:それは可能ですか?回答:はい、それは可能です。 – immibis

答えて

0

この中に多くの関心があるかのように見えるが、私は私がしようと思いましたしません私の投稿nswer将来のために、ケースには他の誰がこのタイプのプロジェクトを掘り下げしようとします。

調査結果:

  • arecordがに静的揮発int型の変数を追加することによって、あなたがCコード
  • にスレッドを追加するには、信じられないほどのwiringPi Cライブラリを使用することができますはaplay
  • の単なるリンクコピーですコード - スレッドとメインプログラムの間で共有されるようになります
  • 変数をperc値に設定すると、スレッドプログラムで直ちに更新されます。

私はこのコードを使用してLEDを6レベルのオーディオレベルメーターをシミュレートすることができた:

Iが表示されないというLEDレベルを切り替えるにはブレッドボード上のボタンを使用します。

setAudioLEDSスレッド機能:

PI_THREAD (setAudioLEDs) 
{ 
    // Only update LEDS if button is pressed 
    // Gets Audio Level from global var: globalAudioLevel 

    // Wiring Pi Constants for led and button 
    // Pin number declarations. We're using the Broadcom chip pin numbers. 

#define CYCLE_UPDATE '0' 
#define CYCLE_STEADY '1' 

    int last_button; 
    int last_cycle; 
    int this_cycle; 

    // Button is released if this returns 1 
    // HIGH or LOW (1 or 0) 
    last_button = digitalRead(butPin); 
    last_cycle = CYCLE_STEADY; 
    this_cycle = last_cycle; 

    while (1) 
    { 
     if (digitalRead(butPin) != last_button) { 
      if (last_cycle == CYCLE_UPDATE) 
       this_cycle = CYCLE_STEADY; 
      else 
       this_cycle = CYCLE_UPDATE; 
      last_cycle = this_cycle; 
     } 

     switch (this_cycle) { 

     case CYCLE_UPDATE: 

      // Set LEDS based on audio level 
      if (globalAudioLevel > 20) 
       digitalWrite(led1, HIGH); // Turn LED ON 
      else 
       digitalWrite(led1, LOW); // Turn LED OFF 

      if (globalAudioLevel > 40) 
       digitalWrite(led2, HIGH); // Turn LED ON 
      else 
       digitalWrite(led2, LOW); // Turn LED OFF 

      if (globalAudioLevel > 60) 
       digitalWrite(led3, HIGH); // Turn LED ON 
      else 
       digitalWrite(led3, LOW); // Turn LED OFF 

      if (globalAudioLevel > 70) 
       digitalWrite(led4, HIGH); // Turn LED ON 
      else 
       digitalWrite(led4, LOW); // Turn LED OFF 

      if (globalAudioLevel > 80) 
       digitalWrite(led5, HIGH); // Turn LED ON 
      else 
       digitalWrite(led5, LOW); // Turn LED OFF 

      if (globalAudioLevel > 90) 
       digitalWrite(led6, HIGH); // Turn LED ON 
      else 
       digitalWrite(led6, LOW); // Turn LED OFF 

      break; 

     default: 
      /* Button hasn't been pressed */ 
      digitalWrite(led1, LOW); // Turn LED OFF 
      digitalWrite(led2, LOW); // Turn LED OFF 
      digitalWrite(led3, LOW); // Turn LED OFF 
      digitalWrite(led4, LOW); // Turn LED OFF 
      digitalWrite(led5, LOW); // Turn LED OFF 
      digitalWrite(led6, LOW); // Turn LED OFF 
     } 
    } 
} 
関連する問題