チーム2016

課題名

PSoC variable MUSIC BOX

研究者名

2-15-011 Shimon Kato
2-15-012 Yuya Kato

概要

PSoCに予め入力した音楽とは別の音楽をUARTで一気に書き込んで再生することができる。
楽曲は8小節分、A2~A4の2オクターブ+1音(#・♭のつく音は入力として受け付けない)
8小節分再生すると半音上げて再生、を繰り返す。
ボタンを押していると短調化(入力をmajorとしてminorにする)

HSPで実行するプログラムからは、LCDの表示内容の変更、PSoC内部の音楽の書き換え、最初から再生、が可能(予め仕込んだいくつかの楽曲は簡単に入力できる)
variable_hsp.png

ハード接続設定

スピーカーは
 p00<==>GND

ジャンパはそれぞれ
 Tx<==>p05
 Rx<==>p03
 SW<==>p14


hard.jpg

UserModules

user_module.png

パラメータ(Global & PWM_16)

param_global.png


パラメータ(Counter 8)

param_cnt.png

パラメータ(UART)

param_uart.png

パラメータ(LCD)

param_lcd.png

パラメータ(Timer16)

param_timer.png

Pinout設定

左の+マークをクリックして、それぞれの値を設定してください(この場合変更するのはP1[4]のみ)
pinout.png

割り込み設定

timer_asm.png

ソースコード(main.c)

//----------------------------------------------------------------------------
// PSoC MUSIC BOX
// timer_pwm2:REF scale_freq.xls
// gpio_poll
// pwn_uart_2
// TODO | | ==>| |
// Sys Clock 24MHz, PWM16 Clock = VC3/25, VC3=VC2/1, VC2=VC1/16
//----------------------------------------------------------------------------

#include <m8c.h> // part specific constants and macros
#include "PSoCAPI.h" // PSoC API definitions for all User Modules
#pragma interrupt_handler myISR

#define SW 0b00010000
enum MELODY_TYPE{MELODY_BASE, MELODY_MAIN};
char ISTAN=0;
#define MELO1(a) tencho(kai[ISTAN][a],MELODY_MAIN)
#define MELO2(a) tencho(kai[ISTAN][a],MELODY_MAIN)
#define MELOb(a) tencho(kai[ISTAN][a],MELODY_BASE)
int PW=125;// Pulse Width
//Array meccha RAM kurau dengana...
//Func nara ROM de sumu dengana
// onkai
//int mpr[26] = {0,288, 273 ,258 ,243 ,229 ,217 ,204 ,193 ,182 ,172 ,162 ,153 ,145 ,136 ,129 ,121 ,115 ,108 ,102 ,96 ,91 ,86 ,81 ,77 ,72, 68};
int mprf(char x){
  switch (x){
       case  1: return 288;
       case  2: return 273;
       case  3: return 258;
       case  4: return 243;
       case  5: return 229;
       case  6: return 217;
       case  7: return 204;
       case  8: return 193;
       case  9: return 182;
       case 10: return 172;
       case 11: return 162;
       case 12: return 153;
       case 13: return 145;
       case 14:return 136;
       case 15:return 129;
       case 16:return 121;
       case 17:return 115;
       case 18:return 108;
       case 19:return 102;
       case 20:return 96;
       case 21:return 91;
       case 22:return 86;
       case 23:return 81;
       case 24:return 77;
       case 25:return 72;
       case 26:return 68;
       default :return 0;
   }
}
int mprb[13]= {0,545 ,513 ,488 ,458 ,432 ,408 ,385,364,343,324,306,288};

// for major & minor
char kai[2][16] = {
  {0, 2, 4, 5, 7, 9, 10, 12, 14, 16, 17, 19, 21, 22, 24, 26},// major
   {0, 1, 3, 5, 7, 8, 10, 12, 13, 15, 17, 19, 20, 22, 24, 25}//minor
};
//Scale(4bit)   //For UART
#define SL 0 //
#define A2 1 //
#define B2 2 //
#define C3 3 //
#define D3 4 //
#define E3 5 //
#define F3 6 //
#define G3 7 //
#define A3 8 //
#define B3 9 //
#define C4 10 //A
#define D4 11 //B
#define E4 12 //C
#define F4 13 //D
#define G4 14 //E
#define A4 15 //F
char TC=0;// Time Count

char tench=0;
int tencho(char kai, char m){
  if (kai==0) return 0;
   if (m){
       // MELODY_MAIN
       if (kai+tench<=26)return mprf(kai+tench);
       return mprf((kai+tench-26)%12+14);
   }else {
       // MELODY_BASE
       if (kai+tench<=12)return mprb[kai+tench];
       return mprb[(kai+tench-1)%12+1];
   }
}

// saisyo ha 3 waon MusicBox yarou to shita
// uart tsukattara pwm hairan...
// kore sono zangai...

/*
unsigned char melo1[64]={
  D3<<4|D3, D3<<4|D3, A3<<4|A3, A3<<4|A3, E3<<4|E3, E3<<4|E3, A3<<4|A3, A3<<4|A3,
   F3<<4|F3, F3<<4|F3, G3<<4|G3, A3<<4|A3, G3<<4|G3, G3<<4|G3, B3<<4|B3, B3<<4|B3,
   D4<<4|D4, A3<<4|A3, E4<<4|E4, F4<<4|F4, E4<<4|E4, F4<<4|E4, D4<<4|D4, C4<<4|C4,
   A3<<4|A3, C4<<4|C4, G3<<4|G3, A3<<4|A3, F3<<4|F3, F3<<4|F3, F3<<4|F3, F3<<4|F3,
   D3<<4|D3, D3<<4|D3, A3<<4|A3, A3<<4|A3, E3<<4|E3, E3<<4|E3, A3<<4|A3, A3<<4|A3,
   F3<<4|F3, F3<<4|F3, G3<<4|G3, A3<<4|A3, G3<<4|G3, G3<<4|G3, B3<<4|B3, B3<<4|B3,
   D4<<4|D4, A3<<4|A3, E4<<4|E4, F4<<4|F4, E4<<4|E4, F4<<4|E4, D4<<4|D4, C4<<4|C4,
   D4<<4|D4, D4<<4|D4, D4<<4|D4, D4<<4|D4, D4<<4|D4, D4<<4|D4, D4<<4|D4, D4<<4|D4
};
unsigned char melo2[64]={
  A2<<4|A2, A2<<4|A2, F3<<4|F3, F3<<4|F3, A2<<4|A2, A2<<4|A2, F3<<4|F3, F3<<4|F3,
   D3<<4|D3, D3<<4|D3, E3<<4|E3, F3<<4|F3, E3<<4|E3, E3<<4|E3, G3<<4|G3, G3<<4|G3,
   A3<<4|A3, F3<<4|F3, C4<<4|C4, D4<<4|D4, SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL,
   F3<<4|F3, A3<<4|A3, E3<<4|E3, F3<<4|F3, D3<<4|D3, D3<<4|D3, D3<<4|D3, D3<<4|D3,
   A2<<4|A2, A2<<4|A2, F3<<4|F3, F3<<4|F3, A2<<4|A2, A2<<4|A2, F3<<4|F3, F3<<4|F3,
   D3<<4|D3, D3<<4|D3, E3<<4|E3, F3<<4|F3, E3<<4|E3, E3<<4|E3, G3<<4|G3, G3<<4|G3,
   A3<<4|A3, F3<<4|F3, C4<<4|C4, D4<<4|D4, SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL,
   A3<<4|A3, A3<<4|A3, A3<<4|A3, A3<<4|A3, A3<<4|A3, A3<<4|A3, A3<<4|A3, A3<<4|A3
};
// 1/2 shosetsu *2 * 8
unsigned char bass[4]={
  F3<<4|G3, A3<<4|G3, F3<<4|G3, A3<<4|A3
};*/
//** The monster girl of Hartman
unsigned char melo1[64]={
  D4<<4|D4, C4<<4|C4, D4<<4|D4, A3<<4|A3, F3<<4|F3, E3<<4|E3, F3<<4|F3, D3<<4|E3,
   F3<<4|F3, F3<<4|F3, F4<<4|F4, F4<<4|F4, E4<<4|E4, E4<<4|E4, C4<<4|C4, C4<<4|C4,
   D4<<4|D4, E4<<4|E4, F4<<4|F4, A4<<4|A4, F4<<4|F4, E4<<4|E4, C4<<4|C4, E3<<4|E3,
   F3<<4|F3, F3<<4|F3, C4<<4|C4, C4<<4|C4, D4<<4|D4, D4<<4|D4, D4<<4|D4, A3<<4|C4,
   D4<<4|D4, C4<<4|C4, D4<<4|D4, E4<<4|E4, F4<<4|F4, E4<<4|E4, G4<<4|G4, E4<<4|E4,
   F4<<4|F4, E4<<4|E4, D4<<4|D4, C4<<4|C4, F3<<4|F3, F3<<4|F3, E3<<4|E3, E3<<4|E3,
   D3<<4|D3, E3<<4|E3, F3<<4|F3, A3<<4|A3, F3<<4|F3, A3<<4|A3, F3<<4|F3, E3<<4|E3,
   D3<<4|D3, C3<<4|C3, A2<<4|A2, C3<<4|C3, D3<<4|D3, D3<<4|D3, E3<<4|E3, E3<<4|E3
};
/*
unsigned char melo2[64]={
  SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL,
   D3<<4|D3, D3<<4|D3, D4<<4|D4, D4<<4|D4, C4<<4|C4, C4<<4|C4, A3<<4|A3, A3<<4|A3,
   SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL, C3<<4|C3,
   D3<<4|D3, D3<<4|D3, E3<<4|E3, E3<<4|E3, F3<<4|F3, F3<<4|F3, F3<<4|F3, SL<<4|SL,
   SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL,
   D4<<4|D4, C4<<4|C4, A3<<4|A3, A3<<4|SL, D3<<4|D3, D3<<4|D3, C3<<4|C3, C3<<4|C3,
   SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL, SL<<4|SL,
   A2<<4|A2, A2<<4|A2, F3<<4|F3, A2<<4|A2, F3<<4|F3, F3<<4|F3, G3<<4|G3, G3<<4|G3
};*/
// 1/2 shosetsu *2 * 8
/*unsigned char bass[4]={
  D3<<4|A3, F3<<4|A3, F3<<4|A3, F3<<4|A3
};*/

void myISR(void){
  int t;
   // base
   /*t=TC/8;
   if (t&1)PW=MELOb(bass[(t/2)%8]&0b1111);
   else PW=MELOb(bass[(t/2)%8]>>4);
   PWM16_3_WritePeriod(PW);
   PWM16_3_WritePulseWidth(PW/2);*/
   // main
   t=TC/2;
   // melo1
   PW=MELO1( (TC&1) ? melo1[t]&0b1111 : melo1[t]>>4);
   PWM16_1_WritePeriod(PW);
   PWM16_1_WritePulseWidth(PW/2);
   // melo2
   /*PW=MELO2( (TC&1) ? melo2[t]&0b1111 : melo2[t]>>4);
   PWM16_2_WritePeriod(PW);
   PWM16_2_WritePulseWidth(PW/2);
   */
   // roop & tencho
   if(TC==127){
       TC=0;
       tench=(tench+1)%12;
   }
   else TC++;
}
int htod(char x){
  if('0'<=x && x<='9')        return x-'0';
   else if ('A'<=x && x<='F')  return x-'A'+10;
   return -1;
}

//for UART
char *strPtr;

void main(void)
{
  M8C_EnableGInt ; // Uncomment this line to enable Global Interrupts
   // Insert your main routine code here.
   
   PWM16_1_Start();
   //PWM16_2_Start();
   //PWM16_3_Start();
   Timer16_1_EnableInt();
   Timer16_1_Start();
   LCD_Start();
   LCD_Position(0,1);
   LCD_PrCString("The monster ");
   LCD_Position(1,1);
   LCD_PrCString("girl of Hartman");
   PRT1DR&=(~SW);
   
   UART_CmdReset();
   UART_IntCntl(UART_ENABLE_RX_INT);
   
   Counter8_WritePeriod(155);
   Counter8_WriteCompareValue(77);
   Counter8_Start();
   
   UART_Start(UART_PARITY_NONE);

  /*
    PC=>PSoC
    num data
    (0<= num <=FF)
   num
       1    replay
   
       10-1F rewrite music
   
       FC-FF rewrite LCD
   
    PSoC=>PC
    SC num | FA num
   
   */

  while (1){
       // push swich => minor
       // nopush swich =>major
       if (PRT1DR & SW)ISTAN=1;
       else ISTAN=0;
       PRT1DR &=(~SW);
       
       //UART
       if (UART_bCmdCheck()){
           // disable interrupt
           M8C_DisableGInt;
           if (strPtr = UART_szGetParam()){
               int mes_num=0;
               while (*strPtr!='\0'){
                   mes_num*=16;
                   if (htod(*strPtr)>=0) mes_num+=htod(*strPtr);
                   else{
                       mes_num=-1;
                       break;
                   }
                   strPtr++;
               }
               if (mes_num<0 | | 256<=mes_num){
                   //fault
                   UART_CPutString("FA ");
                   UART_PutSHexInt(mes_num);
                   UART_CPutString("\r\n");
               }else {
                   //success
                   if(strPtr = UART_szGetParam()){
                       if (mes_num==0x01){
                           //reset
                           TC=0;
                           tench=0;
                       }else if (0xFC<=mes_num && mes_num<=0xFF){
                           char posx[4]={0,0,1,1}, posy[4]={0,8,0,8}, x[9];
                           char i;
                           for(i=0; strPtr[i]!='\0' ; i++){
                               x[i]=strPtr[i];
                               if (x[i]=='_') x[i]=' ';
                           }
                           LCD_Position(posx[mes_num-0xFC],posy[mes_num-0xFC]);
                           LCD_PrCString("        ");
                           LCD_Position(posx[mes_num-0xFC],posy[mes_num-0xFC]);
                           LCD_PrString(x);
                       }else if (0x10<=mes_num && mes_num<=0x1F){
                           char i;
                           for (i=0; i <4; i++){
                               int f1= htod(strPtr[2*i]), f2= htod(strPtr[2*i+1]);
                               if(0<=f1 && 0<=f2) melo1[(mes_num-0x10)*4+i]=f1<<4 | f2;
                               else melo1[(mes_num-0x10)*4+i]=0;
                           }
                       }else{
                           LCD_Position(0,0);
                           LCD_PrCString("Not Found");
                           LCD_Position(1,0);
                           LCD_PrHexInt(mes_num);
                       }
                       UART_CPutString("SC ");
                   }else {
                       UART_CPutString("FA ");
                   }
                   UART_PutSHexInt(mes_num);
                   UART_CPutString("\r\n");
               }
           }
           UART_CmdReset();
           M8C_EnableGInt;
       }
       
   };
}

ソースコード(HSP)

//-------------------------------------------------------
// HSP SourceCode
//メリット・GUIが楽
//-------------------------------------------------------
#include "hspext.as"
#include "mod_regexp.as"


//[TODO] 各環境ごとに書き換え
#define COM_PORT 5


  onexit *close
   comopen COM_PORT,"baud=38400 parity=N data=8 stop=1"
   if stat : dialog "接続エラー" : end
   
   //連続的な命令の送信をQueueの形で管理し送信
   //ただHSPにキューが無いのでnote系命令で代用
   
   title "PSoC variable MUSIC BOX REWRITER"
   
   sdim rxBuffer, 64
   sdim txBuffer, 64
   font "MS UI Gothic", 13 , 0
   sdim cmdbuf, 256
   notesel cmdbuf
   
   //LCD表示用
   sdim uplinemes, 16
   sdim btlinemes, 16
   sdim x,16
   
   input uplinemes, 240, 20, 16//objid = 0
   input btlinemes, 240, 20, 16//objid = 1
   
   
   
   //音階書き換え用
   sdim melody, 256
   sdim melodyToSend, 256
   sdim strbuf, 64
   
   
   
   mesbox melody,320, 60 //objid = 2
   
   pos 0,100
   objsize 160,40
   button gosub "音階を書換", *add_Melody //objid = 3
   pos 160,100
   button gosub "最初から再生", *add_Zero //objid = 4
   
   pos 240,0
   objsize 80,40
   button gosub "LCDを書換", *add_LCDrewrite//objid = 5
   
   pos 340,20
   objsize 80,40
   button gosub "Yamada Denki", *music_yamada
   button gosub "B.B.K.K.B.K.K.", *music_bbkkbkk
   button gosub "Southern Cross", *music_SouthernCross
   button gosub "ハルトマン", *music_haltman
   
   
   sdim log,4096
   log="Start\n"
   pos 0,140
   mesbox log,320,320,4096
   logbox = stat
   
   
   
   sendmes=0    //キューが空の状態から新しい命令が追加されたことを伝える変数
   resendcnt=0 //送信失敗回数を数えるための変数
   change=0    //ボタン押下可能かを管理する変数

*main
   gosub *getdata
   await 50//何故か長いとバグる?
   goto *main
*getdata
   comget rxBuffer, 64
   if(rxBuffer != ""){
       //何らかの文字を取得した時
       log+= "GET :\""+replace(rxBuffer,"[\\r\\n]","")+"\"\n"
       objprm logbox,log
       split rxBuffer, " ", rslt, num
       if(rslt == "SC"){
           //success
           resendcnt=0
           notedel 0
           if(notemax!=0){
               gosub *send
           }else{
               gosub *enable
           }
       }else{
           //fault(resend)
           if(notemax!=0){
               gosub *resend
           }
       }
   }
   if(sendmes){
       gosub *send
   }
   
   return
//16部音符単位で記入 8小節。ラ~ソ、ラ↑~ソ↑、ラ↑↑の15音、音伸ばし(ー)、休符(・)以外は無視される
//連続で同じ音がなると音符が繋がる。
*music_yamada
   // music:YamadaDenki
   melody = "ド↑・ド↑ーーーレ↑ー|ド↑ーーシ↑ラ↑ーソー|ラ↑ーソーファーミー|レーーーーーー・|レーミーファーソー|ラ↑ーソーラ↑ーシ↑ー|ド↑ーシ↑ード↑ーレ↑ー|ミ↑ー・・ド↑ーソー|ーーー・ミ↑・ミ↑ー|ファ↑ーミ↑ーレ↑ード↑ー|・・シ↑ー・・ソー|ラ↑ー・・シ↑ード↑ー|・・・・ミー・・|・・ミー・・ドレ|ミー・・・・・・|・・・・・・・・"
   objprm 2,melody
   return
*music_bbkkbkk
   // music:B.B.K.K.B.K.K.
   melody= "ラ↑ー・ラ↑ー・ソー            |ラ↑ー・ラ↑ー・シ↑ー|\nド↑ー・ド↑ー・シ↑ー        |ド↑ーシ↑ード↑ーレ↑ー|\nファ↑ー・ファ↑ー・ミ↑ー    |ファ↑ー・ファ↑ー・ソ↑ー|\nミ↑ー・ミ↑ー・レ↑ー        |ミ↑ーレ↑ード↑ーソー|\nラ↑ー・ラ↑ー・ソー            |ラ↑ー・ラ↑ー・シ↑ー|\nド↑ー・ド↑ー・シ↑ー        |ド↑ーシ↑ード↑ーレ↑ー|\nファ↑ー・ファ↑ー・ミ↑ー    |ファ↑ー・ファ↑ー・ソ↑ー|\n・・・・・・・・                |・・・・・・・・"
   objprm 2,melody
   return

*music_southerncross
   // music:SouthernCross
   melody= "レーーーラミラミドラミドラ↑ミド↑ラ↑|ミ↑ファ↑ソ↑ミ↑ファ↑ド↑ラ↑ファラ↑ド↑ファ↑ラ↑ド↑ファ↑ミ↑|ド↑ラ↑ファファ↑ミ↑ファ↑ミ↑ミシ↑ド↑ミ↑ミシ↑ソファミ|ソシミソララ↑ララ↑レ↑ド↑シ↑ラ↑ミー・・|ミー・・ラミラミドラミドラ↑ミド↑ラ↑|ミ↑ファ↑ソ↑ミ↑ファ↑ド↑ラ↑ファラ↑ド↑ファ↑ラ↑ド↑ラ↑ファ↑ミ↑|ド↑ラ↑ファファ↑ミ↑ファ↑ミ↑ミシ↑ド↑ミ↑ミシ↑ソファミ|シ↑ミソシ↑ララ↑ラミ↑レドシララ↑ーーー"
   objprm 2,melody
   return
   
*music_haltman
   // music:The monster girl of Hartman
   melody= "レ↑ード↑ーレ↑ーラ↑ーファーミーファーレミファーーーファ↑ーファ↑ーミ↑ーーード↑ーーーレ↑ーミ↑ーファ↑ーラ↑↑ーファ↑ーミ↑ード↑ーミーファーーード↑ード↑ーレ↑ーーーーーラ↑ド↑レ↑ード↑ーレ↑ーミ↑ーファ↑ーミ↑ーソ↑ーミ↑ーファ↑ーミ↑ーレ↑ード↑ーファーーーミーーーレーミーファーラ↑ーファーラ↑ーファーミーレードーラードーレーーーミーーー"
   objprm 2,melody
   return
*add_LCDrewrite
   gosub *enable
   if(notemax==0){
       sendmes=1
   }
   //spaceは_でエスケープ(良い文字ねぇかな)
   if(uplinemes!=""){
       x=strmid(uplinemes, 0, 8)+"________"
       noteadd "FC "+replace(strmid(x,0,8)," ","_")
       x=strmid(uplinemes, 8, 8)+"________"
       noteadd "FD "+replace(strmid(x,0,8)," ","_")
   }
   if(btlinemes!=""){
       x=strmid(btlinemes, 0, 8)+"________"
       noteadd "FE "+replace(strmid(x,0,8)," ","_")
       x=strmid(btlinemes, 8, 8)+"________"
       noteadd "FF "+replace(strmid(x,0,8)," ","_")
   }
   return

*send
   //キューの先頭(note0行目)のコマンドを送信
   noteget txBuffer, 0
   txBuffer=replace(txBuffer,"[^A-Za-z0-9_+*\\- \\t]","")

  log+= "SEND:\""+txBuffer+"\"\n"
   objprm logbox,log

  comput txBuffer+"\r"
   txBuffer=null
   sendmes=0
   return

*resend
   //再送信(4回まで)
   if(resendcnt>=4){
       resendcnt=0
       notedel 0
       log+= "4times FAULT..."
       objprm logbox,log
       return
   }
   resendcnt++
   noteget txBuffer, 0
   txBuffer=replace(txBuffer,"[^A-Za-z0-9_+*\\- ]","")

  log+= "RESEND:\""+txBuffer+"\"\n"
   objprm logbox,log

  comput txBuffer+"\r"
   txBuffer=null
   return

*add_Melody
   gosub *enable
   //入力された音階情報から送信コードを生成
   melodyToSend=replace(melody,"ー|―","-")
   melodyToSend=replace(melodyToSend,"[^ドレミファソラシ↑・-]","")
   melodyToSend=replace(melodyToSend,"ラ↑↑","F")
   melodyToSend=replace(melodyToSend,"ソ↑","E")
   melodyToSend=replace(melodyToSend,"ファ↑","D")
   melodyToSend=replace(melodyToSend,"ミ↑","C")
   melodyToSend=replace(melodyToSend,"レ↑","B")
   melodyToSend=replace(melodyToSend,"ド↑","A")
   melodyToSend=replace(melodyToSend,"シ↑","9")
   melodyToSend=replace(melodyToSend,"ラ↑","8")
   melodyToSend=replace(melodyToSend,"ソ","7")
   melodyToSend=replace(melodyToSend,"ファ","6")
   melodyToSend=replace(melodyToSend,"ミ","5")
   melodyToSend=replace(melodyToSend,"レ","4")
   melodyToSend=replace(melodyToSend,"ド","3")
   melodyToSend=replace(melodyToSend,"シ","2")
   melodyToSend=replace(melodyToSend,"ラ","1")
   melodyToSend=replace(melodyToSend,"・","0")
   while match(melodyToSend,"-")!=""
       melodyToSend=replace(melodyToSend,"(.)-","$1$1")
       melodyToSend=replace(melodyToSend,"^-","0")
   wend
   melodyToSend=replace(melodyToSend,"[^0-9A-F]","")
   if(notemax==0){
       sendmes=1
   }
   repeat 16
       //0埋めして半小節ごとにコマンドにし、キュー(note最終行)に追加
       strbuf=strmid(melodyToSend, 8*cnt, 8)+"00000000"
       noteadd strf("1%X ",cnt)+strmid(strbuf, 0, 8)
   loop
   return

*add_Zero
   //最初から再生
   gosub *enable
   if(notemax==0){
       sendmes=1
   }
   noteadd "1 0"
   return
*enable
   //オブジェクトの有効・無効を切り替え
   repeat 6
       objenable cnt, change
   loop
   change^=1
   return
*close
   comclose
   end
   

考察

PSoC variable MUSIC BOXの他のデバイスと異なる特徴は発音情報を都度都度送信するのではなく、楽譜データを一気に送信し、あくまで奏でるのはPSoCであるという点にある。そのため(PSoCにとっては)大容量通信を実現するために相互通信プロトコル(コマンド)を自分らで決めた。

PC側からの送信は1バイトのコマンド番号と12文字程度に収まるデータ, PSoCからはその返答として適切に受信できたことを意味するコードを送信することにした。
これにより、異常な返答ならば再送信するなどの対応が取れる


また、転調と移調を実現するため、
ハ長調入力(0~15) , 転調するかどうか=>音(半音含む)のインデックス(0~26)
音のインデックス, 移調度合い=>実際に鳴らす音のPWM16 Period(int)
の二段階の変換を行うことにした。

元々は3和音を奏でられる書き換え可能なデバイスを作りたかったが、UserModelsの置き場所が足りず、泣く泣く2音分のPWM16を消去したという経緯をたどっている。
(3和音はPWMの各出力をXORすれば実現できた)
そのため、いかにRAM使用量上限を超えないようにするか、ということで64bit配列に128音分の情報を埋め込むかを考え、半音の情報を削除した2オクターブ分15通り(4bit)に制限した。
しかし、情報を圧縮したことで、転調・移調などを複雑な分岐をせずに実装することができた。

楽譜情報の転送の際、再送信や待機なども柔軟にできるよう、キューの構造を使いたかったがHSPにキュー構造が無かった。しかしNOTE系命令で代用できることに気づいた。

課題として、まれに転送に失敗する(PSoCからの返答が得られない)こと, 表現可能な音が2オクターブ程しかないこと, 和音を実現できなかったこと等が挙げられる。
また、LCDに書き換える際、空白が意味のある文字として存在するので、アンダーバーでエスケープしているが、これではアンダーバーが使えない。通常使用しないで動作がおかしくならないような適切な制御文字に変えたい。
転送の失敗度合いはawaitの値を変えることである程度抑えられそうだが、適切な値を検討できずにいる。

参考

hello_world, timer_pwm, gpio_poll, pwn_uart_2, HSPの利用に関してはTAのページを参考にした

  • 最終更新:2020-06-02 18:17:12

このWIKIを編集するにはパスワード入力が必要です

認証パスワード