電子楽器の夢をみるのか -3ページ目

電子楽器の夢をみるのか

電子楽器製作をつづる。

相変わらず横道にそれます。
前回のプログラムで前々回YMZ294をAVRで動かす(2)~さっそく動かしてみる~
より楽に音の高さを指定することができました。
ちょっと曲を打ち込んでみようと思います。
打ち込んだ曲はこれ
「こいのぼり」

こどもの落書き。デジタルは難しい。

やねよりたかいこいのぼり~ってやつ。この曲にしたのは5月だから。ちょっと時期がずれているのはプログラムを作ったのが4月終わり、現在のプログラムはもうちょっと進んでる(´・ω・`)
楽譜を見ながらプログラムをぽちぽち打ち込む。前々回より楽になったとはいえ、時間がかかる。

前回のプログラムのメイン関数に次のデータを書き込みました。
        //イントロ
        setTone(72,0);
        setTone(48,1);
        _delay_ms(250);
        setTone(74,0);
        _delay_ms(250);
        setTone(76,0);
        _delay_ms(500);
        setTone(79,0);
        setTone(52,1);
        _delay_ms(500);
        //
        setTone(84,0);
        setTone(53,1);
        _delay_ms(500);
        setTone(81,0);
        _delay_ms(500);
        setTone(48,1);
        setTone(79,0);
        _delay_ms(500);
        //
        setTone(76,0);
        setTone(48,1);
        _delay_ms(250);
        setTone(76,0);
        _delay_ms(250);
        setTone(55,1);
        setTone(74,0);
        _delay_ms(500);
        setTone(76,0);
        _delay_ms(500);
        //
        setTone(72,0);
        setTone(48,1);
        _delay_ms(1000);
        setTone(128,0);
        setTone(128,1);
        _delay_ms(500);

        //1やねより
        setTone(64,0);
        setTone(48,1);
        _delay_ms(250);
        setTone(62,0);       
        _delay_ms(250);       
        setTone(60,0);       
        _delay_ms(500);
        setTone(62,0);
        setTone(52,1);       
        _delay_ms(500);
        //2たかい
        setTone(64,0);
        setTone(48,1);       
        _delay_ms(500);
        setTone(69,0);
        _delay_ms(500);
        setTone(52,1);
        setTone(67,0);
        _delay_ms(500);
        //3こいのぼ
        setTone(64,0);
        setTone(48,1);
        _delay_ms(250);
        setTone(64,0);
        _delay_ms(250);
        setTone(64,0);
        _delay_ms(500);
        setTone(62,0);
        setTone(52,1);
        _delay_ms(250);       
        setTone(60,0);
        _delay_ms(250);
        //4り
        setTone(62,0);
        setTone(55,1);
        _delay_ms(1000);
        setTone(128,0);
        setTone(128,1);
        _delay_ms(500);
       
        //5おおきい
        setTone(60,0);
        setTone(48,1);
        _delay_ms(250);
        setTone(62,0);
        _delay_ms(250);
        setTone(64,0);
        _delay_ms(500);
        setTone(67,0);
        setTone(52,1);
        _delay_ms(500);
        //6まごいは
        setTone(69,0);
        setTone(48,1);
        _delay_ms(250);
        setTone(69,0);
        _delay_ms(250);
        setTone(67,0);
        setTone(48,1);
        _delay_ms(500);
        setTone(64,0);
        _delay_ms(500);
        //7おとうさ
        setTone(67,0);
        setTone(48,1);
        _delay_ms(250);
        setTone(67,0);
        _delay_ms(250);
        setTone(64,0);
        _delay_ms(500);
        setTone(62,0);
        setTone(55,1);
        _delay_ms(500);
        //8ん
        setTone(60,0);
        setTone(48,1);
        _delay_ms(1000);
        setTone(128,0);
        setTone(128,1);
        _delay_ms(500);
       
        //9ちいさい
        setTone(72,0);
        setTone(52,1);
        _delay_ms(250);
        setTone(72,0);
        _delay_ms(250);
        setTone(72,0);
        _delay_ms(500);
        setTone(69,0);
        setTone(57,1);
        _delay_ms(500);
        //10ひごいは
        setTone(67,0);
        setTone(48,1);
        _delay_ms(250);
        setTone(67,0);
        _delay_ms(250);
        setTone(67,0);
        setTone(48,1);
        _delay_ms(500);
        setTone(64,0);
        _delay_ms(500);
        //11こどもた
        setTone(62,0);
        setTone(55,1);
        _delay_ms(250);
        setTone(62,0);
        _delay_ms(250);
        setTone(62,0);
        _delay_ms(500);
        setTone(60,0);
        setTone(48,1);
        _delay_ms(250);
        setTone(64,1);
        _delay_ms(250);
        //12ち
        setTone(67,0);
        setTone(55,1);
        _delay_ms(1000);
        setTone(128,0);
        setTone(128,1);
        _delay_ms(500);
       
        //13おもしろ
        setTone(60,0);
        setTone(48,1);
        _delay_ms(250);
        setTone(62,0);
        _delay_ms(250);
        setTone(64,0);
        _delay_ms(500);
        setTone(67,0);
        setTone(52,1);
        _delay_ms(500);
        //14そうに
        setTone(72,0);
        setTone(53,1);
        _delay_ms(500);
        setTone(69,0);
        _delay_ms(500);
        setTone(48,1);
        setTone(67,0);
        _delay_ms(500);
        //15およいで
        setTone(64,0);
        setTone(48,1);
        _delay_ms(250);
        setTone(64,0);
        _delay_ms(250);
        setTone(55,1);
        setTone(62,0);
        _delay_ms(500);
        setTone(64,0);
        _delay_ms(500);
        //16る
        setTone(60,0);
        setTone(48,1);
        _delay_ms(1000);
        setTone(128,0);
        setTone(128,1);
        _delay_ms(500);

これを打ち込むと・・音が鳴りました。これで好きな曲を打ち込むことが出来ます。
ですが本題はMIDIで動かすこと。まだまだ続きます。
自動演奏している所を見れるように動画を投稿しました。
こちら↓ YMZ294で「こいのぼり」

https://www.youtube.com/watch?v=TYjxrjbEKxk&feature=youtu.be

というわけでつづく

と言う訳で早速mega88で配列を組み込んだプログラムを作ります。
まず回路はこんな感じ

ピンの対応はtiny2313の時と変わっていません。YMZ294のD0~7はmega88のPORTB0~7に接続しています。D0はPB0、D1はPB1・・・・と繋ぐ。回路の書き方はこれであってるのだろうか。また、/WRは megaのPD0、/CSはPD1、A0はPD2、/ICはPD3に接続しています。
そしてメインのプログラムはこれ
/*
*YMZ294のテストその2        27/04/2014
*YMZ294_testを参考にちょっといじくる
*自動演奏用
*Author: Longtail
*対応ポート
*mega88                YMZ294
*PB0~7                D0~7
*PD0                    /WR
*PD1                    /CS
*PD2                    A0
*PD3                    /IC
*/
#define    F_CPU    1000000UL    // 1MHz
#include <util/delay.h>            // wait関数
#include <avr/io.h>
unsigned char ADR=0,DAT=0,SQU=0, x=0;    //変数の設定 ADR=アドレス DAT=データ
unsigned int Note[]={15289,14431,13621,12856,12135,11454,10811,10204,//C-1 0~7
    9631,9091,8581,8099,7645,7215,6810,6428,6067,5727,5405,5102,//C0
    4816,4545,4290,4050,3822,3608,3405,3214,3034,2863,2703,2551,//C1
    2408,2273,2145,2025,1911,1804,1703,1607,1517,1432,1351,1276,//C2
    1204,1136,1073,1012,956,902,851,804,758,716,676,638,//C3
    602,568,536,506,478,451,426,402,379,358,338,319,//C4
    301,284,268,253,239,225,213,201,190,179,169,159,//C5
    150,142,134,127,119,113,106,100,95,89,84,80,//C6
    75,71,67,63,60,56,53,50,47,45,42,40,//C7
    38,36,34,32,30,28,27,25,24,22,21,20,//C8
    19,18,17,16,15,14,13,13,12,11,11,10,//C9
    0//noteoff
    //MIDIノート番号に対応
};
void InitHard(void);        //ポートの初期化,YMZ294の音量設定
void Output(unsigned char,unsigned char);                //アドレス・データをYMZ294に渡すためのサブルーチン
void setTone(unsigned int,unsigned char);
int main(void){                    //メイン
    InitHard();
    _delay_ms(1000);                //安定のためにちょっと待つ
  setTone(69,0);                   //A=(440Hz)に指定する
    while(1){}
}
void InitHard(void) {            //ポート初期設定
    DDRB=0xff;                    //PORTB出力
    PORTB=0;                    //0を出力
    DDRD=0xff;                    //PORTD出力
    PORTD=0x08;                    //PD3以外0を出力
    _delay_ms(500);                //YMZ294が安定するまで待つ.
    Output(0x07,0x3e);            //ミキサー設定 Achのみ出力
    Output(0x08,0x1f);            //Ach 音量はEGに依存
}
void Output(unsigned char ADR,unsigned char DAT){
    PORTD=0x08;
    PORTB=ADR;                    //アドレスの出力
    PORTD=0x0b;
    PORTD=0x0c;
    PORTB=DAT;                    //データの出力
    PORTD=0x0f;
    PORTD=0x08;
}
void setTone(unsigned int x ,unsigned char SQU){
    switch(SQU){
        case 0:
        Output(0x00,Note[x] & 0xff);
        Output(0x01,(Note[x] >>8) & 0x0f);
        break;
        case 1:
        Output(0x02,Note[x] & 0xff);
        Output(0x03,(Note[x] >>8) & 0x0f);
        break;
        case 2:
        Output(0x04,Note[x] & 0xff);
        Output(0x05,(Note[x] >>8) & 0x0f);
        break;
    }
}

前回と同様にラ(A=440Hz)を出力することができました。
これでMIDIに対応できるんじゃないかなと思います。
次回はこれを使って自動演奏してみようと思います。要は横道にそれる。
つづく
前回、プログラムが大きすぎてコンパイル(ぷよぷよの会社ではない、今はSEGAだけど)が通らなくなりました。
その原因は配列が問題でした。配列のデータがマイコンのEEPROM(電源を切ってもデータを保存してくれるところ)の領域を圧迫したみたいです。
いろいろ考えた結果、使うマイコンを変えることにしました。
前回まではTiny2313を使用していましたが、mega88というものを使おうと思います。

さて、mega88がtiny2313と違うところをいくつかチョイス
1.フラッシュメモリとEEPROMの容量の違い
tiny2313だとフラッシュメモリは2kbyte,EEPROMは128byteに対し、mega88はフラッシュメモリは8kbyte,EEPROMは512byteと容量がup!
これで前回の問題は解決できそうです。もしかしたら、うまくプログラムを組めばtiny2313でも動作できるかもしれないけどね。
2.ピン数の違い
tiny2313は20ピンありますがmega88は28ピンあり、その分入出力ピンが増えています。今後、MIDI用の入力ポートやLEDを使う時にピン数の制約に悩まされないかも。
3.mega88はAD変換が使える
AD変換とは入力(アナログ)の値をコンピュータが扱いやすいデジタルに変換してくれるもの。
詳しい話は置いといて、こいつが何をできるかというと、こんな感じ↓
他にもセンサのデータが必要な時にも使われます。温度センサとかあれば温度計が作れる( `・ω・´ )マイクとか使えば録音とかできるかも。
とりあえず、AD変換は後程やろうかな。次回からmega88でYMZ294を動かします。
つづく




さて、前回の配列から好きな音を出すために関数をつくる必要があります。
作ったのがこちら
void setTone(unsigned int x ,unsigned char SQU){
    switch(SQU){
        case 0:
        Output(0x00,Note[x] & 0xff);
        Output(0x01,(Note[x] >>8) & 0x0f);
        break;
        case 1:
        Output(0x02,Note[x] & 0xff);
        Output(0x03,(Note[x] >>8) & 0x0f);
        break;
        case 2:
        Output(0x04,Note[x] & 0xff);
        Output(0x05,(Note[x] >>8) & 0x0f);
        break;
    }
}

この関数の最初の行にある変数xに数値を代入することで音を出します。例えばド(=262Hz)を出したいときは60と入力すればいい( `・ω・´ )ラ(=440Hz)なら69。ちなみにMIDIのノート番号と一緒にしてます。
ここでもう一つ変数SQUが出てきますがこれは音の割り振り。YMZ294は3音同時に出すことができます。SQUを0から2に設定することで3音を割り振りすることができます。
関数の使い方はこう
setTone(60,0);
これでAchにド(=262Hz)の高さの音をだすという命令になります。
さぁこのプログラムを組み込んで動かそう!と思った矢先、ハードウェア的な問題が、tiny2313に書き込もうと思ったら

プログラムのデータが大きすぎて書き込めないみたい(´・ω・`)

ちょっと考えてみます。つづく
前回、プログラムを打ち込みましたが、ちょっと変更しようと思います。
変更するところはここ、音程
前回ではラ(A=440z)を出力しました。ですがいろいろな高さの音を出したいです。でもそのたびに毎回毎回計算するのは面倒(´・ω・`)
と、いうわけでC言語の配列を使ってもう少し楽にできるようにしてみました。
とりあえず目標としては
「数値を入れる」→「その数値に対応した音がでる」
こんな感じ。数値に対応した音ってのは例えば60を入れたらド(C=261.63Hz)の音がでるといった感じ。
本当なら、直接「ド」の音をだす!とプログラムを作ってもいいけど、目標は外部からのキーボードで演奏できるようにしたいので規格に合わせるため(一応合わせたつもり(汗))に数値にしました。
まずは計算。一つ一つ計算するのは面倒なのでExcel君に頑張ってもらいました。周波数はこちらのサイトさんを参考にしました→DTM技術情報
ttp://www.g200kg.com/jp/docs/tech/notefreq.html

そして出てきた値を使って配列に組み込みます。ちなみに、小数点以下は四捨五入をしたため実際の周波数との誤差があります(´・ω・`)
書いたのがこちら↓

const int Note[]={15289,14431,13621,12856,12135,11454,10811,10204,//C-1 0~7
9631,9091,8581,8099,7645,7215,6810,6428,6067,5727,5405,5102,//C0
4816,4545,4290,4050,3822,3608,3405,3214,3034,2863,2703,2551,//C1
2408,2273,2145,2025,1911,1804,1703,1607,1517,1432,1351,1276,//C2
1204,1136,1073,1012,956,902,851,804,758,716,676,638,//C3
602,568,536,506,478,451,426,402,379,358,338,319,//C4
301,284,268,253,239,225,213,201,190,179,169,159,//C5
150,142,134,127,119,113,106,100,95,89,84,80,//C6
75,71,67,63,60,56,53,50,47,45,42,40,//C7
38,36,34,32,30,28,27,25,24,22,21,20,//C8
19,18,17,16,15,14,13,13,12,11,11,10,//C9
0//note off
//MIDIノート番号に対応
};

128個。この数もMIDIのノート番号に合わせてます。これで楽に呼び出しができそうです。
ですがこの配列の値を呼び出す関数をつくる必要があります。とりあえず続く。