プロトタイプ編 で、作ったアプリケーション内のコードですが
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';
の箇所があまりにもベタなので、配列を使って書き直すのと、ついでにオクターブに関する処理も加えてみた
画面の変更点
- 鍵盤の両端にオクターブを操作するためのボタンを追加
- 現在どの音程のところにいるかを表示するボックスを追加(0 が低音、1 が通常、2 が高音)
コードの変更点
- 音階の配列と、ヘルツの配列を設定して、Form.Create のタイミングで初期化するようにした
- 音階のキーの配列の添え字と、ヘルツの配列の添え字を対応させておく
- for ループで配列内を操作して合致した添え字のヘルツを取り出すという仕組みに変更
- 音階の配列は 3 種類用意して現在の音程で切り替えている
配列と for ループを使うと、ベタで書いていた箇所がスッキリ!
for I := 0 to 11 do begin
if Kenban = octave[i] then Hz := Hz1[i];
end;
オクターブ処理編の全体のコードはこちら
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; // C-ド
Button2: TButton; // C# - ド#
Button3: TButton; // D - レ
Button4: TButton; // D# - レ#
Button5: TButton; // E - ミ
Button6: TButton; // F - ファ
Button7: TButton; // F# - ファ#
Button8: TButton; // G - ソ
Button9: TButton; // G# - ソ#
Button10: TButton; // A - ラ
Button11: TButton; // A# - ラ#
Button12: TButton; // B - シ
Label1: TLabel;
NumberBox1: TNumberBox; // Tempo
Button13: TButton; // Low
Button14: TButton; // High
NumberBox2: TNumberBox; // Octave
Label2: TLabel;
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);
procedure FormCreate(Sender: TObject);
procedure Button13Click(Sender: TObject);
procedure Button14Click(Sender: TObject);
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;
Octave_sw: Integer;
Hz0, Hz1, Hz2: array of string;
octave: array of string;
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
{ TForm1 }
procedure TForm1.Button13Click(Sender: TObject);
begin
Octave_sw := Octave_sw -1;
if Octave_sw <= 0 then Octave_sw := 0; // 0 以下は 0
NumberBox2.Value := Octave_sw;
end;
procedure TForm1.Button14Click(Sender: TObject);
begin
Octave_sw := Octave_sw + 1;
if Octave_sw >= 2 then Octave_sw := 2; // 2 以上は 2
NumberBox2.Value := Octave_sw;
end;
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.FormCreate(Sender: TObject);
begin
// 初期値設定
Octave_sw := 1;
SetLength(Hz0, 12);
SetLength(Hz1, 12);
SetLength(Hz2, 12);
SetLength(octave, 12);
Hz0 := ['131','139','147','165','156','175','185','196','208','220','233','247'];
Hz1 := ['262','277','294','311','330','349','370','392','415','440','466','494'];
Hz2 := ['523','554','587','622','659','698','740','784','831','880','932','988'];
octave := ['C','C#','D','D#','E','F','F#','G','G#','A','A#','B'];
end;
procedure TForm1.FormShow(Sender: TObject);
begin
generate_setTempo; // 最初に tempo(120) の文字列を生成
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;
I: Integer;
begin
if Octave_sw = 0 then
begin
for I := 0 to 11 do begin
if Kenban = octave[i] then Hz := Hz0[i];
end;
end else if Octave_sw = 1 then
begin
for I := 0 to 11 do begin
if Kenban = octave[i] then Hz := Hz1[i];
end;
end else begin
for I := 0 to 11 do begin
if Kenban = octave[i] then Hz := Hz2[i];
end;
end;
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.
あとがき
これで結構個人的には十分だったりします
単音ですが 1 曲分のコード書きがさくさくできます
そして、残りは休符のロジックの実装です