sexta-feira, 10 de fevereiro de 2012

GO FOR IT / コードで世界は変えられる / 旋律に隠された特徴

プログラムコード(melody.c)

/**************** START ****************/

#include < stdio.h >

struct note {

int height;

int length;

int accident;

int height2;

};


int checkscale(int x,int y);

int SumInterval(int q,struct note x[]);


/**************** main ****************/


int main () {


struct note x[30];

int c,i=0,d,m,sum;

char buff[100];


/******** 記入した譜面を構造体に記録する ***************/

while((c=getchar())!='\n') {


while(c!=','){


if (c=='-') {


c=getchar();

buff[1]='\0';  /* reset buff */

buff[0]=c;

d =atoi(buff); /* 自然数に変える */

x[i].height=-d; /* マイナスをつける */

}

else if (c==':') x[i].height=x[i-1].height;


else {

buff[1]='\0';

buff[0]=c;

d =atoi(buff);

x[i].height=d;

}


c=getchar(); /* :をスキップ */

c=getchar();

m=0;


while (c!=':'){

buff[m]=c;

c=getchar();

m++;

}


d =atoi(buff);

x[i].length=d; /*分析に音の長さを使っていないので、省略可 */

c=getchar();

if (c!=',' && c!='\n') {

buff[0]=c;

x[i].accident=buff[0];

}


else {

x[i].accident='0';

}


if (x[i].accident=='s') x[i].height2=x[i].height*10+5;

if (x[i].accident=='x') x[i].height2=x[i].height*10+10;

if (x[i].accident=='b') x[i].height2=x[i].height*10-5;

if (x[i].accident=='d') x[i].height2=x[i].height*10-10;

if (x[i].accident=='0') x[i].height2=x[i].height*10;


i++;

break;

}

}


sum=SumInterval(i,x);

printf("特徴量=%d\n",sum);

}


/********* checkscale ******************/

/*******-シ、ミ-ファを通る分、

半音を引く計算をする関数 ****************/


int checkscale(int x,int y){


int sum=0,l;

int scale[16]={0,5,0,0,5,0,0,0,5,0,0,5,0,0,0,5}; /*-8から+8までのスケール。全音を0、半音を5としている*/


if (x>y) {


for (l=y+8;l< x+8;l++){

sum+=scale[l];

}

}


if (x

for (l=x+8;l< y+8;l++){

sum+=scale[l];

}

}


return (sum);

}


/**************** SumInterval *********************/

/*隣り合う音の間隔を計算する関数。*/


int SumInterval(int q,struct note x[]){

int a,b,sum=0,check,i;


for (i=1;i< q;i++){


a=x[i].height2-x[i-1].height2;

b=a<0?0-a:a; /* 絶対値の計算*/

check=checkscale(x[i].height,x[i-1].height);

sum+=(b-check);

}


return (sum);

}


/**************** END ****************/

出力の例

全音を10、半音を5として隣り合う音同士の間隔を数えている。

AからGまでの楽譜を入力したときの出力は以下の通り。

A楽譜:

t11m022@s01612h009:~/sony$ cc melody.c -o melody

t11m022@s01612h009:~/sony$

t11m022@s01612h009:~/sony$ ./melody

-3:4:,-2:4:,-1:4:,0:4:b,-1:4:,-2:4:,-3:4:,:4:,-1:4:,0:4:b,1:4:,2:4:,1:4:,0:4:b,-1:4:,:4:

特徴量=120

B楽譜:

t11m022@s01612h009:~/sony$ ./melody

3:4:,2:4:,1:4:,0:4:b,1:4:,2:4:,3:4:,:4:,1:4:,0:4:b,-1:4:,-2:4:,-1:4:,0:4:b,1:4:,:4:

特徴量=130

C楽譜:

t11m022@s01612h009:~/sony$ ./melody

3:4:,2:4:,1:4:,0:4:,1:4:,2:4:,3:4:,:4:,1:8:,0:4.:,-1:4:,-2:4:,:8:,-1:4.:,0:8:,1:8:

特徴量=120

D楽譜:

t11m022@s01612h009:~/sony$ ./melody

-6:8:,-6:8:,-6:8:,-4:8:,-2:8:,-2:8:,-2:8:,:8:,-5:8:,-5:8:,-5:8:,-3:8:,-2:8:,-2:8:,-2:8:,:8:,:8:,-2:8:,-2:8:,-1:8:b,-1:8:,-1:8:,-1:8:,-1:8:b,-2:4:,0:4:,1:4:,:4:

特徴量=130

E楽譜:

t11m022@s01612h009:~/sony$ ./melody

-6:8.:,-7:16:,-6:8:,-5:8:,-4:8:,-4:8:,-4:4:,-3:8.:,-4:16:,-5:8:,-6:8:,-5:4:,:4:,-3:8:,-5:4:,-5:8:,-4:8:,-4:8:,-3:8:,-3:8:,-4:8:,-4:8:,-5:8:,-5:8:,-6:4:,:4:

特徴量=140

F楽譜:

t11m022@s01612h009:~/sony$ ./melody

-6:2:,-5:4:,-6:8:,-5:8:,-4:4:,-2:4:,-4:4:,:4:,-5:4:,-5:4:,-6:4:,-5:4:,-4:2.:,:4:

特徴量=110

G楽譜:

t11m022@s01612h009:~/sony$ ./melody

-2:8.:,-1:16:,-2:8.:,-1:16:,-2:4:,-4:4:,-4:8.:,-3:16:,-4:8.:,-3:16:,-4:4:,-6:4:,-4:8:,:8:,-6:8.:,-5:16:,-4:8:,:8:,-6:8.:,-5:16:,-4:8.:,-4:16:,-2:8.:,-2:16:,-5:8.:,-4:16:,-5:4:

特徴量=255

t11m022@s01612h009:~/sony$

i)の問題はABが異なって、ACが特徴量が同じになるようにと指示してあったので、これを満たしている。A=C=120 、B=130

ii)の問題はD,E,FのどれがBと同じ特徴量を出力するかという問題である。

D130E=140F110なので、Bと同じのはD

iii)はすみませんが、時間の関係で解いていない。

アルゴリズムの簡単な説明・動作方法

このプログラムでまず入力した楽譜を構造体で整理している。

: や「,」を区きりにして、その間の情報を音の高さheight、長さlength、臨時記号accidentで分けている。

その後、accidentで高さを調整している。自然数で計算できるように、高さを10でかけて、accidentによって+5 (s) , +10 (x) , -5 (b) , -10 (d)を引いたり足したりする。その結果をheight2として保存する。

SumInterval関数では隣り合う音同士の間隔をそのまま足している。例えば、ド(+1)からレ(+2)に移動した旋律なら、|10-20|=10 。その後レ(+2)からミ(+3)のフラットなら、|20-25|=5。 sum=10+5=15となる。

しかし、シとドまたはミとファの間には半音の間隔しかないので、その調整を checkscale関数でしている。

楽譜の-8から+8の音の間隔がscale配列に記録されているので、SumIntervalの計算に「ド・シ、ミ・ファを通った分」5を引いて行く。

これで特徴量として、隣り合う音同士の間隔を足した値を使って楽譜を分析した。

実行環境など

LinuxUbuntu Ver. 10 , 64bitモードで実行しましたが、C言語のコンパイラがあればどこでも実行できると思います。

コードを.cファイルとして保存して、コンパイルしたら実行できます。