すごい、複雑な楽譜を書いたとします。

でも、人で弾ける限界はあります。

でもでも、コンピュータなら演奏できます。


ということで、MIDIとして音符をプログラムで作成して、電子ピアノに弾かせてみました。

カオスを発生させるロジスティック写像を使っています。

#この写像関数については適当に検索をすればいっぱい解説が出てくるので略



chaosmusic1

https://youtu.be/QMQZDy_f4uQ


私はピアニストではないですが、ピアノを弾く役で自作自演。

ジョン・ケージの4'33''のイメージが被るかもしれませんが、そんなムービーを作ってみました!




プログラムはC言語で書いてます。スタンダードMIDIファイルとして出力。

譜面はSibeliusで作成。

以下は基本部分のプログラムを。上の作品ではいろいろアレンジしてますが、でも、結構書き方が汚いので他人様に見せるのは…やめときます。


#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "MIDIData.h"
#pragma comment( lib, "MIDIData.lib" )

// 音符の定義
#define Onpu4  120 // 4分音符の長さ
#define Onpu16  30 // 16分音符の長さ
#define C3 36  // 最低音
#define C8 96  // 最高音
// 楽器の定義
#define Piano   1 // Acoustic Grand Piano

#define  Velocity  100 // 強さ(固定)

// 音高を計算する
int calc_pitch(float xn) {
 // 音高の範囲はC3からC8、xnの範囲は0.0から1.0である
 int pitch = (int)((C8 - C3) * xn) + C3;
 // 計算結果を返す
 return pitch;
}

// タイミングを計算する
int calc_timing(float xn, int end_time, int c_timing) {
 // 曲の範囲はendtime、xnの範囲は0.0から1.0である
 int t = (int)(end_time * xn) + c_timing;
 if (t > end_time) {
  t = t - end_time;
 }
 // 計算結果を返す
 return t;
}

int main()
{
 int i;
 float x; // 現在のxの値
 float xn; // 次のx
 float a;
 FILE *fp;

 int max_note_num; // 出力する音符数
 int N;    // 曲の小節数N

 int note_pitch; // 音高
 int note_timing = 0; // タイミング

 // 音符数と小節数の入力
 printf("音符数を入力してください\n");
 scanf_s("%d", &max_note_num);
 printf("曲の小節数を入力してください\n");
 scanf_s("%d", &N);
 printf("初期値xを入力してください(0~1.0)\n");
 scanf_s("%f", &x);
 printf("変数aの値を入力してください(1.0~4.0)\n");
 scanf_s("%f", &a);

 if (fopen_s(&fp, "function.csv", "w") != 0) {
  printf("ファイルが開けませんでした\n");
  getchar();
  return 0;
 }

 // 曲全体の長さ:4分音符×4個(1小節)×小節数
 int endtime = Onpu4 * 4 * N;

 // MIDIファイルの設定
 MIDIData* pMIDIData;
 MIDITrack* pMIDITrack;
 MIDIEvent* pMIDIEvent;

 // MIDIデータの生成(フォーマット0,トラック数1,TPQNベース,120)
 pMIDIData = MIDIData_Create(
  MIDIDATA_FORMAT0, 1, MIDIDATA_TPQNBASE, 120);
 if (pMIDIData == NULL) {
  printf("MIDIData作成エラー");
  return -1;
 }

 // 最初のトラックへのポインタ
 pMIDITrack = MIDIData_GetFirstTrack(pMIDIData);
 // 各種設定
 MIDITrack_InsertTrackName(pMIDITrack, 0, _T("sample4-4"));  // タイトル
 MIDITrack_InsertTempo(pMIDITrack, 0, 60000000 / 120); // 速度
 MIDITrack_InsertProgramChange(pMIDITrack, 0, 0, Piano); // 楽器(Electric Bass (pick))

 // 音符の数分計算する
 for (i = 0; i < max_note_num; i++) {
  // 音符の音高とタイミングをそれぞれロジスティック写像から決める
  xn = a * x * (1 - x);
  note_pitch = calc_pitch(xn);
  x = xn;

  xn = a * x * (1 - x);
  note_timing = calc_timing(xn, endtime, note_timing);
  x = xn;

  // 音符の書き出し 今はすべて16分音符 、真ん中のドを境に上下2段のピアノ譜に割り当てる
  if(note_pitch >= 60)
   MIDITrack_InsertNote(pMIDITrack, note_timing, 0, note_pitch, Velocity, Onpu16);
  else
   MIDITrack_InsertNote(pMIDITrack, note_timing, 1, note_pitch, Velocity, Onpu16);

 }

 // トラックの終端 トータルの時間も指定する
 MIDITrack_InsertEndofTrack(pMIDITrack, endtime);
 //  MIDIデータとして保存
 MIDIData_SaveAsSMF(pMIDIData, _T("sample4-4.mid"));
 // データの削除
 MIDIData_Delete(pMIDIData);
 pMIDIData = NULL;

 // なにかキーを押すと終了
 getchar();

 fclose(fp);

 return 0;
}