前回はラーメンのチャルメラを流すコードだったけど、今回はもう少し長めのメロディーを作ってみた。
作ったもの
作ったメロディーはシューティングゲーム、東方風神録の3面テーマ「神々が恋した幻想郷」。
折角なのでYouTubeにUploadした。(音が鳴るので注意)
創業から240年の 小田原かまぼこの元祖 鱗吉 うろこきぐちの生すり身で造った本物のかまぼこ さつま揚げ ギフト お土産 敬老の日 ギフト かまぼこ 「小田原江戸物語」送料無料 小田原かまぼこ発祥の店うろこき 蒲鉾 贈り物 内祝い お土産 老舗 神奈川 小田原 箱根 ご当地 グルメ 詰め合わせ お取り寄せ 大特価 今だけ 贅沢グルメ 訳あり 母の日 父の日 宅飲み お中元
知らない方向けに原作もご紹介。※私のプレイじゃないです。
youtu.be
配線は前回のチャルメラと同じ。
コード
チャルメラのときはドレミの周波数を直接指定していたけど、今回は関数にして簡単に呼び出せるようにしつつ、中身も音階ごとの周波数を12平均律という方法で計算で求めるということをやってみた。
ラの音が440Hzと定められているので、そこに2の12乗根をn乗するとn音階あがり、-n乗するとn音階下がる。
これをさらにm倍すると、mオクターブ上がり、mで割るとmオクターブ下がるという仕組み。
ド♯・レ♯とかは今回定義しなかったのでドレミファソラシの7音のみ定義。
const double FREQUENCY_PITCH = 1.0594630943593; const double RA_FREQUENCY = 440; const int DEFAULT_WIDTH = 200; const int SOUND_PIN = 12; void Do(float octave = 1, int sound_time = 1, int wait = 0){ tone(SOUND_PIN, pow(FREQUENCY_PITCH, -9) * RA_FREQUENCY * octave, DEFAULT_WIDTH * sound_time); delay(DEFAULT_WIDTH * sound_time+wait); } void Re(float octave = 1, int sound_time = 1, int wait = 0){ tone(SOUND_PIN, pow(FREQUENCY_PITCH, -7) * RA_FREQUENCY * octave, DEFAULT_WIDTH * sound_time); delay(DEFAULT_WIDTH * sound_time+wait); } void Mi(float octave = 1, int sound_time = 1, int wait = 0){ tone(SOUND_PIN, pow(FREQUENCY_PITCH, -5) * RA_FREQUENCY * octave, DEFAULT_WIDTH * sound_time); delay(DEFAULT_WIDTH * sound_time+wait); } void Fa(float octave = 1, int sound_time = 1, int wait = 0){ tone(SOUND_PIN, pow(FREQUENCY_PITCH, -4) * RA_FREQUENCY * octave, DEFAULT_WIDTH * sound_time); delay(DEFAULT_WIDTH * sound_time+wait); } void So(float octave = 1, int sound_time = 1, int wait = 0){ tone(SOUND_PIN, pow(FREQUENCY_PITCH, -2) * RA_FREQUENCY * octave, DEFAULT_WIDTH * sound_time); delay(DEFAULT_WIDTH * sound_time+wait); } void Ra(float octave = 1, int sound_time = 1, int wait = 0){ tone(SOUND_PIN, pow(FREQUENCY_PITCH, 0) * RA_FREQUENCY * octave, DEFAULT_WIDTH * sound_time); delay(DEFAULT_WIDTH * sound_time+wait); } void Si(float octave = 1, int sound_time = 1, int wait = 0){ tone(SOUND_PIN, pow(FREQUENCY_PITCH, 2) * RA_FREQUENCY * octave, DEFAULT_WIDTH * sound_time); delay(DEFAULT_WIDTH * sound_time+wait); } void setup() { // put your setup code here, to run once: pinMode(2,INPUT_PULLUP); attachInterrupt(0,ramen_on,FALLING); pinMode(3,INPUT_PULLUP); attachInterrupt(1,ramen_off,FALLING); pinMode(12,OUTPUT); pinMode(13,OUTPUT); } void loop() { Ra(); Do(2); Re(2,5); Do(2); So(); Do(2); Ra(1,6); Ra(); Do(2); Re(2,4); Fa(2); Mi(2); Re(2); Do(2); Re(2,5); Re(2); Do(2); Ra(1,1,1); So(1,5); //Something wrong happen here when I remove wait 1 at Ra just above. Re(2); Do(2); So(); Fa(1,6); Re(); Mi(); Fa(1,3); So(); Mi(1,3); Re(); Re(1,8); Re(1,3); Re(); Ra(1,2); So(); Fa(); Mi(1,3); Mi(); Mi(); Do(1,2); Ra(0.5); Re(1,12); Re(1,2); Mi(1,2); Fa(1,4); Fa(); So(1,2); Ra(); Ra(1,4); Ra(1,2); Si(); Do(2); Do(2,2); Si(1,2); Ra(1,2); Do(2,2); Re(2,3); Re(2); Mi(2,4); Re(2,2); Ra(); So(); So(1,2); Fa(); So(); Re(1,6); Re(); Mi(); Fa(1,2); Mi(1,2); Re(1,2); Do(1,2); Re(1,4); Mi(1,4); Re(2,2); Ra(); So(); So(1,2); Fa(); So(); Re(1,6); Re(1,2); Mi(); Fa(); Fa(1,2); Mi(); Fa(); So(1,2); Fa(); So(); Ra(1,2); Si(1/FREQUENCY_PITCH,2); Ra(1,10); } void ramen_on(){ digitalWrite(13,HIGH); } void ramen_off(){ digitalWrite(13,LOW); }
苦労した点
音階データ(ドレミ)はすぐ見つかったけど、長さが分からないので苦労した。
楽譜なんてものはもちろん読めないし。
使った方法が、一旦すべての伸ばし音を短く切って、各音を同じ長さで歌いながら確認するという手法。
たとえばこの曲の始まりはこんな感じなんだけど、
「ラドレーーーードソドラーーーーー」
「ラドレレレレレドソドララララララ」という風に歌いながら机でも叩いて、叩いた回数を数えれば、何個分伸ばせばいいか分かる。
あ、昼休み終わってしまったので以上。