});
@@ -122,10 +124,6 @@ export const PianoRoll: React.FunctionComponent<{
/**
* 入力領域の音程を表す平行線のSVG要素。
* 音程ごと、1オクターブごとに色分けして区切る。
- *
- * path の d は以下の構文を取り、SVG上で直線を表現する。
- * d="M {x1} {y1} L {x2} {y2}"
- * 上記のように指定すると、起点(x1y1)から終点(x2y2)に線を引く。
*/
const xLineElements = () => {
const elements = [];
diff --git a/src/typescript/component/tracks/track-panel.tsx b/src/typescript/component/tracks/track-panel.tsx
index 2e0a287..5a3612a 100644
--- a/src/typescript/component/tracks/track-panel.tsx
+++ b/src/typescript/component/tracks/track-panel.tsx
@@ -10,7 +10,7 @@ export const TrackPanel: React.FunctionComponent<{track: Track}> = (props) => {
- {props.track.getName}
+ {props.track.name}
diff --git a/src/typescript/component/tracks/track-panels.tsx b/src/typescript/component/tracks/track-panels.tsx
index d0844d8..bea82ad 100644
--- a/src/typescript/component/tracks/track-panels.tsx
+++ b/src/typescript/component/tracks/track-panels.tsx
@@ -6,7 +6,7 @@ import { TrackPanel } from './track-panel';
export const TrackPanels: React.FunctionComponent<{tracks: Tracks}> = (props) => {
return (
- {props.tracks.asList.map(track => )}
+ {props.tracks.tracks.map(track => )}
);
}
\ No newline at end of file
diff --git a/src/typescript/domain/track.ts b/src/typescript/domain/track.ts
index 5376463..3556f9b 100644
--- a/src/typescript/domain/track.ts
+++ b/src/typescript/domain/track.ts
@@ -1,44 +1,78 @@
+import { Message } from "./message";
+
export default class Track {
- private no: number;
- private name: string;
- private instrumentId: number;
- private sequenseId: number;
+ no: number;
+ name: string;
+ instrumentId: number = 0; // TODO: GUIから選択できるようにする。
+ messages: Message[] = [];
- constructor(no: number){
- this.no = no;
- this.name = `track${no}`;
+ // TODO: conductorTrack(), instrumentalTrack() の用途が限定的なため、Tracks.default() に処理を移動する
+ static conductorTrack(): Track{
+ const track = new Track(0, `Conductor Track`, 0, []);
+
+ return track;
}
- public get getNo(): number{
- return this.no;
+
+ static instrumentalTrack(no: number): Track{
+ if(no === 0){
+ throw new Error("Track No.0 is used as Conductor Track.");
+ }
+
+ const track = new Track(no, `Track${no}`, 0, []);
+ return track;
}
- public get getName(): string{
- return this.name;
+
+ constructor(no: number, name: string, instrumentId: number, messages: Message[]){
+ this.no = no;
+ this.name = name;
+ this.instrumentId = instrumentId;
+ this.messages = messages;
}
+
+ addMessage(message: Message): void {
+ this.messages.push(message);
+ }
+
}
export class Tracks {
- private tracks: Track[];
+ tracks: Track[];
+
constructor(tracks: Track[]){
this.tracks = tracks;
}
- public static empty(): Tracks {
+
+ static empty(): Tracks {
return new Tracks([]);
}
- public static default(): Tracks {
- let tracks = this.empty();
+
+ static default(): Tracks {
+ const tracks = [];
+
+ tracks.push(Track.conductorTrack());
for(let idx = 1; idx <= 16; idx++){
- tracks.add(tracks.size + 1);
+ const track = Track.instrumentalTrack(idx);
+ tracks.push(track);
}
- return tracks;
+
+ return new Tracks(tracks);
}
- public add(no: number): void {
- const track = new Track(no);
+
+ add(no: number): void {
+ const track = Track.instrumentalTrack(no);
this.tracks.push(track);
}
- public get asList(): Track[]{
- return this.tracks;
+
+ get(no: number): Track {
+ if(no > this.tracks.length){
+ throw new Error("OutOfRangeError.");
+ }
+
+ return this.tracks[no];
}
- public get size(): number {
- return this.tracks.length;
+
+ addMessage(idx: number, message: Message): void {
+ const track = this.get(idx);
+ track.addMessage(message);
}
}
\ No newline at end of file
diff --git a/src/typescript/layout.tsx b/src/typescript/layout.tsx
index 112342c..2589844 100644
--- a/src/typescript/layout.tsx
+++ b/src/typescript/layout.tsx
@@ -1,45 +1,52 @@
import * as React from 'react';
+import { Container } from 'react-bootstrap';
+import clone from "clone";
import { Header } from './component/header/header';
-import { Tracks } from './domain/track';
import { TrackPanels } from './component/tracks/track-panels';
-import { Container } from 'react-bootstrap';
-import { PIANO_ROLLE_HEIGHT, PianoRoll } from './component/piano-roll/piano-roll';
-import NoteOnMessage from './domain/message';
import { PianoKey } from './component/piano-roll/piano-key';
+import { PianoRoll } from './component/piano-roll/piano-roll';
+import NoteOnMessage from './domain/message';
+import { Tracks } from './domain/track';
export const Layout: React.FunctionComponent<{}> = (props) => {
+ /** 現在選択しているMIDI出力ポート。 */
+ const [port, setPort] = React.useState('');
+
/** 現在開いているMIDIファイル。 */
const [file, setFile] = React.useState();
- /** シーケンサーで入力したノートオンメッセージのリスト。 */
- const [messages, setMessages] = React.useState([]);
-
- /** シーケンサーに設定済みのMIDI出力ポート。 */
- const [port, setPort] = React.useState('');
+ /** 現在選択しているトラックの番号。 */
+ const [trackIdx, setTrackIdx] = React.useState(0);
- /** シーケンサーで設定したトラックのリスト。 */
- const tracks: Tracks = Tracks.default();
+ /** トラックのリスト。 */
+ const [tracks, setTracks]= React.useState(Tracks.default());
- /** ノートオンメッセージのリストに要素を追加する。 */
+ /** 現在選択しているトラックにノートオンメッセージを追加する。 */
const addMessage = (message: NoteOnMessage) => {
- setMessages(messages.concat(message));
+ const newTracks: Tracks = clone(tracks);
+ newTracks.addMessage(trackIdx, message);
+ setTracks(newTracks);
+ }
+
+ const selectTrack = (targetIdx) => {
+ setTrackIdx(targetIdx);
}
return (
setFile(file)}
setPort={(port: string) => setPort(port)}
- setMessage={(messages: []) => setMessages(messages)}
+ setTracks={(tracks: Tracks) => setTracks(tracks)}
/>
addMessage(message)}
/>
diff --git a/src/typescript/repository/repository.ts b/src/typescript/repository/repository.ts
index f7c3ac0..32c4c67 100644
--- a/src/typescript/repository/repository.ts
+++ b/src/typescript/repository/repository.ts
@@ -1,5 +1,6 @@
import axios, { ResponseType } from "axios";
import NoteOnMessage from "../domain/message";
+import Track, { Tracks } from "../domain/track";
// TODO: FQDNを共通化する
@@ -22,8 +23,8 @@ export const saveAndDownload = (messages: NoteOnMessage[], filename: string) =>
})
}
-export const play = (messages: NoteOnMessage[], portName: string) => {
- const data = {messages: messages, portName: portName};
+export const play = (portName: string, tracks: Tracks) => {
+ const data = {tracks: tracks.tracks, portName: portName};
axios.post('http://localhost:8000/v1.0/player', data)
.then((response) => console.log(response))
.catch((error) => console.log(error));
@@ -39,10 +40,16 @@ export const uploadFile = async (file: File) => {
formData.set("file", blob, file.name);
const response = await axios.post('http://localhost:8000/v1.0/upload', formData);
- return response.data.map(
- message => new NoteOnMessage(
- message.noteNumber, message.startedAt, message.velocity, message.tick)
+ // TODO: TS側のオブジェクトに変換する処理のリファクタ
+ const tracks = response.data.map(
+ track => {
+ const messages = track.messages.map(message =>
+ new NoteOnMessage(message.noteNumber, message.startedAt, message.velocity, message.tick));
+
+ return new Track(track.no, track.name, track.instrumentId, messages)
+ }
);
+ return new Tracks(tracks);
}
export const selectFile = () => {