チラシのうら

レゴとか、工作とか。

8pinoで圧電スピーカーを鳴らす その4

もう1つ輪唱

前回の投稿 で、輪唱の基礎は構築したので、応用は大変容易です。

目標の1つだった、「静かな湖畔」の輪唱にもチャレンジしてみましょう。

といってもやることは、ネットに落ちていた楽譜をデータ列に起こすだけです。 約30分で完了しました。

では、どうぞ

こちらも、輪唱パート毎にLEDを分けて光らせています。

基礎を1つ作ると、その後は超簡単ですね!

コードはこちら

#include <Adafruit_NeoPixel.h>
#ifdef __AVR_ATtiny85__ // Trinket, Gemma, etc.
 #include <avr/power.h>
#endif

#define NEOPIXEL_IN_PIN 0
#define NUM_OF_PIXELS 16
#define NEOPIXEL_BRIGHTNESS 30
Adafruit_NeoPixel pixels = Adafruit_NeoPixel( NUM_OF_PIXELS, NEOPIXEL_IN_PIN );

// Definitions
#define _8PINO_TONE_START ( 0x00 )
#define _8PINO_TONE_STOP  ( 0x01 )

#define _8PINO_TONE_NOT_USED ( 0 )

#define _8PINO_TONE_SO_2 ( 158 )
#define _8PINO_TONE_RA_2 ( 141 )
#define _8PINO_TONE_SI_2 ( 126 )
#define _8PINO_TONE_DO_3 ( 118 )
#define _8PINO_TONE_RE_3 ( 106 )
#define _8PINO_TONE_MI_3 (  94 )
#define _8PINO_TONE_FA_3 (  89 )
#define _8PINO_TONE_SO_3 (  79 )
#define _8PINO_TONE_RA_3 (  70 )
#define _8PINO_TONE_SI_3 (  62 )
#define _8PINO_TONE_DO_4 (  59 )

// Global variables
#define _8PINO_TONE_SPEAKER_PIN_1 ( 1 )
#define _8PINO_TONE_SPEAKER_PIN_2 ( 4 )

#define SIZE_OF_TONE_ARRAY ( 160 )
PROGMEM prog_uint16_t noteArray[] =
{
  
  // Wait...
  _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED,
  _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED,
  _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED,
  _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED,
  _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED,
  _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED,
  _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED,
  _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED,
  
  // Shi-Zu-Ka-Na-Ko-Han-No
  _8PINO_TONE_DO_3, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, _8PINO_TONE_DO_3, 
  _8PINO_TONE_DO_3, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, _8PINO_TONE_RE_3, 
  _8PINO_TONE_MI_3, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, _8PINO_TONE_MI_3, 
  _8PINO_TONE_MI_3, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, _8PINO_TONE_MI_3, 
  
  // Mo-Ri-No-Ka-Ge-Ka-Ra
  _8PINO_TONE_RE_3, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, _8PINO_TONE_DO_3, 
  _8PINO_TONE_RE_3, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, _8PINO_TONE_MI_3, 
  _8PINO_TONE_DO_3, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, _8PINO_TONE_DO_3, 
  _8PINO_TONE_SO_2, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, 
  
  // Mou-Oki-Tya-I-Ka-Ga-To-Kakko-Ga-Na-Ku Ka-
  _8PINO_TONE_MI_3, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, 
  _8PINO_TONE_MI_3, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, _8PINO_TONE_FA_3, 
  _8PINO_TONE_SO_3, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, _8PINO_TONE_SO_3, 
  _8PINO_TONE_SO_3, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, _8PINO_TONE_SO_3, 
  _8PINO_TONE_FA_3, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, _8PINO_TONE_MI_3, 
  _8PINO_TONE_FA_3, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, _8PINO_TONE_SO_3, 
  _8PINO_TONE_MI_3, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, 
  _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, _8PINO_TONE_SO_3, 
  
  //Kko Ka-Kko Ka-Kko Ka-Kko Ka-Kko
  _8PINO_TONE_MI_3, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, 
  _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_SO_3, 
  _8PINO_TONE_MI_3, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, 
  _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_SO_3, 
  _8PINO_TONE_MI_3, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, _8PINO_TONE_SO_3, 
  _8PINO_TONE_MI_3, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, _8PINO_TONE_SO_3, 
  _8PINO_TONE_MI_3, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP, 
  _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED,
  
  // Wait...
  _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED,
  _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED,
  _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED,
  _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED,
  _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED,
  _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED,
  _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED,
  _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED, _8PINO_TONE_NOT_USED,
  
};

void setup(){
  
  // Initialize PIN mode.
  pinMode( _8PINO_TONE_SPEAKER_PIN_1, OUTPUT );
  pinMode( _8PINO_TONE_SPEAKER_PIN_2, OUTPUT );
  
  // Configure Registers for PWM of PB1(PIN No.1)
  //  1. Waveform Generation Mode -> Fast PWM
  //  2. Clock Select -> 8MHz/256 = 32KHz.
  //  3. Compare Match Output B Mode
  //    -> Clear OC0A/OC0B on Compare Match, 
  //        set OC0A/OC0B at BOTTOM
  TCCR0A = _BV (COM0B1) | _BV (WGM01) | _BV (WGM00);
  TCCR0B = _BV (WGM02) | _BV (CS02);
  
  // Configure Registers for PWM of PB4(PIN No.4)
  //  1. Comparator A Mode -> Set the OC1A output line.
  //  2. Time/Counter1 Prescale Select -> 8MHz/256 = 32KHz.
  //  3. Enable Pulse Width Modulator B.
  //  4. Comparator B Mode -> Set the OC1B output line
  TCCR1 = _BV (COM1A1) | _BV (COM1A0) | 
             _BV (CS13) | _BV (CS10);
  GTCCR = _BV (PWM1B) | _BV (COM1B1) | _BV (COM1B0);
  
  // NeoPixel LED
  pinMode( NEOPIXEL_IN_PIN, OUTPUT );
  
#ifdef __AVR_ATtiny85__ // Trinket, Gemma, etc.
  if( F_CPU == 16000000 ) clock_prescale_set( clock_div_1 );
#endif
  pixels.begin();
  pixels.setBrightness( NEOPIXEL_BRIGHTNESS );
  pixels.show(); // Initialize all pixels to "off"
  
}

void loop(){
  
  for( int count = 32; count < SIZE_OF_TONE_ARRAY; count++ )
  {
    if( pgm_read_word( &noteArray[count] ) == _8PINO_TONE_NOT_USED ){
      // Do Nothing.
    }else if( pgm_read_word( &noteArray[count] ) == _8PINO_TONE_STOP ){
      _8pinoTone( _8PINO_TONE_SPEAKER_PIN_1, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP );
      setNeopixelColor( _8PINO_TONE_SPEAKER_PIN_1, _8PINO_TONE_STOP );
    }else{
      _8pinoTone( _8PINO_TONE_SPEAKER_PIN_1, pgm_read_word( &noteArray[count] ), _8PINO_TONE_START );
      setNeopixelColor( _8PINO_TONE_SPEAKER_PIN_1, pgm_read_word( &noteArray[count] ) );
    }
    
    if( pgm_read_word( &noteArray[count-32] ) == _8PINO_TONE_NOT_USED ){
      // Do Nothing.
    }else if( pgm_read_word( &noteArray[count-32] ) == _8PINO_TONE_STOP ){
      _8pinoTone( _8PINO_TONE_SPEAKER_PIN_2, _8PINO_TONE_NOT_USED, _8PINO_TONE_STOP );
      setNeopixelColor( _8PINO_TONE_SPEAKER_PIN_2, _8PINO_TONE_STOP );
    }else{
      _8pinoTone( _8PINO_TONE_SPEAKER_PIN_2, pgm_read_word( &noteArray[count-32] ), _8PINO_TONE_START );
      setNeopixelColor( _8PINO_TONE_SPEAKER_PIN_2, pgm_read_word( &noteArray[count-32] ) );
    }
    
    pixels.show();
    delay( 8000 / OCR0A );
  }
  
}

void _8pinoTone( int pin_speaker, uint8_t freq, uint8_t startstop ){
  if( startstop == _8PINO_TONE_START ){
    pinMode( pin_speaker, OUTPUT );
    if( pin_speaker == _8PINO_TONE_SPEAKER_PIN_1 ){
      OCR0A = freq;
      OCR0B = OCR0A - 1;
    }else{
      OCR1C = freq;
      OCR1B = OCR1C - 1;
    }
  }else{
     pinMode( pin_speaker, INPUT );
  }
}

void setNeopixelColor( int speaker_id, int tone ){
  
  uint8_t led_index = 0;
  int i = 0;
  
  if( speaker_id == _8PINO_TONE_SPEAKER_PIN_1 ){
    switch( tone ){
      case _8PINO_TONE_SO_2:
        led_index = 12;
        break;
      case _8PINO_TONE_DO_3:
        led_index = 13;
        break;
      case _8PINO_TONE_RE_3:
        led_index = 14;
        break;
      case _8PINO_TONE_MI_3:
        led_index = 15;
        break;
      case _8PINO_TONE_FA_3:
        led_index = 0;
        break;
      case _8PINO_TONE_SO_3:
        led_index = 1;
        break;
    }
    
    if( tone == _8PINO_TONE_STOP ){
      for( i = 0; i < 2; i++ ){
        pixels.setPixelColor( i, 0, 0, 0 );
      }
      for( i = 12; i < 16; i++ ){
        pixels.setPixelColor( i, 0, 0, 0 );
      }
    }else{
      for( i = 0; i < 2; i++ ){
        pixels.setPixelColor( i, 0, 0, 0 );
      }
      for( i = 12; i < 16; i++ ){
        pixels.setPixelColor( i, 0, 0, 0 );
      }
      if( led_index < 2 ){
        for( i = 0; i < led_index + 1; i++ ){
          pixels.setPixelColor( i, 255, 0, 0 );
        }
        for( i = 12; i < 16; i++ ){
          pixels.setPixelColor( i, 255, 0, 0 );
        }
        
      }else{
        for( i = 12; i < led_index + 1; i++ ){
          pixels.setPixelColor( i, 255, 0, 0 );
        }
      }
    }
    
  }else{
    switch( tone ){
      case _8PINO_TONE_SO_2:
        led_index = 11;
        break;
      case _8PINO_TONE_DO_3:
        led_index = 10;
        break;
      case _8PINO_TONE_RE_3:
        led_index = 9;
        break;
      case _8PINO_TONE_MI_3:
        led_index = 8;
        break;
      case _8PINO_TONE_FA_3:
        led_index = 7;
        break;
      case _8PINO_TONE_SO_3:
        led_index = 6;
        break;
    }
    
    if( tone == _8PINO_TONE_STOP ){
      for( i = 6; i < 12; i++ ){
        pixels.setPixelColor( i, 0, 0, 0 );
      }
    }else{
      for( i = 6; i < 12; i++ ){
        pixels.setPixelColor( i, 0, 0, 0 );
      }
      for( i = led_index; i < 12; i++ ){
        pixels.setPixelColor( i, 0, 255, 0);
      }
    }
    
  }
  
}

まだまだ

圧電スピーカーハックは続きます。