クモのようにコツコツと

フロントエンドエンジニア イイダリョウの技術ブログ。略称「クモコツ」

【React & Tone.js】コードプレイヤーを作った(鍵盤でいろいろなコードを調べるアプリ)

Reactアプリの続きです。前回はTone.jsを使ってビートプレイヤーを作りました。今回も音楽アプリでコードプレイヤーを作りました。以前CodePenで作成したコードプレイヤーをReact/Next環境に移植し、新機能を追加しました。それではいきましょう!

【目次】

※参考:前回記事
【React & Tone.js】ビートプレイヤーを作った(ビートとBPMを変更可能) - クモのようにコツコツと

※参考:【React】ReactでWebアプリを作るシリーズまとめ
qiita.com

作ったもの

コードプレイヤー f:id:idr_zz:20211025061505j:plain

下記のような用途に活用できる。

  • 「根音」で鍵盤から単音を鳴らせる
  • 「三和音」「四和音」「五和音」で和音を鳴らせる
  • 和音の構成音を鍵盤の色や文字情報で調べることができる
  • 和音の種類を変えると同じキーでの構成音の違いを比較できる

作ったアプリはこちら

※参考:コードプレイヤー

アプリの使い方

※参考:このアプリについて | コードプレイヤー

コードタイプ一覧

※参考:コードタイプ一覧 | コードプレイヤー

ソースコード

※参考:GitHub - ryo-i/chord-player: Tone.jsを使ったコードプレイヤー

このアプリで実現したかったこと

以前、こちらのTone.jsを使ってCodePen上に作ったコードプレイヤー

※参考:【Tone.js】和音楽器に五和音(テンションコード)他を追加する - クモのようにコツコツと

※参考:【Web Audio】Tone.jsを習得するためにやったことまとめ(随時更新) - Qiita


これをReact/Next環境で再現したい。前回の配色ジェネレーターと同じく、Nextスターターキットの環境をベースに作成する。

※参考:GitHub - ryo-i/next-app-started

※参考:【React】ReactでWebアプリを作るシリーズまとめ(随時更新) - Qiita

ソースコード

上記の挙動を実現しているソースコードはこちら。

※参考:GitHub - ryo-i/chord-player: Tone.jsを使ったコードプレイヤー

tone.jsのインストール

前回のビートプレイヤーと同じ手順。下記のコマンド

$ npm i tone

※参考:Tone.js

データ:data.json

innerキーの中にコードプレイヤー用のデータ(設定値)を入れている。

"inner": {
      "keys": 
          // 鍵盤の名称
      ,
      "keyButtons": 
          // 鍵盤タグの値
      ,
      "scale": 
          // スケール(音程)の一覧
      ,
      "chordTypes": 
          // コードタイプの一覧
      ,
      "chordTypeButtons": 
          // コードタイプ設定タグの値
    },

CodePen版で直に配列で書いていた設定値をこちらに移動した。また、タグの数が多いのでループで生成するためにタグの設定値もこちらに追加した。


keysキーは鍵盤の名称。このキーを元にコードの構成音を取得する。

      "keys": [
          ["C4"], ["C#4"], ["D4"], ["D#4"], ["E4"], ["F4"], ["F#4"], ["G4"], ["G#4"], ["A4"], ["A#4"], ["B4"], ["C5"]
      ],

keyButtonsキーは鍵盤タグの値。この値をループで読み込んでJSXの鍵盤タグを生成する。

      "keyButtons": [
        {"value": "C4" , "className": "w_key", "keyName": "C", "onClick": true},
        {"value": "C#4" , "className": "b_key" , "keyName": "C#", "onClick": true},
        // 中略
      ],

scaleはスケール(音程)の一覧。コード構成音の番号に該当する音程をここから取得する。

      "scale": [
          "null",
          "C4", "C#4", "D4", "D#4", "E4", "F4", "F#4", "G4", "G#4", "A4", "A#4", "B4",
          "C5", "C#5", "D5", "D#5", "E5", "F5", "F#5", "G5", "G#5", "A5", "A#5", "B5",
          "C6", "C#6", "D6", "D#6", "E6", "F6", "F#6", "G6", "G#6", "A6", "A#6", "B6"
      ],

chordTypesキーはコードタイプの一覧。コードタイプを変更した時にこの情報をページに表示したり、鍵盤を押したときのコード構成音の音程を取得する。

      "chordTypes": [
          {
            "chordValue": "ルート",
            "chordName": "(R)",
            "chordKeys": [1]
          },
          {
            "chordValue": "パワーコード",
            "chordName": "5",
            "chordKeys": [1,8]
          },
         // 中略
      ],

chordTypeButtonsキーはコードタイプ設定タグの値。この値をループで読み込んでJSXのコードタイプ設定タグを生成する。

      "chordTypeButtons": {
        "root": [
          {"id": "chord_R", "value": "ルート", "cohrdTypeName": "(R)", "defaultChecked": true},
          {"id": "chord_5", "value": "パワーコード", "cohrdTypeName": "5"}
        ],
        "triad": [
          {"id": "chord_M", "value": "メジャー", "cohrdTypeName": "(M)"},
          {"id": "chord_m", "value": "マイナー", "cohrdTypeName": "m"},
          // 中略
        ],
        "seventh": [
           {"id": "chord_M7", "value": "メジャー・セブンス", "cohrdTypeName": "M7"},
           {"id": "chord_7", "value": "セブンス", "cohrdTypeName": "7"},
           // 中略
        ],
        "tension": [
           {"id": "chord_M9", "value": "メジャー・ナインス", "cohrdTypeName": "M9"},
           {"id": "chord_9", "value": "ナインス", "cohrdTypeName": "9"},
           // 中略
        ]
      }

※参考:chord-player/data.json at main · ryo-i/chord-player · GitHub

Inner.tsx(全体)

Inner.tsxはコードプレイヤーの本体にあたるファイル

※参考:chord-player/Inner.tsx at main · ryo-i/chord-player · GitHub

全体的な構成はこうなっている。

import React, { useState, useEffect, useRef }  from 'react';
import styled from 'styled-components';
import { inner } from '../data/data.json';
import * as Tone from 'tone';


// CSS in JS
// 中略
const CoadPlayer = styled.div`
  // 中略
`;

// Component
function Inner() {
 // 中略(フック、Tone.js、JSXを設定)
}

export default Inner;
  • reactとフックuseState, useEffect, useRefをインポート
  • CSS in JSstyled-componentsをインポート
  • 設定データdata.jsonからinnerキーをインポート
  • Tone.jstoneをインポート
  • 関数Inner()でInnerコンポーネントを設定(中でフック、Tone.js、JSXを設定)
  • Innerコンポーネントをエクスポート

CoadPlayerコンポーネント(CSS in jS)

変数keyWidthで鍵盤タグの幅を設定(後でcalc()の中で鍵盤数を掛けて鍵盤全体の幅を設定)

const keyWidth = '37px'

CoadPlayerコンポーネントにstyled-componentsによるCSS in JSの設定を書いている。divタグになる。

const CoadPlayer = styled.div`
  color: #fff;
  #key {
    max-width: calc(${keyWidth} * 21);
    margin: 0 auto;
    overflow-x: scroll;
    .key_inner {
      background: #333;
      width: calc(${keyWidth} * 21);
      display: block;
      padding: 0 0 10px;
      position: relative;
      button {
        width: ${keyWidth};
        text-align: center;
        display: inline-block;
      }
       // 中略
  }
`;

CodePenのCSSをSass(SCSS)的な書き方で整理する。

また、ビートプレイヤーの時と同じく全体的に黒背景ベースのスタイルにした。

Innerコンポーネント(全体)

Innerコンポーネントでフック、Tone.js、JSXを設定している。全体的な構成はこうなっている。

// Component
function Inner() {
  // Hooks
  const [synth, setSynth] = useState(null);
  // 他、中略

  // オブジェクト設定
  interface chordTypes {
      // 中略
  };

  interface keyButtons {
      // 中略
  };

  interface chordTypeButtons {
      // 中略
  };


  // シンセ設定
  useEffect(() => {
    // 中略
  },[]);


  // 鍵盤リセット
  const resetKey = (): void => {
    // 中略
  };


  // 鍵盤カレント
  const currentKey = (currentChord): void => {
    // 中略
  };


  // 最新のコード取得
  const getChord = (key: string, chords: string[][]): string[] => {
    // 中略
  };


  // 鍵盤の構成音のテキスト取得
  const chordKeysText = (chord: string[]): string[] => {
    // 中略
  };


  // 鍵盤クリックイベント
  const clickKey = (e: React.MouseEvent<HTMLButtonElement>): void => {
    // 中略
  };


  // コードタイプ取得
  // 中略
  };


  //コード取得
  const getChords = (chordTypes: chordTypes): string[][] => {
    // 中略
  };


  // コード構成音変更
  const changeChordInterval = (currentChords: string[][]): void => {
    // 中略
  };


  //コードタイプ変更イベント
  const chordTypeSelect = (e: React.ChangeEvent<HTMLInputElement>): void => {
    // 中略
  }


  // JSX
  return (
        // 中略
  );
}

フック設定

冒頭でフック設定をしている。

  // Hooks
  const [synth, setSynth] = useState(null);
  const [chords, setChords] = useState(inner.keys);
  const [chord, setChord] = useState(['-']);
  const [rootKey, setRootKey] = useState('-');
  const [chordsInterval, setChordInterval] = useState('-');
  const [chordValue, setChordValue] = useState(inner.chordTypes[0].chordValue);
  const [chordName, setChordName] = useState(inner.chordTypes[0].chordName);
  const [chordKeys, setChordKeys] = useState(inner.chordTypes[0].chordKeys.join(','));
  const keyElement = useRef<HTMLInputElement>(null);
  • synthはシンセ設定。初期値はnull
  • chordsはコード音の設定。初期値はinner(データ)のkeysキー
  • chordはコードタイプの設定。初期値は['-'](配列の中に文字列の-が一つ)
  • rootKeyはルート音設定。初期値は文字列の-
  • chordsIntervalはコードの音程設定。初期値は文字列の-
  • chordValueはコードの日本語名。初期値はinnerの配列chordTypesの一つ目のchordValue
  • chordNameはコードの記号名。初期値はinnerの配列chordTypesの一つ目のchordName
  • chordKeysはコード構成音の番号。初期値はinnerの配列chordTypesの一つ目のchordKeysjoin(',')でカンマ区切りの文字列にしている
  • keyElementuseRefでinputタグを取得。初期値はnull

配列をカンマ区切りにするメソッドjoin()
※参考:[JavaScript] 配列→カンマ区切り文字列にする – コピペで使える JavaScript逆引きリファレンス

ちなみにカンマ区切りの文字を配列にするメソッドはsplit()
※参考:[JavaScript] カンマ区切り文字列→配列にする – コピペで使える JavaScript逆引きリファレンス

useRefの型の書き方
※参考:TypeScriptのもとでuseRefを使うときに知るべきRefObjectとMutableRefObjectについて
useStateの型は任意
※参考:TypeScriptで使うReact hooks | JS Challenge

オブジェクト型設定

今回、TypeScriptの型推論だけでなく自分でもなるべく型をつけていこうと思い、オブジェクト(連想配列)のキーにもinterfaceでオブジェクト型も設定した。

TypeScript型設定の参考
※参考:TypeScriptの型入門 - Qiita
※参考:TypeScript超入門(2):構文を理解する - Qiita

chordTypeskeyButtonschordTypeButtons

  // オブジェクト設定
  interface chordTypes {
    chordValue: string;
    chordName: string;
    chordKeys: number[];
  };


  interface keyButtons {
    value: string;
    className: string;
    onClick: boolean;
    keyName: string;
  };


  interface chordTypeButtons {
    id: string;
    value: string;
    cohrdTypeName: string;
    defaultChecked: boolean;
  };

シンセ設定

シンセ音の設定を初期に一回だけ実行する。これをしないと鍵盤を押すたびにシンセ音が重なってだんだん音が濁る現象が起こった。

※参考:鍵盤を連打するとだんだん音が濁る · Issue #6 · ryo-i/chord-player · GitHub

  // シンセ設定
  useEffect(() => {
    setSynth(new Tone.PolySynth().toDestination());
  },[]);

いろいろ調べた結果、フックsynthuseState()初期値をnullにしつつ、下記のuseEffect()(第二引数が空の配列でページ読み込み時に1回だけ実行)でsetSynth()で設定する方法がうまくいった。

こちらの方法が参考になった!
※参考:JavaScript - Reactで関数を1回だけ実行する

鍵盤リセット

今回、CodePen版にはなかった新機能として和音の構成音にあたる鍵盤の色を変えた。

そのために、別の鍵盤を押したり、コードタイプを実行した時に、このresetKey()関数で鍵盤色を変えるclassを削除して、リセットしている。

  // 鍵盤リセット
  const resetKey = (): void => {
    const keyElements: HTMLCollection = keyElement.current.children;
    for (let i = 0; i < keyElements.length; i++) {
      if (keyElements[i].classList.contains('current')) {
        keyElements[i].classList.remove('current');
      }
    }
  };

関数の戻り値(return)の型はカッコのあとにつけるのだが、戻り値がない関数はvoidをつける。

keyElementuseRefcurrent.childrenプロパティによって子要素を取得できる。

useRefのドキュメント、読んでもいまいちわかりづらかったが
※参考:フック API リファレンス – React
こちらの記事がわかりやすかった
※参考:【useRef】React hookが便利すぎる

class名の存在チェックはcontains、削除はremove
※参考:Element.classList - Web API | MDN

鍵盤カレント

先ほどのresetKey()関数の後に、currentKey()関数で鍵盤リセットの後に、鍵盤の色を変更するclass名を追加する。

  // 鍵盤カレント
  const currentKey = (currentChord): void => {
    const keyElements: HTMLCollection = keyElement.current.children;
    for (let i = 0; i < keyElements.length; i++) {
      const getKeyElement: HTMLButtonElement = keyElements[i] as HTMLButtonElement;
      const keyText: string = getKeyElement.value;
      if (currentChord.includes(keyText)) {
        keyElements[i].classList.add('current');
      }
    }
  };

keyElementの子要素のinputタグの中でvalueが引数のcurrentChordと一致する鍵盤にclass名currentを追加する。

最新のコード取得

鍵盤を押したりコードタイプを変更したときに、その時のルート音の音程に該当するコード構成音を取得する。

  // 最新のコード取得
  const getChord = (key: string, chords: string[][]): string[] => {
    let getCurrentChord: string[];
    for (let i = 0 ; i < chords.length; i++) {
      if (chords[i].indexOf(key) === 0) {
        getCurrentChord = chords[i];
      }
    }
    return getCurrentChord;
  };

配列内の存在チェックの方法はいろいろあるが、今回は配列の1番目との一致を調べたかったのでindexOf()を使った

※参考:JavaScriptで指定した要素が配列に存在するかチェックする方法を現役エンジニアが解説【初心者向け】 | TechAcademyマガジン

鍵盤の構成音のテキスト取得

これも新機能で、ルート音に該当するコード構成音の音程を取得して画面に表示する。

  // 鍵盤の構成音のテキスト取得
  const chordKeysText = (chord: string[]): string[] => {
    let chordKeysText: string[] = [];
    for (let i = 0; i < chord.length; i++) {
      const getChortText: string = chord[i].slice(0, -1);
      chordKeysText.push(getChortText);
    }
    return chordKeysText;
  };

chordの末尾には4など何オクターブ目かを表す数値がついている。この数値はページに表示する際には不要なので、slice()で末尾の一文字を削除した。

※参考:JavaScriptで先頭、末尾の文字を削除する方法

鍵盤クリックイベント

鍵盤を押した時の処理

  // 鍵盤クリックイベント
  const clickKey = (e: React.MouseEvent<HTMLButtonElement>): void => {
    const eventTarget: HTMLButtonElement = e.target as HTMLButtonElement;
    const KeyValue: string = eventTarget.value;
    const getCurrentChord: string[] = getChord(KeyValue, chords);
    setChord(getCurrentChord);
    resetKey();
    currentKey(getCurrentChord);

    const getChordsIntervalsArray: string[] = chordKeysText(getCurrentChord);
    const getRootkey: string = getChordsIntervalsArray[0];
    const getChordsIntervals: string = getChordsIntervalsArray.join(', ');
    setRootKey(getRootkey);
    setChordInterval(getChordsIntervals);

    synth.triggerAttackRelease(getCurrentChord, 0.4);
  };
  • 引数が押した鍵盤のbuttonタグの情報
  • その内容を元にgetChord()を実行しsetChord()にセット
  • 鍵盤色をresetKey()currentKey()で変更
  • chordKeysText()でコード音程のテキストを取得し、setRootKey()にルート音、setChordInterval()にコード音程をセット
  • synth.triggerAttackRelease()でシンセ音を鳴らす。

TypeScriptのイベント系の型
※参考:any型で諦めない React.EventCallback - Qiita
※参考:React + TypeScript: ReactでTypeScriptを使うとき基本として知っておきたいこと - Qiita

「Property 'value' does not exist on type 'EventTarget'.」エラーには「event.target as HTMLElement」と書いたら解決した。
※参考:javascript - Property 'value' does not exist on type EventTarget in TypeScript - Stack Overflow

コードタイプ取得

ここからはコードタイプ変更関係の処理になる。

引数のvalueとマッチするデータのchordTypesの情報を返す処理

  // コードタイプ取得
  const getChordTypes = (getChordValue: string): chordTypes => {
    let getchordTypes: chordTypes;
    for (let i = 0; i < inner.chordTypes.length; i++) {
      if (inner.chordTypes[i].chordValue === getChordValue) {
        getchordTypes = inner.chordTypes[i];
      }
    }
    return getchordTypes;
  };

戻り値の型は先ほどオブジェクト型で設定したchordTypes

コード取得

引数のchordTypesを元にデータのスケールからコードの音程を配列に追加して返す処理

  // コード取得
  const getChords = (chordTypes: chordTypes): string[][] => {
    let getChords: string[][] = [];
    for (let i = 0 ; i < inner.keys.length; i++) {
      getChords.push([]);
      for (var  j = 0; j < chordTypes['chordKeys'].length; j++){
        const key: string = inner.scale[i+chordTypes['chordKeys'][j]];
        getChords[i].push(key);
      }
    }
    return getChords;
  };

多次元配列の型はstring[][]など[]を2つ重ねる
※参考:TypeScriptの複雑な型 - asterisks

コード構成音変更

コード構成音が変わる時の鍵盤のカレントclassと表示されるテキストのフック変更

  // コード構成音変更
  const changeChordInterval = (currentChords: string[][]): void => {
    const getRoot: string = String(chord[0]);
    const getCurrentChord: string[] = getChord(getRoot, currentChords);
    resetKey();
    currentKey(getCurrentChord);

    const getChordsIntervalsArray: string[] = chordKeysText(getCurrentChord);
    const getChordsIntervals: string = getChordsIntervalsArray.join(', ');
    setChordInterval(getChordsIntervals);
  };
  • 引数のcurrentChordsを元にgetChord()で最新のコード取得して該当する鍵盤にclass名を追加
  • chordKeysText()で鍵盤の構成音のテキスト取得し、join()で半角カンマ区切りの文字列に結合してsetChordInterval()にセット

コードタイプ変更イベント

コードタイプ変更のinputタグを押した時のイベント

  // コードタイプ変更イベント
  const chordTypeSelect = (e: React.ChangeEvent<HTMLInputElement>): void => {
    const getChordValue: string = e.target.value;
    const getCurrentChordTypes: chordTypes = getChordTypes(getChordValue);
    setChordValue(getCurrentChordTypes.chordValue);
    setChordName(getCurrentChordTypes.chordName);
    setChordKeys(getCurrentChordTypes.chordKeys.join(', '));

    const getCurrentChords: string[][] = getChords(getCurrentChordTypes);
    setChords(getCurrentChords);
    if (rootKey !== '-') {
      changeChordInterval(getCurrentChords);
    }
  }
  • 引数eは押されたコードタイプ変更のinputタグ
  • eのvalueを元にgetChordTypes()でコードタイプを取得し、その中の値をsetChordValue()setChordName()setChordKeys()にセット
  • getChords()でコードの音程情報を取得しsetChords()にセット
  • ルートのフックrootKey-(初期値)でなければchangeChordInterval()でコード構成音を変更

JSX設定

JSXタグをレンダリング処理

  // JSX
  return (
    <>
      <CoadPlayer>
        <div id="key">
          <div className="key_inner" ref={keyElement}>
            {inner.keyButtons.map((val: keyButtons) =>
              <button key={val.value} value={val.value} className={val.className}
              onClick={val.onClick ? clickKey : null}>{val.keyName}</button>
            )}
          </div>
        </div>
        <div id="chord_type">
          <section id="chord_text">
            <h2 id="chord_type">{chordValue}</h2>
            <p id="chord_keys">構成音: {chordKeys}</p>
            <p id="chord_name">{rootKey}{chordName}: {chordsInterval}</p>
          </section>
          <div id="chord_types">
            <dl id="root">
              <dt>根音</dt>
              <dd>
                {inner.chordTypeButtons.root.map((val: chordTypeButtons) =>
                  <label key={val.id}><input key={val.id} type="radio" id={val.id} name="chord_type" value={val.value} onChange={chordTypeSelect}
                  defaultChecked={val.defaultChecked || null} />{val.cohrdTypeName}</label>
                )}
              </dd>
            </dl>
            <dl id="triad">
              <dt>三和音</dt>
              <dd>
                {inner.chordTypeButtons.triad.map((val: chordTypeButtons) =>
                  <label key={val.id}><input key={val.id} type="radio" id={val.id} name="chord_type" value={val.value} onChange={chordTypeSelect}
                  defaultChecked={val.defaultChecked || null} />{val.cohrdTypeName}</label>
                )}
              </dd>
            </dl>
            <dl id="seventh">
              <dt>四和音</dt>
              <dd>
                {inner.chordTypeButtons.seventh.map((val: chordTypeButtons) =>
                  <label key={val.id}><input key={val.id} type="radio" id={val.id} name="chord_type" value={val.value} onChange={chordTypeSelect}
                  defaultChecked={val.defaultChecked || null} />{val.cohrdTypeName}</label>
                )}
              </dd>
            </dl>
            <dl id="tension">
              <dt>五和音</dt>
              <dd>
                {inner.chordTypeButtons.tension.map((val: chordTypeButtons) =>
                  <label key={val.id}><input key={val.id} type="radio" id={val.id} name="chord_type" value={val.value} onChange={chordTypeSelect}
                  defaultChecked={val.defaultChecked || null} />{val.cohrdTypeName}</label>
                )}
              </dd>
            </dl>
          </div>
        </div>
      </CoadPlayer>
    </>
  );
}
  • CoadPlayerコンポーネントはCSS in JS
  • . key_innerタグのref属性の値keyElementが子要素タグの取得処理に使われる
  • データのinner.keyButtonsからmap()ループで鍵盤のbuttonタグを生成
  • onClickイベントはonClickキーがtrueならclickKeyを、なければnull(音が鳴らない鍵盤)
  • #chord_typesタグ以下ではデータinner.chordTypeButtons以下からタイプによってroottriadseventhtensionオブジェクトからmap()ループでコードタイプ変更のinputタグを生成
  • onChangeイベントにはchordTypeSelectを設定
  • defaultChecked設定はval.defaultCheckedがあれば設定、なければnull

似たような構成のタグが多かったのでmap()でループして生成
※参考:【React】ループの書き方(for文エラー回避、配列、map()) - クモのようにコツコツと

マップの引数valには冒頭で設定したオブジェクト型keyButtons(鍵盤)、chordTypeButtons(コードタイプ設定)を設定している

条件によってあったりなかったりする属性は三項演算子や論理演算子||で分岐処理
※参考:【React】条件分岐の書き方(if文エラー回避、論理演算子、三項演算子) - クモのようにコツコツと

鍵盤のref属性は子要素取得するためにuseRefと連携して使う
※参考:Ref と DOM – React

リポジトリ名の変更→Vercelに反映

CodePen版の中にあるコードの綴りがかなりの部分が「cord」になっており、ただしくは「chord」なので置換する必要があった。

和音(わおん、英語: chord(コード)、独: Akkord)

※参考:和音 - Wikipedia


そしてリポジトリ名自体も「cord」になっていたので、リポジトリ名の変更を行なった。

リポジトリの変更方法
※参考:[https://docs.github.com/ja/github/administering-a-repository/managing-repository-settings/renaming-a-repository GitHubのリポジトリ名変更方法 - Qiita]

まずGitHub上のリポジトリ名をリネイムし、次にローカルのリポジトリURLを変更

$ git remote set-url origin https://github.com/ryo-i/chord-player

configファイルのremote "origin"のurlが変わった。


リポジトリ名変更後にVercelへのデプロイがどうなるか
※参考:GibHub でリポジトリの名前を変更する · GitHub

Vercelのプロジェクト内にProject Settingsというページがあり、そこでプロジェクト名を「chord-player」に変更してみるが、下記のデプロイエラーになった

Failed to assign a domain to your deployment due to the following error: Aliasing the Deployment Timed Out

「次のエラーのため、デプロイメントにドメインを割り当てることができませんでした。 展開のエイリアスがタイムアウトしました」

Vercelのプロジェクト内のSettingsのdomainsでドメインも変更してみたがうまくいかず。


デプロイがうまくされないため、新プロジェクトを作ることにする。旧プロジェクトは「-bk」付きに再度リネイムした。

Vercelで新規プロジェクトを作成してデプロイうまくいったが、「-bk」付きの方も二重でデプロイされる。こちらのGitHubとの連携は解除したところ、新プロジェクトのみにデプロイされるようになった!

※参考:リポジトリ名を修正(cord-player -> chord-player) · Issue #4 · ryo-i/chord-player · GitHub

今後の課題

本アプリで聴けるコードは根音(ルート)の上に和音の構成音を重ねる配置だが、実際の音楽のアレンジでは和音の構成音を前後のオクターブに配置する「ボイシング」が行われることが多い。

コードチェンジの移動をなるべく少なくするために1オクターブ内で構成音の配置を変えるクローズドボイシング、両手を使って構成音が1オクターブ以上に広がった響きにするオープンボイシングがある。

ボイシングの種類やそれを実現する処理の検討はまだ検討できていないため、今後の課題としたい。

あと、今は「ジャーン」と和音を同時に鳴らしていますが、この他に「タ・ラ・ラ・ラーン、ジャーン」みたいな一音ずつ聴けるモードが必要なのか検討している。

今のメニュー数がSPの1画面に収まっているので、機能追加によってボタンが増えするのも考えものかという気持ちもある。。

最後に

ということでコードプレイヤーが完成しました。今回は、CodePen時代にはなかった新機能として、鍵盤にコード構成音の色をつけたり、ルート音が変わったときの音程をテキストで表示することができました。これによって、構成音が視覚的にもわかりやすくなたっと思います!

ピアノの白鍵黒鍵はCメジャースケールがベースになっているため、ルートが変わると黒鍵白鍵の組み合わせが変わるところに難しさを感じていました。このアプリでコードの理解のわかりやすさにつながるといいなと思います。

次は音楽編の第三弾、「スケールプレイヤー」を作りたく思います!このコードプレイヤーをベースに改造すれば作れそうな気がしています。スケールもキーが変わると白鍵黒鍵の組み合わせが変わるため、そこが視覚的にわかるといいなと思います。

スケールプレイヤーができると音楽の三要素「メロディ、ハーモニー、リズム」が揃うことになります♪それではまた!


※参考:【React】ReactでWebアプリを作るシリーズまとめ
qiita.com