LoginSignup
2
0

More than 5 years have passed since last update.

Delphi で micro:bit の音階コードを生成してみた (プロトタイプ編)

Posted at

micro:bit で、自分の好きな曲を演奏するには
mb04.png
な感じにコツコツと楽譜を入力しないとならぬ
拍数なども試し試しで入力するのである

個人的には、鍵盤をつかって演奏したら、演奏したイメージでコードを生成して欲しいというワガママがむくむくと
じゃ Delphi で作ってみるべと思うのである

下調べ

どのようなコードが生成されているか、入力すべき値などを確認する

生成するべき JavaScript のコードを確認する

上記の scrach ベースのコードを JavaScript で確認すると

   music.setTempo(120)  --> テンポの設定 120bpm
   music.playTone(262, music.beat(BeatFraction.Half)) --> 真ん中のド 1/2
   music.playTone(330, music.beat(BeatFraction.Half)) -->  
   music.playTone(349, music.beat(BeatFraction.Half)) --> ファ
   music.playTone(392, music.beat(BeatFraction.Whole)) -->  1
   music.rest(music.beat(BeatFraction.Quater))  --> 休符 1/4

となる

音符のヘルツを確認する

playtone で指定されるのは音符のヘルツ(四捨五入)の値なので、ヘルツの値を確認した
C0 は 低いド、C1 は真ん中のド、C2 は高いドを表しています。

音階 C0 C0# D0 D0# E0 F0 F0# G0 G0# A0 A0# B0
ヘルツ 131 139 147 165 156 175 185 196 208 220 233 247
音階 C1 C1# D1 D1# E1 F1 F1# G1 G1# A1 A1# B1
ヘルツ 262 277 294 311 330 349 370 392 415 440 466 494
音階 C2 C2# D2 D2# E2 F2 F2# G2 G2# A2 A2# B2
ヘルツ 523 554 587 622 659 698 740 784 831 880 932 988

拍数の記述を確認する

BeatFreaction で指定できる拍数は 1, 1/2, 1/4, 1/8, 1/16, 2, 4 でそれぞれの記述を確認した

拍数 記述
1 Whole
1/2 Half
1/4 Quarter
1/8 Eighth
1/16 Sixteenth
2 Double
4 Breve

テンポと拍数と秒数の関係を確かめる

60bpm のときの 1 泊は 1 秒
120bpm のときの 1 拍は 0.5 秒
指定可能なテンポの値は 4bpm から 400bpm の間 (デフォルト 120bpm)

となると ミリ秒で差を出して 1 秒 =1000 ミリ秒なので 1000 で割って、基本の 60bpm をかけて、設定されている bpm で割るで計算あってるかな?
1000 (1秒) / 1000 * 60 だと 60 になるから 60 bpm のときは 1 だし、120 bpm は 0.5 になるから OK (のはず)

Delphi で作ってみる

といっても唐突には作れないので、仕様を決める

作るアプリケーションの仕様を考える

  • 初期バージョンなので、曲の途中ではテンポを変えない
  • テンポは最初に決定する
  • 鍵盤は1オクターブ分だけ用意する
  • オクターブの高低はスイッチ的な要素で決定する
  • 鍵盤を押している間の時間で拍数を算出する
  • 鍵盤を離して次の鍵盤を押すまでの間が 1/16 拍以上であれば休符を入れる
  • 和音は考えない
  • 生成したコードは画面上でコピーして micro:bit のエディタにペーストができればいい(自分しか使わないから)

実際に作ってみた

今回はプロトタイプなので、あくまで鍵盤のキーと拍数がそこそこ合っていて、文字列が生成できればよい
今回はプロトタイプなので休符とオクターブの高低は考えていない
今回はベタの if 文で判定した
ボタンの操作は同じなので Button1MouseUp / Button1MouseDown にすべてのボタンの処理を集約し、ボタンの種類は TButton(sender).Text; で判断(Cとか C#とかの文字列が入ります)

できあがったプロトタイプ画面

music01.png

コードはこちら

// プロトタイプなのでエラーなどは全く考慮していないベタな感じで書いてます

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Edit,
  FMX.EditBox, FMX.NumberBox, FMX.StdCtrls, FMX.Controls.Presentation,
  FMX.ScrollBox, FMX.Memo, FMX.Layouts, System.Math, System.DateUtils;

type
  TForm1 = class(TForm)
    Layout1: TLayout;
    Layout2: TLayout;
    Memo1: TMemo;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    Button6: TButton;
    Button7: TButton;
    Button8: TButton;
    Button9: TButton;
    Button10: TButton;
    Button11: TButton;
    Button12: TButton;
    Label1: TLabel;
    NumberBox1: TNumberBox;
    procedure NumberBox1Change(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure Button1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Single);
    procedure Button1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Single);
  private
    { private 宣言 }
    const setTempo = 'music.setTempo(';
    const playTone = 'music.playTone(';
    const rest = 'music.rest(';
    const beat = 'music.beat(';

    const whole = 'BeatFraction.Whole';
    const half = 'BeatFraction.Half';
    const quarter = 'BeatFraction.Quarter';
    const Eighth = 'BeatFraction.Eighth';
    const Sixteenth = 'BeatFraction.Sixteenth';
    const B_Double = 'BeatFraction.Double';
    const Breve = 'BeatFraction.Breve';

    const e_1 = ')';
    const e_2 = '))';

    procedure generate_setTempo;
    procedure generate_playTone;
    procedure generate_rest;

  public
    { public 宣言 }
    timeCount: Double;
    StartTime, EndTime: TDateTime;
    Kenban, Hz, Haku: string;
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

{ TForm1 }

procedure TForm1.Button1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Single);
begin
  StartTime := Now;
  EndTime := 0;
  Kenban := TButton(sender).Text;
end;

procedure TForm1.Button1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Single);
begin
  EndTime := Now;
  timeCount := ((MilliSecondsBetween(EndTime, StartTime) / 1000) * 60) / NumberBox1.Value;
  generate_playTone;
  StartTime := 0;
end;

procedure TForm1.FormShow(Sender: TObject);
begin
  generate_setTempo;
end;

procedure TForm1.generate_setTempo;
var
  javaStrings: string;
begin
  javaStrings := setTempo + NumberBox1.Text + e_1;
  Memo1.Lines.Add(javaStrings);
end;

procedure TForm1.generate_playTone;
var
  javaString: string;
  cnt: double;
begin
  if Kenban = 'C' then Hz := '262';
  if Kenban = 'C#'then Hz := '277';
  if Kenban = 'D' then HZ := '294';
  if Kenban = 'D#'then HZ := '311';
  if Kenban = 'E' then Hz := '330';
  if Kenban = 'F' then Hz := '349';
  if Kenban = 'F#'then Hz := '370';
  if Kenban = 'G' then Hz := '392';
  if Kenban = 'G#'then Hz := '415';
  if Kenban = 'A' then Hz := '440';
  if Kenban = 'A#'then Hz := '466';
  if Kenban = 'B' then Hz := '494';

  cnt := Roundto(timeCount, -2);

  if cnt <= (1/16) then haku := Sixteenth;
  if (cnt <= (1/8)) and (cnt > (1/16)) then haku := Eighth;
  if (cnt <= (1/4)) and (cnt > (1/8)) then haku := quarter;
  if (cnt <= (1/2)) and (cnt > (1/4)) then haku := half;
  if (cnt <= 1) and (cnt > (1/2)) then haku := whole;
  if (cnt <= 2) and (cnt > 1) then haku := B_Double;
  if cnt > 2 then haku := Breve;

  javaString := playTone + Hz + ', ' + beat + haku + e_2;
  Memo1.Lines.Add(javaString);
end;

procedure TForm1.generate_rest;
var
  javaString: string;
begin
  javaString := rest + beat + half + e_2;
  Memo1.Lines.Add(javaString)
end;

procedure TForm1.NumberBox1Change(Sender: TObject);
begin
  generate_setTempo;
end;

end.

あとがき

プロトタイプだけど、micro:bit側での操作は恐ろしく楽になった
もうちょっとスマートに書くのと、鍵盤をそれらしく表現して完成させるのは次回

しかし、こんな拡張ボードがあったのか....これは直接演奏するときですが、音源を作りたいのよね
https://www.switch-science.com/catalog/4030/

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0