musicLineアプリ開発日記

作曲を誰でも楽しく簡単に♪

【iOS】進捗報告 13(リピートフレーズ)

musicLine(iOS)についての進捗。
今回はリピートフレーズやiOSリリースまでの進捗を報告します。

リピートフレーズ


実装状況

カテゴリタイトル補足
View
Splash
アプリ起動画面
背景デザイン星の輝き、テキストロゴ
コミュニティボタンアプリ起動からコミュニティへクイックアクセスするためのボタン
画面遷移作曲画面とコミュニティ画面を遷移する役割
ファイルから起動ファイルマネージャで曲データを選択して、アプリを起動 (iOS独自)
Composition
UI配置
ガイド表示
リピートフレーズリピートフレーズデザイン・同期解除ボタン、リピートタブ、リピートハンドル (iOS独自)
再生モード追従、リピート、ページ送りへ切り替え
ナビゲーションパネル登録した小節数へジャンプする、適切な音域へジャンプする (iOS独自)
Common
ダイアログ
設定設定項目を表示、グループの開閉
アカウントFirebaseAuthとの連携でログインUI表示、プレミアムリング
トースト表示曲保存時などに画面下に情報を表示
Composition
PhraseTool
フレーズツール
フレーズの編集
リピートフレーズデータ構造、リピート変更時のフレーズの同期、上書きフレーズの把握
フレーズ同期解除同期解除でフレーズを複製・配置(iOS独自)
リピート回数設定フレーズダイアログから指定、サブ編集エリアからドラッグで変更(iOS独自)、状況によって回数制限
リピートフレーズ移動リピートフレーズ移動する時は、リピートフレーズに乗っている上書きフレーズも一緒に移動
Commnity
Service
サービスモデル
通知いいねやコメントもらった時の通知バナー表示、通知権限許可
Common
Manager
管理シングルトン
アカウントいいねやお気に入りの同期、プレミアムユーザーの管理
プレミアム機能プレミアムユーザーかプレミアムスターを使用時にプレミアム機能の有効を管理
多言語対応日本語、韓国語、中国語(繁体語)、英語に対応
広告バナー広告、レクタングル広告、全画面広告


全進捗マップを表示

カテゴリタイトル補足
View
Splash
アプリ起動画面
背景デザイン星の輝き、テキストロゴ
コミュニティボタンアプリ起動からコミュニティへクイックアクセスするためのボタン
画面遷移作曲画面とコミュニティ画面を遷移する役割
ファイルから起動ファイルマネージャで曲データを選択して、アプリを起動 (iOS独自)
Composition
UI配置
ガイド表示
ピアノ
スクロールエリア
小節番号
小節線
分割線拡大率によって間隔を変化
フレーズフレーズがないところはフレーズ作成ボタンを表示
ツールボタン 選択中のツールはツール色にハイライトする
メロディーライン ペンツールでの音符作成時の入力線
メロディー音符 音符の先頭にチョボをつける
リズム音符 ベース音符のみ下に表示
サンプルデータ 手入力したサンプルデータの音符を配置
連符連符は数字で表示、拡大率によって省略
ペンツールガイド長さ編集しているリズム音符、伸ばした時の削る範囲
(ドラム) 左にスワイプしている時、削除する範囲
指ツールガイド移動中の音符影、矩形選択の枠
(ドラム) 長さ編集している時、伸ばし線(iOS独自)。矩形選択の範囲
消しゴムツールガイド削除範囲、和音のみの削除範囲
(ドラム) 削除範囲
フレーズツールガイドフレーズ移動・伸縮のバー、選択範囲テキスト(iOS独自)
フレーズボタンフレーズボタンとサブボタンを配置、ツールに応じてアイコンを変更、画面拡大率に応じて縮小
フレーズタブツールに応じてアイコンを変更、拡大率に応じて縮小、スクロール状態に応じて移動
音符描画の高速化音符が多くても描画できる速さへ最適化
音符の編集状態選択や変更した時に枠線の色変更
音符音階メロディ音符に音階表示
再生バー曲を再生している時に、再生位置をバーで表示
再生ボタン曲を再生/停止を監視して、状態を変更、再生準備が遅い時はインジケーターを表示
再生速度の表示曲の再生速度を表示(iOS独自)
テスト音のガイド鳴っている音階に色をつける
ドラム音符音符と連符の表示。分割線に乗っていない音符は細く表示(iOS独自)
ドラム盤ピアノ鍵盤の位置にドラムセットを表示
伴奏音符音符/休符と連符の表示。細かい連符は省略して表示
ペンツールガイド(伴奏) 移動してる時、移動影。左にスワイプしている時、削除する範囲。長さ編集している時、伸ばし線
指ツールガイド(伴奏) 移動してる時、移動影と上書き音符に光。長さ編集している時、伸ばし線。矩形選択の範囲
消しゴムツールガイド(伴奏) 削除範囲
リピートフレーズリピートフレーズデザイン・同期解除ボタン、リピートタブ、リピートハンドル (iOS独自)
再生モード追従、リピート、ページ送りへ切り替え
ナビゲーションパネル登録した小節数へジャンプする、適切な音域へジャンプする (iOS独自)
Composition
ダイアログ
フレーズフレーズの作成・設定・挿入、フレーズの長さやリピート回数の設定
曲設定タイトル・テンポ、キー等の曲の設定
トラック選択編集トラックの変更・追加/削除、ボリュームやミュート等の設定
楽器選択トラックの使用楽器変更、楽器のランダム選択・選択リセット(iOS独自)
ドラム楽器一覧使用ドラム楽器をリスト表示。使用楽器の編集や並び替え(iOS独自)
ドラム楽器設定ドラム楽器の音量調整・ミュート、削除・複製
ドラム楽器選択トラックの使用ドラム楽器変更、楽器のランダム選択・選択リセット(iOS独自)
スライドメニューアイコンタップで作曲画面を右にスライドしてメニューを表示アカウントとお問い合わせは未着手
設定設定項目を表示
曲の読み込みDB参照して曲の一覧を表示。検索と 並び替え(iOS独自)
曲の概要曲の概要を表示
バックアップ一覧フォルダ内のファイル確認して、曲のバックアップと定期バックアップの一覧を表示。検索と並び替え(iOS独自)
ハーモニー音符和音の位置と長さ、ディグリーやボイシングNo等の情報を表示
ハーモニーガイド和音を編集する時、必要な情報を表示
Community
(共通)
UI配置
コミュニティディスプレイとコントローラーを表示。縦持ちと横持ちのレイアウト。どのディスプレイ、コントローラーを使用するかは各コミュニティ画面で派生
カテゴリーリスト群カテゴリー選択、カテゴリーリストを表示。どのカテゴリーリストを表示するかは各コミュニティ画面で派生
ページスクロールリストを表示。スワイプでリスト項目を取得。どのリスト項目を使用するかは各カテゴリーで派生
曲リスト項目各コミュニティ画面で派生系を用意する
リレー曲リスト項目左右にスワイプで前後走者の曲を表示
その他リスト項目曲ID:検索で曲ID一覧を表示、ユーザー:ユーザー検索やいいねリスト等で表示
曲詳細曲の情報と貰ったコメントを表示、送るコメントを編集する
曲の情報曲のタイトル、作者、ランキング順位、タグ、ユーザーの反応等を表示
貰ったコメントテキストとOGP特殊コメントの装飾
ソングビジュア曲再生位置の変更と可視化。曲情報でトロフィー変更。リスト/詳細ボタンで切り替え。シンプルのみ実装でリリース後に追加予定。
カテゴリー選択カテゴリータブ表示。スクロール可能。選択表示。
ユーザーアイコンユーザー画像、プレミアムリングを表示。タップでユーザーページへ
プレイヤー曲の再生、いいね・お気に入り等のボタン。現在の状況を反映再生リスト追加ボタン
設定パネルレイアウト設定、ソングビジュア設定、楽器フィルタ リリース後に実装予定
Community
Square
コミュニティ広場
UI配置
ディスプレイ状況によりカテゴリー説明/ソングビジュアを切り替え。
カテゴリー説明広場カテゴリーの説明
コントローラーカテゴリーリスト群/曲詳細を切り替え
カテゴリーリスト群Squareのカテゴリーリストを切り替えるように派生
リスト項目カテゴリー別にリスト項目を派生(ランキングなら左にランク情報)。コンテスト項目はタップでコンテスト画面へ
イベント詳細コンテストの詳細情報の表示
絞り込み検索
Community
UserPage
ユーザーページ
UI配置
ディスプレイユーザープロフィールを表示。下へスワイプした時に隠れてヘッダーが表示されるように
ユーザープロフィールユーザー情報、紹介文、アクティビティログ等表示
ユーザー情報名前、アイコン、リンクリスト、フォロー欄、紹介文表示
リンクリスト外部リンク(X等)ボタンを並べる
フォロー欄フォロー、ミュート、通知ボタン
アクティビティログ活動レベル、投稿曲数やいいね数など表示
ヘッダー
コントローラーディスプレイに追従
カテゴリーリスト群UserPageのカテゴリーリストを切り替えるように派生
リスト項目開閉するプレイリスト項目を作成。
Community
Contest
コンテスト結果
UI配置
ディスプレイ状況によりコンテスト概要/ソングビジュアを切り替え。
コンテスト概要コンテストのテーマ、内容、提案者の表示
コントローラーカテゴリーリスト群/曲詳細を切り替え
カテゴリーリスト群Contestのカテゴリーリストを切り替えるように派生
リスト項目コンテストの順位や自分の投票数を表示するリスト項目に派生
Community
ダイアログ
リストダイアログいいね・お気に入りをしたユーザーリスト表示、曲を含む再生リストの表示
メッセージアラート通知するテキストを知らせる(DLした時や削除確認など)
プロフィール編集名前、アイコン、紹介文等を編集
プレイリスト詳細プレイリストのタイトル、説明、作者、コメント等を表示
プレイリスト編集タイトル、アイコン、曲リスト等を編集
コンテスト投票開催コンテスト曲の視聴と投票
MIDI詳細曲のテンポ、音符・トラック数、使用楽器等
Common
ダイアログ
アラートメッセージユーザーに通知するコメント
数字ピッカー数字(範囲制限)をポップアップダイアルで取得
項目ピッカー特定の値をポップアップのリスト項目で取得
HTMLテキストテキストスタイルを部分的に変えるため、HTML形式に対応したText
文字制限テキスト編集文字制限付きのTextField、制限文字数を超えは赤文字で閉じる時に切り捨て
全画面テキスト編集複数行のテキストを編集する時に、ポップアップ全画面でTextEditorとキーボード表示
FitScrollView閾値高さで スクロールありorなしを切り替える(画面に収まるときはScrollViewにしない)
WheelMenuPicker値をタップすると選択肢が表示されて値を変更、値をスワイプするとホイールで素早く変更
設定設定項目を表示、グループの開閉
アカウントFirebaseAuthとの連携でログインUI表示、プレミアムリング
トースト表示曲保存時などに画面下に情報を表示
Composition
Common
作曲共通
データ構造座標とサイズ、状態を保持する。レンダラーやコライダー、通知等のロジック
コンバーターDomainのデータ構造へ変換・逆変換
通知機構Modelに変更があった時に、Viewへ通知して再描画。変更状況を監視してキャッシュ
Changer
曲設定変更
テンポ変更送信MIDI信号の変更
拍子変更フレーズ外音符の削除、横スクロール位置を修正
キー変更送信MIDI Noの増減
鍵盤タイプ変更鍵盤Noに応じて全ての音符位置を修正、縦スクロール位置を修正
編集トラック変更ピアノ鍵盤のサンプラー変更
トラック設定変更トラック名・略称、トラック追加・複製・削除
IO
データの入出力
保存・読み込み
新規作成現在の編集曲を保存してDBへ登録、新しい曲データに変更
保存曲データを書き出しDBへ登録、曲毎のバックアップ
曲の読み込み現在の編集曲を保存して、DBから選択した曲データに変更
外部への入出力アプリ外部のフォルダへ曲のバックアップデータを入出力
定期バックアップ指定した分毎にバックアップファイルを出力
曲の複製曲ファイルを複製してDBへ登録
曲の復元曲のバックアップファイルを確認して曲データへ復元
メロディーツール
FingerTool
指ツール
音符の編集
データ構造フレーズの音符を取得、基点と移動ベクトルを保持して移動する
音符の移動和音や連符は上下のみに制御
音符の影移動中に操作できているかわかりやすいように(iOS独自)
内外判定音符の移動をフレーズ内に留める
衝突判定移動する音符が他の音符に重なったときの挙動
タップ選択タップした音符の子音符も選択・解除
矩形選択囲った音符を選択
音符の入れ替えリズム音符のスライドで重なった音符と入れ替える(iOS独自)
和音の削除和音を移動した時に重なる時に削除する
連符に切り替えリズム音符タップで切り替え
PenTool
ペンツール
音符の作成
データ構造音符を作成・分割・統合、フレーズへ音符を追加する
音符の作成タップで音符を作成。分割線に合わせて長さを決定
音符列の作成スワイプに沿って複数の音符を作成。音階変わる時に音符分割
有無判定タップやスワイプした縦ラインに既に音符があるか判定
音符の移動音符が既にある場合は、作成ではなく移動。一定距離進むと移動終了
音符の分割リズム音符をタップした時、音符を分割、メロディ線に沿ってY位置を動かす
音符の統合2つのリズム音符の間をタップした場合、音符を統合
音符の伸縮リズム音符を左右にスワイプすることで音符の長さを伸縮、始点で分割なし(仕様変更)
音符の消滅音符の伸縮をした時に長さが0になると削除する(iOS独自)
領域差演算音符伸縮で他の音符に重なる時は差演算して他の音符長さを削る
サンプリング補間素早くスワイプしても音符が移動できるようにサンプリング間を補間する
細かい音符分割線内の細かな音符を移動する挙動
EraserTool
消しゴムツール
音符の削除
データ構造和音と連符の認識、フレーズから音符を削除する
音符の削除タップで音符を削除
和音・連符の削除和音・連符をタップで和音・連符のみを削除(iOS独自)
音符種別判定タップした音符が和音・連符・ルート音符なのか判定する
音符列の削除スワイプで指定する削除範囲内の複数の音符を削除。
和音列の削除リズム音符をスワイプで複数の和音のみを削除。(iOS独自)
休符に切り替えリズム音符タップで休符に切り替える
ドラムツール
PenTool
ペンツール
音符の作成
データ構造ドラム音符を作成、フレーズへ音符を追加・削除する
音符の作成・削除タップでドラム音符を作成。既に音符がある場合は削除
音符列の作成スワイプで跨いだ分割線にドラム音符を作成。
音符列の削除左にスワイプした範囲にある複数のドラム音符を削除。(iOS独自)
FingerTool
指ツール
音符の編集
データ構造フレーズのドラム音符を取得、選択、長さを編集して分割する
音符長さ編集音符を左右スワイプで長さを変更。長さがある時、連符になり長さ0の時連符解除
連符数の編集音符を上下にスワイプで連符数を変更(iOS独自)
タップ選択タップした音符を選択・解除
矩形選択囲った音符を選択
EraserTool
消しゴムツール
音符の削除
データ構造音符と連符の認識、フレーズから音符を削除する
音符の削除音符をタップで削除
休符に切り替え連符をタップで休符に切り替える
音符列の削除スワイプで指定する削除範囲内の複数の音符を削除。
伴奏ツール
PenTool
ペンツール
音符の作成
データ構造伴奏音符を作成、フレーズへ音符を追加・削除、長さの編集、分割・統合する
音符の作成タップで伴奏音符を作成
音符の移動 (回避)音符をスワイプして移動。音符があるとこを回避する。
音符長さ編集・削除音符の右ハンドルを左右にスワイプして長さ変更。長さ0の時削除
音符の分割・統合音符をタップで左右に分割・統合
音符列の削除左にスワイプした範囲にある複数の伴奏音符を削除。
FingerTool
指ツール
音符の編集
データ構造フレーズの伴奏音符を取得、選択、長さを編集、連符切り替え
音符の移動 (上書き)音符をスワイプして移動。移動した場所の音符は削除。
音符長さ編集・削除音符の右ハンドルを左右にスワイプして長さ変更。長さ0の時削除
連符数の編集音符選択時に表示されるピッカーで連符数を変更
タップ選択タップした音符を選択・解除
矩形選択囲った音符を選択
EraserTool
消しゴムツール
音符の削除
データ構造音符と連符の認識、フレーズから音符を削除、休符切り替え
音符の削除音符をタップで削除
休符に切り替え連符をタップで休符に切り替え
音符列の削除スワイプで指定する削除範囲内の複数の音符を削除
ハーモニーツール
PenTool
ペンツール
音符の作成
データ構造ハーモニー音符を作成、フレーズへ音符を追加・削除、長さの編集、分割・統合する
FingerTool
指ツール
音符の編集
データ構造フレーズのハーモニー音符を取得、選択、長さを編集
EraserTool
消しゴムツール
音符の削除
データ構造フレーズからハーモニー音符を削除
PhraseTool
フレーズツール
フレーズの編集
データ構造トラックのフレーズを取得・追加、削除、状態
フレーズの作成・挿入ダイアログで長さとリピートを設定
フレーズの選択2点タップで範囲選択、範囲ガイドタップで選択解除(仕様変更)
フレーズの移動左右スワイプで移動、移動は選択フレーズとスワイプ中のフレーズを含む
フレーズの伸縮サブ編集領域をスワイプした時にフレーズ長さを伸縮、長さ0で削除(iOS独自)
フレーズの貼り付け選択フレーズをコピー・ペースト、サブボタンかフレーズタブタップで挿入、選択解除
周囲有無判定作成する小節の近くにフレーズがあるかの判定、設定できる長さやリピート回数の制御
フレーズボタン・タブツールに応じてフレーズボタン、タブの処理を変更
フレーズの結合連続する2フレーズの接する小節線をタップで結合(iOS独自)
フレーズの分割フレーズをタップで分割(iOS独自)
リピートフレーズデータ構造、リピート変更時のフレーズの同期、上書きフレーズの把握
フレーズ同期解除同期解除でフレーズを複製・配置(iOS独自)
リピート回数設定フレーズダイアログから指定、サブ編集エリアからドラッグで変更(iOS独自)、状況によって回数制限
リピートフレーズ移動リピートフレーズ移動する時は、リピートフレーズに乗っている上書きフレーズも一緒に移動
StampTool
スタンプツール
モチーフの編集
Transform
画面移動
座標変換
画面を上下移動ピアノのスワイプにより
画面を左右移動 スクロールエリアのスワイプにより
画面を拡大・縮小ピンチアウト・インにより基点を画面中心に設定する
画面を拡大・縮小(軸指定)長押しからのドラッグ。ピアノでX軸方向、スクロールエリアでY軸方向
ドラム座標系新しくドラムの座標系を追加。下へ楽器が追加されるため、メロディーと異なり左上原点
MIDI コンバーターCompositionからMIDIのデータ構造へ変換
曲の再生画面左からMIDI再生、Compositionのデータ構造から曲の再生、再生位置の同期
曲の再生(最初から)再生ボタン長押しで最初から再生 最初から再生されるが、画面は最初に移動しない
曲の再生(位置指定)スクロール領域をダブルタップでその位置から再生(iOS独自)
再生速度の変更ドラッグで曲の再生速度を変更(iOS独自)
再生処理の最適化曲に変更がない時はキャッシュを使う、変更通知とキャッシュの管理
Commnity
Common
コミュニティ
データ構造カテゴリ等の曲情報、いいねやお気に入り等のリスポンスを保持
CommunitySongPlayerコミュニティ用にラップした曲プレイヤー
CategoryListsカテゴリーリスト群のモデル。カテゴリー別にフェッチ/キャッシュ
ListInfoカテゴリーリストのモデル、リストのスクロール位置、フェッチするページ番号等
ContextCommunity共通のCommonContextと各画面のContextがある
UserActivityManagerユーザーのアクティビティ(いいね、ミュートユーザー、再生リスト、モチーフ登録、アクセス履歴等)を管理
Service
サービスモデル
ListItemFetcherカテゴリーリスト項目のMLサーバーから取得する
MidiRepositoryMIDIファイルをサーバーから取得して貯める
UserActivityFetcherユーザーの行動をMLサーバーから取得する(再生数、再生リストに含まれているか、コメント等)
通知いいねやコメントもらった時の通知バナー表示、通知権限許可
MIDI
Common
MIDI共通
データ構造MIDIフォーマットへ出力できる構造
コントローラー曲の読み込みや再生、再生位置の監視や音源の変更などMIDIの扱いを管理する
サンプラーピアノや音符生成時に単体のMidiイベントから音を鳴らす
Service
サービスモデル
MidiPlayerMIDIを再生する
MidiReaderMIDIファイルの読み込み
MidiWriterMIDIファイル出力
Account
Common
アカウント
データ構造ログインできる構造、アカウント情報、ログイン情報、MLユーザー情報
AccountManagerアカウントの管理、ログイン時にMLサーバーと通信
Service
サービスモデル
UserActivityRepositoryユーザーのアクティビティ(いいね、ミュートユーザー、再生リスト、モチーフ登録、アクセス履歴等)を貯める
ServerCommunicationMLサーバーと通信する処理を集約
Domain
データ構造
Json形式
Melody MelodyTrack, MelodyPhrase, NoteContainer, NoteBlock, Note
Drum DrumTrack, DrumPhrase, BeatContainer, Beat
共通化 Original, Repeat, Syncの3種のPhraseをジェネリッククラスとプロトコルで抽象化
Service
サービスモデル
SongRederJsonファイルを読み込み、Domainのデータへ変換
SongWriterDomainのデータからJsonファイルへ書き出し
Common
Service
サービスモデル
リポジトリ保存データを管理
Manager
管理シングルトン
アカウントいいねやお気に入りの同期、プレミアムユーザーの管理
プレミアム機能プレミアムユーザーかプレミアムスターを使用時にプレミアム機能の有効を管理
多言語対応日本語、韓国語、中国語(繁体語)、英語に対応
広告バナー広告、レクタングル広告、全画面広告


実装の詳細

リピートフレーズ

リピートフレーズ

リピートフレーズはフレーズを繰り返すフレーズで、通常のフレーズ色と少し変えています。
フレーズの音符を変えると、リピートされたフレーズの音符も同期します。

フレーズ左のタグ🏷️に繰り返し回数を表示してます。ちなみに、タグをタップすることでオリジナルフレーズの小節位置にジャンプします。
音符の変更はリピートフレーズからはできないので、音符を変更したい時はタグタップでオリジナルフレーズに移動する必要があります。


リピート回数の設定 (iOS独自)

リピート回数

フレーズ設定からリピート回数を変更できますが、iOSではサブ編集エリアからドラッグすることでもリピート回数を変更できます。

ドラッグでの長さ・リピート変更

ドラッグする位置でフレーズ長さとリピート回数を直感的に変更できます。


上書きフレーズ (iOS独自)

リピートフレーズ

リピートフレーズ上にフレーズを置くことで上書きして、繰り返しリズムにアクセントを加えます。

また、リピートフレーズの同期解除ボタンを押すことで、フレーズをコピーできるので派生を考えた作り方ができます。

リピートフレーズの同期解除


リピートフレーズの移動・長さ変更

リピートフレーズの移動

リピートフレーズの移動時には上書きフレーズも一緒に移動します。
上書きフレーズはリピートフレーズの外にも自由自在に移動できます。

リピートフレーズのサイズ変更

リピートフレーズの長さを変えると、リピートで同期したフレーズの長さも変わります。
上書きフレーズはリピートに合わせて追従しますが、長さを短くした時にはみ出した場合は削除されます。



Androidとの違い Androidはリピートフレーズ上に直接、音符で上書き
iOSはリピートフレーズを、フレーズで上書き
皆様どちらが好みでしょうか?

上書き音符の方がいちいち新たなフレーズを乗せなくていいので楽かもしれませんし、フレーズ単位で考えたい場合は上書きフレーズの方が使いやすいかもしれません。
どちらも一長一短だと思いますが、実装上は断然フレーズ単位で考えた方がデータ構造がシンプルになり、すべてのリピートフレーズの音符で上書きされていないか確認しなくていいのでパフォーマンス面でもメリットが多く、今回は仕様変更となりました。
リピートフレーズ違い(Android、iOSの順)



その他作曲機能

再生モード

再生モード

通常は曲を再生しても画面や再生位置が移動しませんが、再生モードを変更すると曲再生時の挙動が変化します。

  • ループ:画面右端まで再生されると、左端へ再生位置が戻ります。
  • 追従:再生位置が画面の途中まで再生されると、その位置に固定して画面が自動スクロールになります。(再生固定位置は設定で変更可)
  • ページ送り:画面右端まで再生されると、左端が再生位置となるように画面が移動します。


ナビゲーションパネル

ナビゲーションパネル

本来ツールバーの下には保存した小節へジャンプするボタンが並ぶようなナビゲーションパネルがありますが、まだ未実装です。
その代わり、編集中の適切な音域へ自動スクロールするiOS独自の機能をつけてみました。

編集位置縦ジャンプボタン(iOS独自)

編集位置縦ジャンプボタンをタップすると、音符のある音域の中心へ移動します。
トラックにより使用音域が異なることがあり、トラック変更時に瞬時に編集位置に移動したい場合に便利な機能だと思います。



アプリ機能

設定

定期バックアップの間隔やフォルダを指定したり、ピアノ位置や追従再生モードの再生バー固定位置まで様々な設定があります。

中でも触感フィードバックは作曲時に振動を返す設定になります。

触感フィードバック(iOS独自)

音符を置いたときや、長押しで画面の拡大縮小するタイミングで振動して触覚でも知らせてくれます。
例えば小さい音符を移動する時なんかは、指で隠れてしまうことがあるので、振動で移動したことがわかると編集しやすいかもしれません。


アカウント

アカウントログインでコミュニティ曲にいいねやコメントを送れます。
また、ログインすることでいいねやお気に入りの数等のユーザーデータが同期されます。

Androidでプレミアムユーザー加入中の方はプレミアム機能が利用でき、プレミアムリングが付きます。


プレミアム機能

プレミアム機能使用時にノーマルユーザーでもプレミアムスターを使用すると使える機能があります。
スター使用でプレミアム機能の使用期間が決まる場合は時間を管理して終了時間になるとプレミアム機能が解除されます。

プレミアム機能の使用期間を管理

なお、只今早期特典としてプレミアム機能は使い放題となっています!
トラック数制限、ドラム楽器の追加、連符の指定などの機能がスターなしでしばらく使えるようにしてますので是非ご使用ください🙏
なお、最初は機能不足で動作不安定かもしれませんがご容赦ください😂


アプリ起動画面

コミュニティへクイックアクセスするためのボタンを表示します。 Androidと同様で星々の背景です。iOSの方がアニメーションで輝いている感が出ているかも?


ファイルからアプリ起動 (iOS独自)

作曲データファイルからアプリを起動できるようにしました。

共同作曲するときにバックアップファイルを送りあうユーザーを見かけたので、ファイルからアプリ開けると便利かなと思いつけました。
Androidはファイルを共有して、バックアップフォルダへ追加してから、アプリを開いて曲の読み込みから曲を選択する必要があるので地味に面倒かもしれません。

将来的にはワンタッチで曲データに名前をつけて共有できると便利ですかね。
もっと言うとコミュニティの公開範囲を設定できた方が共同作曲をしやすくなりそうですね。共同作曲ユーザー同士で限定公開して、出来上がった時に全体公開。この使い方がスマートでいいかも?


通知

Firebaseと連携して通知を送れるようにしました。
コミュニティを開いた時に、通知を送っていいかの権限許可をとります。

iOSは普段使いしてないのであまり詳しくないのですが、通知が来ると毎回上に通知ポップアップされるのかな?
そうだったら通知が多いと画面が騒がしくなるので、もう少し考えた方が良さそうですね。。


トースト表示

曲の保存等で画面下に情報バナーを表示するトースト機能を実装しました。



iOSリリース

iOSのリリースは8月を予定してましたが、実はもうリリースしちゃいました☆

聞くところによるとAppleのアプリ審査は厳しいとのことだったので、リジェクトされることを前提に早めに一回目の審査を申し込んだところ。。

一発で審査を通過 (๑⊙д⊙๑)

既にApple StroeでmusicLineが並ぶこととなりました ⌯' ꇴ '⌯ಣ

‎3分作曲-musicLine-アプリ - App Store

Apple Store

皆様、今まで開発ブログの閲覧ありがとうございました!
思い返せば「iOS版はいつ出るの?」と声を掛けてもらう機会が増え、5年ほど前からiOSの開発がスタートしました。
正直AndroidもありiOSの開発はあまり進んでいなかったのですが、「iOS版も開発してます」と返事して進んでない状況でした _ (:3 」∠) _
でも軽視しているわけではなく、古参のユーザーがコミュニティからいなくなる度にiOSの必要性を感じていました。
もちろんPCで曲作ることになってスマホ作曲しなくなったとかもあると思います。ボカロPや新たなステージで活躍したいと旅立つことは素晴らしいことで応援してます (*p'∀'q)
ただiOSへ機種変してmusicLineがないからできないという理由だと悲しいことです。
いつでも、どこでも、手軽に作曲!
それがmusicLineのモットーです。

そして3年半前に一念発起し、ブログを始めたタイミングでmusicLineの開発に専念することにしました。
Xの新機能告知とかでいいねやコメントを送っていただいたML民の方とても励みになっています!
​このペースをずっと維持できるかは分かりませんが、生涯をかけてmusicLineを少しずつ大切に育てていきたいと思っています。
​これからも長く付き合っていただけるアプリになれば嬉しいです (*>U<*)
今後ともどうぞよろしくお願いします!



おわりに

なんか開発ブログが終わるかのような締め方になっちゃいましたが、まだまだ続きます!
というか開発しないといけないこと山積みですねー (ʘᗩʘ’)

すみません長々と思い出話を書いちゃいましたが、
今後直近の開発作業は

  • 曲のコミュニティ投稿
  • ユーザーページ
  • 作曲編集のUndo/Redo

を予定してます。

この二つの機能はmusicLineに特になくてはならない機能だと思います。
というか既に曲の投稿について質問が来ていて、もう待たせている状態です (ꈍ罒ꈍ﹡)
iOSリリースの告知もしてないのに!?
既にストアからDLしてて、、
曲を仕上げている!?
まさか??
なるべく早く実装します!8月中には。いや9月中には。。気長に待っていただけると。。。

でもその前にSwitch2を買いたいです!
(いや勝手に買えばいい)

思い返せば1年前にiOSリリース延期して以来、iOSリリースしたら買おうと思ってました
(今回は何度か思い返す回になっております)

ただタイミング悪く値上げしたのが悔しい (ꈍ罒ꈍ﹡)

このタイミングでドンキーコングバナンザ?☺️

では、また (๑˃̵ᴗ˂̵)و



【iOS】進捗報告 12(曲の保存・読み込み)

musicLine(iOS)についての進捗。
今回は曲の保存・読み込み等のデータ入出力について進捗を報告します。

曲読み込み


実装状況

カテゴリタイトル補足
View
Composition
ダイアログ
スライドメニューアイコンタップで作曲画面を右にスライドしてメニューを表示アカウントとお問い合わせは未着手
設定作曲画面の設定項目を表示
曲の読み込みDB参照して曲の一覧を表示。検索と 並び替え(iOS独自)
曲の概要曲の概要を表示
バックアップ一覧フォルダ内のファイル確認して、曲のバックアップと定期バックアップの一覧を表示。検索と並び替え(iOS独自)
ハーモニー音符和音の位置と長さ、ディグリーやボイシングNo等の情報を表示
ハーモニーガイド和音を編集する時、必要な情報を表示
Composition
IO
データの入出力
保存・読み込み
新規作成現在の編集曲を保存してDBへ登録、新しい曲データに変更
保存曲データを書き出しDBへ登録、曲毎のバックアップ
曲の読み込み現在の編集曲を保存して、DBから選択した曲データに変更
外部への入出力アプリ外部のフォルダへ曲のバックアップデータを入出力
定期バックアップ指定した分毎にバックアップファイルを出力
曲の複製曲ファイルを複製してDBへ登録
曲の復元曲のバックアップファイルを確認して曲データへ復元
ハーモニーツール
PenTool
ペンツール
音符の作成
データ構造ハーモニー音符を作成、フレーズへ音符を追加・削除、長さの編集、分割・統合する
FingerTool
指ツール
音符の編集
データ構造フレーズのハーモニー音符を取得、選択、長さを編集
EraserTool
消しゴムツール
音符の削除
データ構造フレーズからハーモニー音符を削除


全進捗マップを表示

カテゴリタイトル補足
View
Common
ダイアログ
アラートメッセージユーザーに通知するコメント
数字ピッカー数字(範囲制限)をポップアップダイアルで取得
項目ピッカー特定の値をポップアップのリスト項目で取得
HTMLテキストテキストスタイルを部分的に変えるため、HTML形式に対応したText
文字制限テキスト編集文字制限付きのTextField、制限文字数を超えは赤文字で閉じる時に切り捨て
全画面テキスト編集複数行のテキストを編集する時に、ポップアップ全画面でTextEditorとキーボード表示
FitScrollView閾値高さで スクロールありorなしを切り替える(画面に収まるときはScrollViewにしない)
WheelMenuPicker値をタップすると選択肢が表示されて値を変更、値をスワイプするとホイールで素早く変更
Composition
UI配置
ガイド表示
ピアノ
スクロールエリア
小節番号
小節線
分割線拡大率によって間隔を変化
フレーズフレーズがないところはフレーズ作成ボタンを表示
ツールボタン 選択中のツールはツール色にハイライトする
メロディーライン ペンツールでの音符作成時の入力線
メロディー音符 音符の先頭にチョボをつける
リズム音符 ベース音符のみ下に表示
サンプルデータ 手入力したサンプルデータの音符を配置
連符連符は数字で表示、拡大率によって省略
ペンツールガイド長さ編集しているリズム音符、伸ばした時の削る範囲
(ドラム) 左にスワイプしている時、削除する範囲
指ツールガイド移動中の音符影、矩形選択の枠
(ドラム) 長さ編集している時、伸ばし線(iOS独自)。矩形選択の範囲
消しゴムツールガイド削除範囲、和音のみの削除範囲
(ドラム) 削除範囲
フレーズツールガイドフレーズ移動・伸縮のバー、選択範囲テキスト(iOS独自)
フレーズボタンフレーズボタンとサブボタンを配置、ツールに応じてアイコンを変更、画面拡大率に応じて縮小
フレーズタブツールに応じてアイコンを変更、拡大率に応じて縮小、スクロール状態に応じて移動
音符描画の高速化音符が多くても描画できる速さへ最適化
音符の編集状態選択や変更した時に枠線の色変更
音符音階メロディ音符に音階表示
再生バー曲を再生している時に、再生位置をバーで表示
再生ボタン曲を再生/停止を監視して、状態を変更、再生準備が遅い時はインジケーターを表示
再生速度の表示曲の再生速度を表示(iOS独自)
テスト音のガイド鳴っている音階に色をつける
ドラム音符音符と連符の表示。分割線に乗っていない音符は細く表示(iOS独自)
ドラム盤ピアノ鍵盤の位置にドラムセットを表示
伴奏音符音符/休符と連符の表示。細かい連符は省略して表示
ペンツールガイド(伴奏) 移動してる時、移動影。左にスワイプしている時、削除する範囲。長さ編集している時、伸ばし線
指ツールガイド(伴奏) 移動してる時、移動影と上書き音符に光。長さ編集している時、伸ばし線。矩形選択の範囲
消しゴムツールガイド(伴奏) 削除範囲
Composition
ダイアログ
フレーズフレーズの作成・設定・挿入、フレーズの長さやリピート回数の設定
曲設定タイトル・テンポ、キー等の曲の設定
トラック選択編集トラックの変更・追加/削除、ボリュームやミュート等の設定
楽器選択トラックの使用楽器変更、楽器のランダム選択・選択リセット(iOS独自)
ドラム楽器一覧使用ドラム楽器をリスト表示。使用楽器の編集や並び替え(iOS独自)
ドラム楽器設定ドラム楽器の音量調整・ミュート、削除・複製
ドラム楽器選択トラックの使用ドラム楽器変更、楽器のランダム選択・選択リセット(iOS独自)
スライドメニューアイコンタップで作曲画面を右にスライドしてメニューを表示アカウントとお問い合わせは未着手
設定作曲画面の設定項目を表示
曲の読み込みDB参照して曲の一覧を表示。検索と 並び替え(iOS独自)
曲の概要曲の概要を表示
バックアップ一覧フォルダ内のファイル確認して、曲のバックアップと定期バックアップの一覧を表示。検索と並び替え(iOS独自)
ハーモニー音符和音の位置と長さ、ディグリーやボイシングNo等の情報を表示
ハーモニーガイド和音を編集する時、必要な情報を表示
Community
(共通)
UI配置
コミュニティディスプレイとコントローラーを表示。縦持ちと横持ちのレイアウト。どのディスプレイ、コントローラーを使用するかは各コミュニティ画面で派生
カテゴリーリスト群カテゴリー選択、カテゴリーリストを表示。どのカテゴリーリストを表示するかは各コミュニティ画面で派生
ページスクロールリストを表示。スワイプでリスト項目を取得。どのリスト項目を使用するかは各カテゴリーで派生
曲リスト項目各コミュニティ画面で派生系を用意する
リレー曲リスト項目左右にスワイプで前後走者の曲を表示
その他リスト項目曲ID:検索で曲ID一覧を表示、ユーザー:ユーザー検索やいいねリスト等で表示
曲詳細曲の情報と貰ったコメントを表示、送るコメントを編集する
曲の情報曲のタイトル、作者、ランキング順位、タグ、ユーザーの反応等を表示
貰ったコメントテキストとOGP特殊コメントの装飾
ソングビジュア曲再生位置の変更と可視化。曲情報でトロフィー変更。リスト/詳細ボタンで切り替え。シンプルのみ実装でリリース後に追加予定。
カテゴリー選択カテゴリータブ表示。スクロール可能。選択表示。
ユーザーアイコンユーザー画像、プレミアムリングを表示。タップでユーザーページへ
プレイヤー曲の再生、いいね・お気に入り等のボタン。現在の状況を反映再生リスト追加ボタン
設定パネルレイアウト設定、ソングビジュア設定、楽器フィルタ リリース後に実装予定
Community
Square
コミュニティ広場
UI配置
ディスプレイ状況によりカテゴリー説明/ソングビジュアを切り替え。
カテゴリー説明広場カテゴリーの説明
コントローラーカテゴリーリスト群/曲詳細を切り替え
カテゴリーリスト群Squareのカテゴリーリストを切り替えるように派生
リスト項目カテゴリー別にリスト項目を派生(ランキングなら左にランク情報)。コンテスト項目はタップでコンテスト画面へ
イベント詳細コンテストの詳細情報の表示
絞り込み検索
Community
UserPage
ユーザーページ
UI配置
ディスプレイユーザープロフィールを表示。下へスワイプした時に隠れてヘッダーが表示されるように
ユーザープロフィールユーザー情報、紹介文、アクティビティログ等表示
ユーザー情報名前、アイコン、リンクリスト、フォロー欄、紹介文表示
リンクリスト外部リンク(X等)ボタンを並べる
フォロー欄フォロー、ミュート、通知ボタン
アクティビティログ活動レベル、投稿曲数やいいね数など表示
ヘッダー
コントローラーディスプレイに追従
カテゴリーリスト群UserPageのカテゴリーリストを切り替えるように派生
リスト項目開閉するプレイリスト項目を作成。
Community
Contest
コンテスト結果
UI配置
ディスプレイ状況によりコンテスト概要/ソングビジュアを切り替え。
コンテスト概要コンテストのテーマ、内容、提案者の表示
コントローラーカテゴリーリスト群/曲詳細を切り替え
カテゴリーリスト群Contestのカテゴリーリストを切り替えるように派生
リスト項目コンテストの順位や自分の投票数を表示するリスト項目に派生
Community
ダイアログ
リストダイアログいいね・お気に入りをしたユーザーリスト表示、曲を含む再生リストの表示
メッセージアラート通知するテキストを知らせる(DLした時や削除確認など)
プロフィール編集名前、アイコン、紹介文等を編集
プレイリスト詳細プレイリストのタイトル、説明、作者、コメント等を表示
プレイリスト編集タイトル、アイコン、曲リスト等を編集
コンテスト投票開催コンテスト曲の視聴と投票
MIDI詳細曲のテンポ、音符・トラック数、使用楽器等
Composition
Common
作曲共通
データ構造座標とサイズ、状態を保持する。レンダラーやコライダー、通知等のロジック
コンバーターDomainのデータ構造へ変換・逆変換
通知機構Modelに変更があった時に、Viewへ通知して再描画。変更状況を監視してキャッシュ
Changer
曲設定変更
テンポ変更送信MIDI信号の変更
拍子変更フレーズ外音符の削除、横スクロール位置を修正
キー変更送信MIDI Noの増減
鍵盤タイプ変更鍵盤Noに応じて全ての音符位置を修正、縦スクロール位置を修正
編集トラック変更ピアノ鍵盤のサンプラー変更
トラック設定変更トラック名・略称、トラック追加・複製・削除
IO
データの入出力
保存・読み込み
新規作成現在の編集曲を保存してDBへ登録、新しい曲データに変更
保存曲データを書き出しDBへ登録、曲毎のバックアップ
曲の読み込み現在の編集曲を保存して、DBから選択した曲データに変更
外部への入出力アプリ外部のフォルダへ曲のバックアップデータを入出力
定期バックアップ指定した分毎にバックアップファイルを出力
曲の複製曲ファイルを複製してDBへ登録
曲の復元曲のバックアップファイルを確認して曲データへ復元
メロディーツール
FingerTool
指ツール
音符の編集
データ構造フレーズの音符を取得、基点と移動ベクトルを保持して移動する
音符の移動和音や連符は上下のみに制御
音符の影移動中に操作できているかわかりやすいように(iOS独自)
内外判定音符の移動をフレーズ内に留める
衝突判定移動する音符が他の音符に重なったときの挙動
タップ選択タップした音符の子音符も選択・解除
矩形選択囲った音符を選択
音符の入れ替えリズム音符のスライドで重なった音符と入れ替える(iOS独自)
和音の削除和音を移動した時に重なる時に削除する
連符に切り替えリズム音符タップで切り替え
PenTool
ペンツール
音符の作成
データ構造音符を作成・分割・統合、フレーズへ音符を追加する
音符の作成タップで音符を作成。分割線に合わせて長さを決定
音符列の作成スワイプに沿って複数の音符を作成。音階変わる時に音符分割
有無判定タップやスワイプした縦ラインに既に音符があるか判定
音符の移動音符が既にある場合は、作成ではなく移動。一定距離進むと移動終了
音符の分割リズム音符をタップした時、音符を分割、メロディ線に沿ってY位置を動かす
音符の統合2つのリズム音符の間をタップした場合、音符を統合
音符の伸縮リズム音符を左右にスワイプすることで音符の長さを伸縮、始点で分割なし(仕様変更)
音符の消滅音符の伸縮をした時に長さが0になると削除する(iOS独自)
領域差演算音符伸縮で他の音符に重なる時は差演算して他の音符長さを削る
サンプリング補間素早くスワイプしても音符が移動できるようにサンプリング間を補間する
細かい音符分割線内の細かな音符を移動する挙動
EraserTool
消しゴムツール
音符の削除
データ構造和音と連符の認識、フレーズから音符を削除する
音符の削除タップで音符を削除
和音・連符の削除和音・連符をタップで和音・連符のみを削除(iOS独自)
音符種別判定タップした音符が和音・連符・ルート音符なのか判定する
音符列の削除スワイプで指定する削除範囲内の複数の音符を削除。
和音列の削除リズム音符をスワイプで複数の和音のみを削除。(iOS独自)
休符に切り替えリズム音符タップで休符に切り替える
ドラムツール
PenTool
ペンツール
音符の作成
データ構造ドラム音符を作成、フレーズへ音符を追加・削除する
音符の作成・削除タップでドラム音符を作成。既に音符がある場合は削除
音符列の作成スワイプで跨いだ分割線にドラム音符を作成。
音符列の削除左にスワイプした範囲にある複数のドラム音符を削除。(iOS独自)
FingerTool
指ツール
音符の編集
データ構造フレーズのドラム音符を取得、選択、長さを編集して分割する
音符長さ編集音符を左右スワイプで長さを変更。長さがある時、連符になり長さ0の時連符解除
連符数の編集音符を上下にスワイプで連符数を変更(iOS独自)
タップ選択タップした音符を選択・解除
矩形選択囲った音符を選択
EraserTool
消しゴムツール
音符の削除
データ構造音符と連符の認識、フレーズから音符を削除する
音符の削除音符をタップで削除
休符に切り替え連符をタップで休符に切り替える
音符列の削除スワイプで指定する削除範囲内の複数の音符を削除。
伴奏ツール
PenTool
ペンツール
音符の作成
データ構造伴奏音符を作成、フレーズへ音符を追加・削除、長さの編集、分割・統合する
音符の作成タップで伴奏音符を作成
音符の移動 (回避)音符をスワイプして移動。音符があるとこを回避する。
音符長さ編集・削除音符の右ハンドルを左右にスワイプして長さ変更。長さ0の時削除
音符の分割・統合音符をタップで左右に分割・統合
音符列の削除左にスワイプした範囲にある複数の伴奏音符を削除。
FingerTool
指ツール
音符の編集
データ構造フレーズの伴奏音符を取得、選択、長さを編集、連符切り替え
音符の移動 (上書き)音符をスワイプして移動。移動した場所の音符は削除。
音符長さ編集・削除音符の右ハンドルを左右にスワイプして長さ変更。長さ0の時削除
連符数の編集音符選択時に表示されるピッカーで連符数を変更
タップ選択タップした音符を選択・解除
矩形選択囲った音符を選択
EraserTool
消しゴムツール
音符の削除
データ構造音符と連符の認識、フレーズから音符を削除、休符切り替え
音符の削除音符をタップで削除
休符に切り替え連符をタップで休符に切り替え
音符列の削除スワイプで指定する削除範囲内の複数の音符を削除
ハーモニーツール
PenTool
ペンツール
音符の作成
データ構造ハーモニー音符を作成、フレーズへ音符を追加・削除、長さの編集、分割・統合する
FingerTool
指ツール
音符の編集
データ構造フレーズのハーモニー音符を取得、選択、長さを編集
EraserTool
消しゴムツール
音符の削除
データ構造フレーズからハーモニー音符を削除
PhraseTool
フレーズツール
フレーズの編集
データ構造トラックのフレーズを取得・追加、削除、状態
フレーズの作成・挿入ダイアログで長さとリピートを設定 リピートフレーズは未実装
フレーズの選択2点タップで範囲選択、範囲ガイドタップで選択解除(仕様変更)
フレーズの移動左右スワイプで移動、移動は選択フレーズとスワイプ中のフレーズを含む
フレーズの伸縮サブ編集領域をスワイプした時にフレーズ長さを伸縮、長さ0で削除(iOS独自)
フレーズの貼り付け選択フレーズをコピー・ペースト、サブボタンかフレーズタブタップで挿入、選択解除
周囲有無判定作成する小節の近くにフレーズがあるかの判定、設定できる長さやリピート回数の制御
フレーズボタン・タブツールに応じてフレーズボタン、タブの処理を変更
フレーズの結合連続する2フレーズの接する小節線をタップで結合(iOS独自)
フレーズの分割フレーズをタップで分割(iOS独自)
StampTool
スタンプツール
モチーフの編集
Transform
画面移動
座標変換
画面を上下移動ピアノのスワイプにより
画面を左右移動 スクロールエリアのスワイプにより
画面を拡大・縮小ピンチアウト・インにより基点を画面中心に設定する
画面を拡大・縮小(軸指定)長押しからのドラッグ。ピアノでX軸方向、スクロールエリアでY軸方向
ドラム座標系新しくドラムの座標系を追加。下へ楽器が追加されるため、メロディーと異なり左上原点
MIDI コンバーターCompositionからMIDIのデータ構造へ変換
曲の再生画面左からMIDI再生、Compositionのデータ構造から曲の再生、再生位置の同期
曲の再生(最初から)再生ボタン長押しで最初から再生 最初から再生されるが、画面は最初に移動しない
曲の再生(位置指定)スクロール領域をダブルタップでその位置から再生(iOS独自)
再生速度の変更ドラッグで曲の再生速度を変更(iOS独自)
再生処理の最適化曲に変更がない時はキャッシュを使う、変更通知とキャッシュの管理
Commnity
Common
コミュニティ
データ構造カテゴリ等の曲情報、いいねやお気に入り等のリスポンスを保持
CommunitySongPlayerコミュニティ用にラップした曲プレイヤー
CategoryListsカテゴリーリスト群のモデル。カテゴリー別にフェッチ/キャッシュ
ListInfoカテゴリーリストのモデル、リストのスクロール位置、フェッチするページ番号等
ContextCommunity共通のCommonContextと各画面のContextがある
UserActivityManagerユーザーのアクティビティ(いいね、ミュートユーザー、再生リスト、モチーフ登録、アクセス履歴等)を管理
Service
サービスモデル
ListItemFetcherカテゴリーリスト項目のMLサーバーから取得する
MidiRepositoryMIDIファイルをサーバーから取得して貯める
UserActivityFetcherユーザーの行動をMLサーバーから取得する(再生数、再生リストに含まれているか、コメント等)
MIDI
Common
MIDI共通
データ構造MIDIフォーマットへ出力できる構造
コントローラー曲の読み込みや再生、再生位置の監視や音源の変更などMIDIの扱いを管理する
サンプラーピアノや音符生成時に単体のMidiイベントから音を鳴らす
Service
サービスモデル
MidiPlayerMIDIを再生する
MidiReaderMIDIファイルの読み込み
MidiWriterMIDIファイル出力
Account
Common
アカウント
データ構造ログインできる構造、アカウント情報、ログイン情報、MLユーザー情報
AccountManagerアカウントの管理、ログイン時にMLサーバーと通信
Service
サービスモデル
UserActivityRepositoryユーザーのアクティビティ(いいね、ミュートユーザー、再生リスト、モチーフ登録、アクセス履歴等)を貯める
ServerCommunicationMLサーバーと通信する処理を集約
Domain
データ構造
Json形式
Melody MelodyTrack, MelodyPhrase, NoteContainer, NoteBlock, Note
Drum DrumTrack, DrumPhrase, BeatContainer, Beat
共通化 Original, Repeat, Syncの3種のPhraseをジェネリッククラスとプロトコルで抽象化
Service
サービスモデル
SongRederJsonファイルを読み込み、Domainのデータへ変換
SongWriterDomainのデータからJsonファイルへ書き出し
Common
Service
サービスモデル
リポジトリ保存データを管理


実装の詳細

スライドメニュー

スライドメニュー

左上のハンバーガーアイコン(☰)タップで作曲画面が右にスライドしてメニュー一覧が表示されます。
ここから曲の新規作成や曲読み込み、保存を行います。

新規作成は空の曲が増幅しないように、すぐに保存せずに編集したときに保存するようにしています。


曲の保存

曲の保存はファイル出力するだけではなく、RealmDBに曲IDを登録して管理しています。DBを使わなくてもフォルダ内のファイルを読み込めば一覧を表示できますが、ファイルが多くなると一覧表示に待ち時間が発生しそうなので、曲の管理にDBを使っています。

曲のデータファイルはセキュリティ的にアプリ内フォルダ(ユーザーが勝手に触れないフォルダ)に出力します。
musicLineは他ユーザーの曲をDLして確認することが出来ますが、そのファイルを直接触れるとデータ改ざんのリスクがあるのでアプリ内フォルダでファイルを管理しています。
なのでアプリ外へファイル出力するバックアップは自分の曲しかできないようになっています。


設定ダイアログ

設定ダイアログ

とりあえず今必要な設定項目を表示しました。
アプリ外にバックアップする時にはiOS純正のフォルダピッカーでフォルダパスとアクセス権限も一緒に取得します。

フォルダピッカー

一度取得したアクセス権限を次回以降のために保存しておきます。
フォルダパスの保存はURLではなくDataに変換して保存しますが、ポイントはアクセス開始startAccessingSecurityScopedResourceした状態でブックマークbookmarkData保存する必要がありました。



DEBUG設定 ユーザーの方には関係ないですが、隠しメニューとしてDebugしやすくなるような設定項目があります。

DEBUG設定項目
裏メニューを見るとわくわくしますね☆



曲の読み込みダイアログ

DBに登録している曲一覧を表示します。

曲の読み込みダイアログ

右下のアイコンから曲の検索やバックアップ一覧ダイアログを表示します。


曲の検索

iOSではタイトル、作成日時、最終編集日時、編集時間で並び替えできるようにしました。

作成時間で並び替え

右上のチェックアイコンで複数選択できます。

複数選択で曲削除


曲の概要ダイアログ

曲の概要ダイアログ

曲のテンポ、拍子、キーを表示します。
このダイアログから削除、複製、復元ができます。
復元はバックアップフォルダからその曲のバックアップファイルを確認します。バックアップがあれば、アプリ内フォルダへ曲データファイルをコピーしてDB登録します。



バックアップ一覧ダイアログ

バックアップフォルダ内のファイルを読み取り、定期バックアップと曲別のバックアップを表示します。

定期バックアップは設定で指定した分数毎にバックアップされます。指定数を超えると自動的に削除されます。
曲別のバックアップは曲別に最新のデータを保持します。

バックアップ一覧も曲読み込みダイアログと同様に曲の検索と並び替え、複数選択削除ができます。

バックアップ一覧ダイアログ

バックアップフォルダは自由度を高めるため、DBを使っていません。バックアップファイルをフォルダ内に入れると表示されます。
デフォルトではアプリ内にバックアップされますが、設定でアプリ外フォルダへもバックアップできます。アプリ外へバックアップすると、アプリを削除してもデータを残すことができます。
現状はiCloudへバックアップしない仕様となっています。課金しないとiCloudまともに使えなさそうだけど、iPhoneユーザーはiCloud使ってるのかな?



おまけ

ハーモニートラックについて検討しました。
前回ハーモニートラックの実装は一旦見送ると言いましたが、ハーモニートラックの今後に関して気になって仕方がなかったので、少し実装して必要性を確認しました。
( いやあああ iOSリリース予定直近なのに =3 =3 )

Androidのハーモニートラックはペンツールがデフォルトで和音設定になっているだけで、メロディートラックと同じです。
なので今の仕様のままではハーモニートラックの意義がなくなりつつあります。
そこで、和音に特化したトラックとして直感的に和音作成するためにはどのような操作性かを想像しながら検討しました。

でも考えてはみたものの、なんか難しそうなUIになってしまったので一旦保留にします。
というかiOSリリース予定に全然間に合わなくなっちゃうのでタイムアップです!!
考えれば考えるほど膨らみ過ぎてしまうので、iOSリリース後アプリが安定してから余裕がある時にします。。。


さて、そんなこんなで試作として出来上がったのがこちら

ハーモニートラック

一応初心者でもどの和音を使えばいいかがわかるようなUIを目指してます。
でも情報が多すぎてどこを見ていいか、何をしていいかわからないのが問題点です。
基本はテンプレの「コード進行を選択するだけ」くらいにした方が簡単でいいかもしれないですね。

あとは上級者向けにどんなUIにしたら使いやすいかですね。
音楽理論を勉強すればするほど、どういう和音まで対応すべきなのかとか色々わからなくなります。
今の方針的には親和性の高い和音(構成音の和音など)ほど簡単に出て、ニッチな和音は長押し等の特殊な操作で生成するような設計にしています。

操作により生成和音が変化
(長押しでニッチな和音を生成)

試作の出来はともあれ、将来的にはハーモニートラックを組み込みたいと思える機会になりました。



おわりに

今回はスライドメニュー、曲の保存・読み込みとアプリ外へのファイルバックアップについて実装できました。
アプリ外へのファイル出力はファイルアクセス権限の保存で悩んでましたが、なんとか仕様通りに動作するようにできました。

個人的にやっぱりハーモニートラックを考えるのが楽しいです。
コード進行はまだよくわかってないですが、上級者になれば感覚でわかるようになるのかな?

知識なくてもコードを選んで曲の大まかな構造ができれば、曲作りがもっと楽しくなれそうです。
音階ってメジャーマイナー以外にも色々あるんですね。音楽理論勉強中。。

そんなこんなでいよいよリリース時期が近づいてきてますね!
締切が近づくと余裕がなくなり焦りが出てきてますね🥹
なんか実装すればするほど、もう少しこうしたいと思っちゃうので8月には実装が途中でも一旦リリースしようと思ってます!!

なので iOSリリースは 予定通り8月 くらい (1ヶ月前後遅れるかも?)

リリースからしばらくはアプリが不安定かもしれませんが、温かく見守って頂ければと思います🙏

ということでリリースまでにあとリピートフレーズとアカウント、設定画面、あと言語対応はしときたい。
↑ 直前に詰め込むタイプ (๑˃̵ᴗ˂̵)


がんばろーっと (๑˃̵ᴗ˂̵)و



【iOS】進捗報告 11 ☆伴奏トラック☆

musicLine(iOS)についての進捗。
今回はiOS独自機能で考案した伴奏トラックについて進捗を報告します。

伴奏トラック


伴奏トラックとは

横線で作るメロディートラックとは異なり、縦も自由に音符を置けるトラックです。

メロディートラックでは縦に音符が重ならないように配置され、和音を乗せていくような作り方です。音符を分割する時は、縦が合うように和音の音符も分割されます。

一方で伴奏トラックは縦に重ねて音符を配置することができ、1音ずつ直接置いていくような作り方です。各音符は独立しており、より直感的に自由な編集ができます。


ちなみに、メロディートラックは1, 2, 3と数字をカウントするのに対し、伴奏トラックはA, B, Cとアルファベットを順番に使っていきます。

伴奏トラックの採番


ということで今回ハーモニートラックの実装は一旦見送り、新しい伴奏トラックを実装しました。

ハーモニートラックの今後 今ではメロディートラックと大差なく特徴のないトラックとなっています。
将来的には和音作りに特化したトラックにしたいと思っています。コード進行に沿って和音の選択肢を出すような支援ツールみたいなイメージです。
でもそのためには、コード進行を入力できる機能なども必要なので、ハーモニートラックの特徴を出せるのはまだ先になりそうですね。


実装状況

カテゴリタイトル補足
View
Common WheelMenuPicker値をタップすると選択肢が表示されて値を変更、値をスワイプするとホイールで素早く変更
Composition
UI配置
ガイド表示
伴奏音符音符/休符と連符の表示。細かい連符は省略して表示
ペンツールガイド(伴奏) 移動してる時、移動影。左にスワイプしている時、削除する範囲。長さ編集している時、伸ばし線
指ツールガイド(伴奏) 移動してる時、移動影と上書き音符に光。長さ編集している時、伸ばし線。矩形選択の範囲
消しゴムツールガイド(伴奏) 削除範囲
Composition
伴奏ツール
PenTool
ペンツール
音符の作成
データ構造伴奏音符を作成、フレーズへ音符を追加・削除、長さの編集、分割・統合する
音符の作成タップで伴奏音符を作成
音符の移動 (回避)音符をスワイプして移動。音符があるとこを回避する。
音符長さ編集・削除音符の右ハンドルを左右にスワイプして長さ変更。長さ0の時削除
音符の分割・統合音符をタップで左右に分割・統合
音符列の削除左にスワイプした範囲にある複数の伴奏音符を削除。
FingerTool
指ツール
音符の編集
データ構造フレーズの伴奏音符を取得、選択、長さを編集、連符切り替え
音符の移動 (上書き)音符をスワイプして移動。移動した場所の音符は削除。
音符長さ編集・削除音符の右ハンドルを左右にスワイプして長さ変更。長さ0の時削除
連符数の編集音符選択時に表示されるピッカーで連符数を変更
タップ選択タップした音符を選択・解除
矩形選択囲った音符を選択
EraserTool
消しゴムツール
音符の削除
データ構造音符と連符の認識、フレーズから音符を削除、休符切り替え
音符の削除音符をタップで削除
休符に切り替え連符をタップで休符に切り替え
音符列の削除スワイプで指定する削除範囲内の複数の音符を削除


全進捗マップを表示

カテゴリタイトル補足
View
Common
ダイアログ
アラートメッセージユーザーに通知するコメント
数字ピッカー数字(範囲制限)をポップアップダイアルで取得
項目ピッカー特定の値をポップアップのリスト項目で取得
HTMLテキストテキストスタイルを部分的に変えるため、HTML形式に対応したText
文字制限テキスト編集文字制限付きのTextField、制限文字数を超えは赤文字で閉じる時に切り捨て
全画面テキスト編集複数行のテキストを編集する時に、ポップアップ全画面でTextEditorとキーボード表示
FitScrollView閾値高さで スクロールありorなしを切り替える(画面に収まるときはScrollViewにしない)
WheelMenuPicker値をタップすると選択肢が表示されて値を変更、値をスワイプするとホイールで素早く変更
Composition
UI配置
ガイド表示
ピアノ
スクロールエリア
小節番号
小節線
分割線拡大率によって間隔を変化
フレーズフレーズがないところはフレーズ作成ボタンを表示
ツールボタン 選択中のツールはツール色にハイライトする
メロディーライン ペンツールでの音符作成時の入力線
メロディー音符 音符の先頭にチョボをつける
リズム音符 ベース音符のみ下に表示
サンプルデータ 手入力したサンプルデータの音符を配置
連符連符は数字で表示、拡大率によって省略
ペンツールガイド長さ編集しているリズム音符、伸ばした時の削る範囲
(ドラム) 左にスワイプしている時、削除する範囲
指ツールガイド移動中の音符影、矩形選択の枠
(ドラム) 長さ編集している時、伸ばし線(iOS独自)。矩形選択の範囲
消しゴムツールガイド削除範囲、和音のみの削除範囲
(ドラム) 削除範囲
フレーズツールガイドフレーズ移動・伸縮のバー、選択範囲テキスト(iOS独自)
フレーズボタンフレーズボタンとサブボタンを配置、ツールに応じてアイコンを変更、画面拡大率に応じて縮小
フレーズタブツールに応じてアイコンを変更、拡大率に応じて縮小、スクロール状態に応じて移動
音符描画の高速化音符が多くても描画できる速さへ最適化
音符の編集状態選択や変更した時に枠線の色変更
音符音階メロディ音符に音階表示
再生バー曲を再生している時に、再生位置をバーで表示
再生ボタン曲を再生/停止を監視して、状態を変更、再生準備が遅い時はインジケーターを表示
再生速度の表示曲の再生速度を表示(iOS独自)
テスト音のガイド鳴っている音階に色をつける
ドラム音符音符と連符の表示。分割線に乗っていない音符は細く表示(iOS独自)
ドラム盤ピアノ鍵盤の位置にドラムセットを表示
伴奏音符音符/休符と連符の表示。細かい連符は省略して表示
ペンツールガイド(伴奏) 移動してる時、移動影。左にスワイプしている時、削除する範囲。長さ編集している時、伸ばし線
指ツールガイド(伴奏) 移動してる時、移動影と上書き音符に光。長さ編集している時、伸ばし線。矩形選択の範囲
消しゴムツールガイド(伴奏) 削除範囲
Composition
ダイアログ
フレーズフレーズの作成・設定・挿入、フレーズの長さやリピート回数の設定
曲設定タイトル・テンポ、キー等の曲の設定
トラック選択編集トラックの変更・追加/削除、ボリュームやミュート等の設定
楽器選択トラックの使用楽器変更、楽器のランダム選択・選択リセット(iOS独自)
ドラム楽器一覧使用ドラム楽器をリスト表示。使用楽器の編集や並び替え(iOS独自)
ドラム楽器設定ドラム楽器の音量調整・ミュート、削除・複製
ドラム楽器選択トラックの使用ドラム楽器変更、楽器のランダム選択・選択リセット(iOS独自)
Community
(共通)
UI配置
コミュニティディスプレイとコントローラーを表示。縦持ちと横持ちのレイアウト。どのディスプレイ、コントローラーを使用するかは各コミュニティ画面で派生
カテゴリーリスト群カテゴリー選択、カテゴリーリストを表示。どのカテゴリーリストを表示するかは各コミュニティ画面で派生
ページスクロールリストを表示。スワイプでリスト項目を取得。どのリスト項目を使用するかは各カテゴリーで派生
曲リスト項目各コミュニティ画面で派生系を用意する
リレー曲リスト項目左右にスワイプで前後走者の曲を表示
その他リスト項目曲ID:検索で曲ID一覧を表示、ユーザー:ユーザー検索やいいねリスト等で表示
曲詳細曲の情報と貰ったコメントを表示、送るコメントを編集する
曲の情報曲のタイトル、作者、ランキング順位、タグ、ユーザーの反応等を表示
貰ったコメントテキストとOGP特殊コメントの装飾
ソングビジュア曲再生位置の変更と可視化。曲情報でトロフィー変更。リスト/詳細ボタンで切り替え。シンプルのみ実装でリリース後に追加予定。
カテゴリー選択カテゴリータブ表示。スクロール可能。選択表示。
ユーザーアイコンユーザー画像、プレミアムリングを表示。タップでユーザーページへ
プレイヤー曲の再生、いいね・お気に入り等のボタン。現在の状況を反映再生リスト追加ボタン
設定パネルレイアウト設定、ソングビジュア設定、楽器フィルタ リリース後に実装予定
Community
Square
コミュニティ広場
UI配置
ディスプレイ状況によりカテゴリー説明/ソングビジュアを切り替え。
カテゴリー説明広場カテゴリーの説明
コントローラーカテゴリーリスト群/曲詳細を切り替え
カテゴリーリスト群Squareのカテゴリーリストを切り替えるように派生
リスト項目カテゴリー別にリスト項目を派生(ランキングなら左にランク情報)。コンテスト項目はタップでコンテスト画面へ
イベント詳細コンテストの詳細情報の表示
絞り込み検索
Community
UserPage
ユーザーページ
UI配置
ディスプレイユーザープロフィールを表示。下へスワイプした時に隠れてヘッダーが表示されるように
ユーザープロフィールユーザー情報、紹介文、アクティビティログ等表示
ユーザー情報名前、アイコン、リンクリスト、フォロー欄、紹介文表示
リンクリスト外部リンク(X等)ボタンを並べる
フォロー欄フォロー、ミュート、通知ボタン
アクティビティログ活動レベル、投稿曲数やいいね数など表示
ヘッダー
コントローラーディスプレイに追従
カテゴリーリスト群UserPageのカテゴリーリストを切り替えるように派生
リスト項目開閉するプレイリスト項目を作成。
Community
Contest
コンテスト結果
UI配置
ディスプレイ状況によりコンテスト概要/ソングビジュアを切り替え。
コンテスト概要コンテストのテーマ、内容、提案者の表示
コントローラーカテゴリーリスト群/曲詳細を切り替え
カテゴリーリスト群Contestのカテゴリーリストを切り替えるように派生
リスト項目コンテストの順位や自分の投票数を表示するリスト項目に派生
Community
ダイアログ
リストダイアログいいね・お気に入りをしたユーザーリスト表示、曲を含む再生リストの表示
メッセージアラート通知するテキストを知らせる(DLした時や削除確認など)
プロフィール編集名前、アイコン、紹介文等を編集
プレイリスト詳細プレイリストのタイトル、説明、作者、コメント等を表示
プレイリスト編集タイトル、アイコン、曲リスト等を編集
コンテスト投票開催コンテスト曲の視聴と投票
MIDI詳細曲のテンポ、音符・トラック数、使用楽器等
Composition
Common
作曲共通
データ構造座標とサイズ、状態を保持する。レンダラーやコライダー、通知等のロジック
コンバーターDomainのデータ構造へ変換・逆変換
通知機構Modelに変更があった時に、Viewへ通知して再描画。変更状況を監視してキャッシュ
Changer
曲設定変更
テンポ変更送信MIDI信号の変更
拍子変更フレーズ外音符の削除、横スクロール位置を修正
キー変更送信MIDI Noの増減
鍵盤タイプ変更鍵盤Noに応じて全ての音符位置を修正、縦スクロール位置を修正
編集トラック変更ピアノ鍵盤のサンプラー変更
トラック設定変更トラック名・略称、トラック追加・複製・削除
メロディーツール
FingerTool
指ツール
音符の編集
データ構造フレーズの音符を取得、基点と移動ベクトルを保持して移動する
音符の移動和音や連符は上下のみに制御
音符の影移動中に操作できているかわかりやすいように(iOS独自)
内外判定音符の移動をフレーズ内に留める
衝突判定移動する音符が他の音符に重なったときの挙動
タップ選択タップした音符の子音符も選択・解除
矩形選択囲った音符を選択
音符の入れ替えリズム音符のスライドで重なった音符と入れ替える(iOS独自)
和音の削除和音を移動した時に重なる時に削除する
連符に切り替えリズム音符タップで切り替え
PenTool
ペンツール
音符の作成
データ構造音符を作成・分割・統合、フレーズへ音符を追加する
音符の作成タップで音符を作成。分割線に合わせて長さを決定
音符列の作成スワイプに沿って複数の音符を作成。音階変わる時に音符分割
有無判定タップやスワイプした縦ラインに既に音符があるか判定
音符の移動音符が既にある場合は、作成ではなく移動。一定距離進むと移動終了
音符の分割リズム音符をタップした時、音符を分割、メロディ線に沿ってY位置を動かす
音符の統合2つのリズム音符の間をタップした場合、音符を統合
音符の伸縮リズム音符を左右にスワイプすることで音符の長さを伸縮、始点で分割なし(仕様変更)
音符の消滅音符の伸縮をした時に長さが0になると削除する(iOS独自)
領域差演算音符伸縮で他の音符に重なる時は差演算して他の音符長さを削る
サンプリング補間素早くスワイプしても音符が移動できるようにサンプリング間を補間する
細かい音符分割線内の細かな音符を移動する挙動
EraserTool
消しゴムツール
音符の削除
データ構造和音と連符の認識、フレーズから音符を削除する
音符の削除タップで音符を削除
和音・連符の削除和音・連符をタップで和音・連符のみを削除(iOS独自)
音符種別判定タップした音符が和音・連符・ルート音符なのか判定する
音符列の削除スワイプで指定する削除範囲内の複数の音符を削除。
和音列の削除リズム音符をスワイプで複数の和音のみを削除。(iOS独自)
休符に切り替えリズム音符タップで休符に切り替える
ドラムツール
PenTool
ペンツール
音符の作成
データ構造ドラム音符を作成、フレーズへ音符を追加・削除する
音符の作成・削除タップでドラム音符を作成。既に音符がある場合は削除
音符列の作成スワイプで跨いだ分割線にドラム音符を作成。
音符列の削除左にスワイプした範囲にある複数のドラム音符を削除。(iOS独自)
FingerTool
指ツール
音符の編集
データ構造フレーズのドラム音符を取得、選択、長さを編集して分割する
音符長さ編集音符を左右スワイプで長さを変更。長さがある時、連符になり長さ0の時連符解除
連符数の編集音符を上下にスワイプで連符数を変更(iOS独自)
タップ選択タップした音符を選択・解除
矩形選択囲った音符を選択
EraserTool
消しゴムツール
音符の削除
データ構造音符と連符の認識、フレーズから音符を削除する
音符の削除音符をタップで削除
休符に切り替え連符をタップで休符に切り替える
音符列の削除スワイプで指定する削除範囲内の複数の音符を削除。
伴奏ツール
PenTool
ペンツール
音符の作成
データ構造伴奏音符を作成、フレーズへ音符を追加・削除、長さの編集、分割・統合する
音符の作成タップで伴奏音符を作成
音符の移動 (回避)音符をスワイプして移動。音符があるとこを回避する。
音符長さ編集・削除音符の右ハンドルを左右にスワイプして長さ変更。長さ0の時削除
音符の分割・統合音符をタップで左右に分割・統合
音符列の削除左にスワイプした範囲にある複数の伴奏音符を削除。
FingerTool
指ツール
音符の編集
データ構造フレーズの伴奏音符を取得、選択、長さを編集、連符切り替え
音符の移動 (上書き)音符をスワイプして移動。移動した場所の音符は削除。
音符長さ編集・削除音符の右ハンドルを左右にスワイプして長さ変更。長さ0の時削除
連符数の編集音符選択時に表示されるピッカーで連符数を変更
タップ選択タップした音符を選択・解除
矩形選択囲った音符を選択
EraserTool
消しゴムツール
音符の削除
データ構造音符と連符の認識、フレーズから音符を削除、休符切り替え
音符の削除音符をタップで削除
休符に切り替え連符をタップで休符に切り替え
音符列の削除スワイプで指定する削除範囲内の複数の音符を削除
PhraseTool
フレーズツール
フレーズの編集
データ構造トラックのフレーズを取得・追加、削除、状態
フレーズの作成・挿入ダイアログで長さとリピートを設定 リピートフレーズは未実装
フレーズの選択2点タップで範囲選択、範囲ガイドタップで選択解除(仕様変更)
フレーズの移動左右スワイプで移動、移動は選択フレーズとスワイプ中のフレーズを含む
フレーズの伸縮サブ編集領域をスワイプした時にフレーズ長さを伸縮、長さ0で削除(iOS独自)
フレーズの貼り付け選択フレーズをコピー・ペースト、サブボタンかフレーズタブタップで挿入、選択解除
周囲有無判定作成する小節の近くにフレーズがあるかの判定、設定できる長さやリピート回数の制御
フレーズボタン・タブツールに応じてフレーズボタン、タブの処理を変更
フレーズの結合連続する2フレーズの接する小節線をタップで結合(iOS独自)
フレーズの分割フレーズをタップで分割(iOS独自)
StampTool
スタンプツール
モチーフの編集
Transform
画面移動
座標変換
画面を上下移動ピアノのスワイプにより
画面を左右移動 スクロールエリアのスワイプにより
画面を拡大・縮小ピンチアウト・インにより基点を画面中心に設定する
画面を拡大・縮小(軸指定)長押しからのドラッグ。ピアノでX軸方向、スクロールエリアでY軸方向
ドラム座標系新しくドラムの座標系を追加。下へ楽器が追加されるため、メロディーと異なり左上原点
MIDI コンバーターCompositionからMIDIのデータ構造へ変換
曲の再生画面左からMIDI再生、Compositionのデータ構造から曲の再生、再生位置の同期
曲の再生(最初から)再生ボタン長押しで最初から再生 最初から再生されるが、画面は最初に移動しない
曲の再生(位置指定)スクロール領域をダブルタップでその位置から再生(iOS独自)
再生速度の変更ドラッグで曲の再生速度を変更(iOS独自)
再生処理の最適化曲に変更がない時はキャッシュを使う、変更通知とキャッシュの管理
Commnity
Common
コミュニティ
データ構造カテゴリ等の曲情報、いいねやお気に入り等のリスポンスを保持
CommunitySongPlayerコミュニティ用にラップした曲プレイヤー
CategoryListsカテゴリーリスト群のモデル。カテゴリー別にフェッチ/キャッシュ
ListInfoカテゴリーリストのモデル、リストのスクロール位置、フェッチするページ番号等
ContextCommunity共通のCommonContextと各画面のContextがある
UserActivityManagerユーザーのアクティビティ(いいね、ミュートユーザー、再生リスト、モチーフ登録、アクセス履歴等)を管理
Service
サービスモデル
ListItemFetcherカテゴリーリスト項目のMLサーバーから取得する
MidiRepositoryMIDIファイルをサーバーから取得して貯める
UserActivityFetcherユーザーの行動をMLサーバーから取得する(再生数、再生リストに含まれているか、コメント等)
MIDI
Common
MIDI共通
データ構造MIDIフォーマットへ出力できる構造
コントローラー曲の読み込みや再生、再生位置の監視や音源の変更などMIDIの扱いを管理する
サンプラーピアノや音符生成時に単体のMidiイベントから音を鳴らす
Service
サービスモデル
MidiPlayerMIDIを再生する
MidiReaderMIDIファイルの読み込み
MidiWriterMIDIファイル出力
Account
Common
アカウント
データ構造ログインできる構造、アカウント情報、ログイン情報、MLユーザー情報
AccountManagerアカウントの管理、ログイン時にMLサーバーと通信
Service
サービスモデル
UserActivityRepositoryユーザーのアクティビティ(いいね、ミュートユーザー、再生リスト、モチーフ登録、アクセス履歴等)を貯める
ServerCommunicationMLサーバーと通信する処理を集約
Domain
データ構造
Json形式
Melody MelodyTrack, MelodyPhrase, NoteContainer, NoteBlock, Note
Drum DrumTrack, DrumPhrase, BeatContainer, Beat
通化 Original, Repeat, Syncの3種のPhraseをジェネリッククラスとプロトコルで抽象化
Service
サービスモデル
SongRederJsonファイルを読み込み、Domainのデータへ変換
SongWriterDomainのデータからJsonファイルへ書き出し
Common
Service
サービスモデル
リポジトリ保存データを管理


実装の詳細

伴奏音符

伴奏音符

伴奏音符は四角形で表示し、右端にハンドルがあります。メロディー音符が角丸に対して、角張っているのが特徴です。
連符は黒枠の中の音符が分割して表示されます。

また、連符は画面の拡大率によって省略表示されます。

連符の省略表示



伴奏ペンツール

伴奏ペンツール

伴奏フレーズ内でタップすることで音符を分割線内に音符を作成します。
右にスワイプをすることで音符作成と同時に長さを指定します。
左にスワイプをして囲った範囲の音符を削除します。


音符の移動と長さの編集

音符をスワイプすることで移動します。移動は分割線にフィットします。画面を拡大することで細かく移動ができます。なお、既にある音符は上書きせずに回避した場所に配置されます。

音符の右端についているハンドルを左右にスワイプすることで長さを伸縮します。
長さが0に縮めた場合は削除になります。

移動と長さ編集


音符の分割・統合

音符内の分割線をタップすることで、音符を左右に分割できます。
逆に左右に音符がある分割線をタップすると統合します。

音符の分割・統合



伴奏指ツール

伴奏指ツール

音符をスワイプで移動します。既にある音符は削除されます。ペンツール移動は回避されるのに対し、指ツール移動は上書きされる違いがあります。
音符のハンドルを左右へスワイプすることで長さを変更します。
タップや矩形選択で音符を選択して、複数同時に長さを変更することができます。
フレーズタブをタップすると、フレーズ内の音符を全選択します。


音符移動時のフィッティング機能

指ツールでは分割線以外にも近くの音符にフィットさせたり、そのまま上下のみ移動することができます。

フィッティング機能


連符数の変更

音符を選択するとピッカーが表示されて連符数を変更することができます。
ピックの仕方はホイールとメニューがあります。

ピッカー(ホイールとメニュー)

メニューはピッカーをタップすると表示される選択肢から選びます。
ホイールは上下スワイプするだけで素早く変更できます。

連符数の変更



伴奏消しゴムツール

伴奏消しゴムツール

音符をタップして削除します。 連符も省略表示の時はタップで削除できます。詳細表示の時はタップで休符に切り替えます。
スワイプで矩形選択した範囲の音符を削除します。



おわりに

伴奏トラックの実装ができました!!
次はハーモニートラック?と思ってましたが、前述通りメロディートラックと大差ないので見送りました。というか今となっては完全にメロディートラックと機能が被ってますね。 (´ヘ`;
(実はリリース当初和音はハーモニートラックしか追加できなかった=3 それはここだけの話੭˙▷˙)੭
なのでハーモニートラックはまた特徴を出せる段階になってから実装しようと思います。

伴奏トラック気に入ってもらえるといいですね ♪
musicLineはメロディーは作りやすいけど、和音を多用する伴奏はイマイチで使いづらいと前々から言われており、
その時から伴奏に特化した伴奏トラックの構想はありましたが気が進まずお蔵入りしてました。
やはり既に完成しているAndroidでは変更する部分がかなり多いので不具合が心配だったり実装が難しかったりするんですね。。iOSで好評だったらAndroidでも頑張ってみようかな?

そんなこんなでiOS版では一味違ったmusicLineを出すことができそうです!iOSリリースする上でAndroidとは違った一押し機能みたいなものを実装しておきたかったので、このタイミングで実装できて良かったです ′◡‵ ノノ☆

次はリピートフレーズを実装していきます。



【iOS】進捗報告 10 (ドラムトラック)

musicLine(iOS)についての進捗。
今回は作曲画面のドラムトラックについて進捗を報告します。

ドラムトラック


実装状況

カテゴリタイトル補足
View
Composition
UI配置
ガイド表示
ドラム音符音符と連符の表示。分割線に乗っていない音符は細く表示(iOS独自)
ドラム盤ピアノ鍵盤の位置にドラムセットを表示
ペンツールガイド(ドラム) 左にスワイプしている時、削除する範囲
指ツールガイド(ドラム) 長さ編集している時、伸ばし線(iOS独自)。矩形選択の範囲
消しゴムツールガイド(ドラム) 削除範囲
Composition
ダイアログ
ドラム楽器一覧使用ドラム楽器をリスト表示。使用楽器の編集や並び替え(iOS独自)
ドラム楽器設定ドラム楽器の音量調整・ミュート、削除・複製
ドラム楽器選択トラックの使用ドラム楽器変更、楽器のランダム選択・選択リセット(iOS独自)
Composition
ドラムツール
PenTool
ペンツール
音符の作成
データ構造ドラム音符を作成、フレーズへ音符を追加・削除する
音符の作成・削除タップでドラム音符を作成。既に音符がある場合は削除
音符列の作成スワイプで跨いだ分割線にドラム音符を作成。
音符列の削除左にスワイプした範囲にある複数のドラム音符を削除。(iOS独自)
FingerTool
指ツール
音符の編集
データ構造フレーズのドラム音符を取得、選択、長さを編集して分割する
音符長さ編集音符を左右スワイプで長さを変更。長さがある時、連符になり長さ0の時連符解除
連符数の編集音符を上下にスワイプで連符数を変更(iOS独自)
タップ選択タップした音符を選択・解除
矩形選択囲った音符を選択
EraserTool
消しゴムツール
音符の削除
データ構造音符と連符の認識、フレーズから音符を削除する
音符の削除音符をタップで削除
休符に切り替え連符をタップで休符に切り替える
音符列の削除スワイプで指定する削除範囲内の複数の音符を削除。
Transform
画面移動
座標変換
ドラム座標系新しくドラムの座標系を追加。下へ楽器が追加されるため、メロディーと異なり左上原点


全進捗マップを表示

カテゴリタイトル補足
View
Common
ダイアログ
アラートメッセージユーザーに通知するコメント
数字ピッカー数字(範囲制限)をポップアップダイアルで取得
項目ピッカー特定の値をポップアップのリスト項目で取得
HTMLテキストテキストスタイルを部分的に変えるため、HTML形式に対応したText
文字制限テキスト編集文字制限付きのTextField、制限文字数を超えは赤文字で閉じる時に切り捨て
全画面テキスト編集複数行のテキストを編集する時に、ポップアップ全画面でTextEditorとキーボード表示
FitScrollView閾値高さで スクロールありorなしを切り替える(画面に収まるときはScrollViewにしない)
Composition
UI配置
ガイド表示
ピアノ
スクロールエリア
小節番号
小節線
分割線拡大率によって間隔を変化
フレーズフレーズがないところはフレーズ作成ボタンを表示
ツールボタン 選択中のツールはツール色にハイライトする
メロディーライン ペンツールでの音符作成時の入力線
メロディー音符 音符の先頭にチョボをつける
リズム音符 ベース音符のみ下に表示
サンプルデータ 手入力したサンプルデータの音符を配置
連符連符は数字で表示、拡大率によって省略
ペンツールガイド長さ編集しているリズム音符、伸ばした時の削る範囲
(ドラム) 左にスワイプしている時、削除する範囲
指ツールガイド移動中の音符影、矩形選択の枠
(ドラム) 長さ編集している時、伸ばし線(iOS独自)。矩形選択の範囲
消しゴムツールガイド削除範囲、和音のみの削除範囲
(ドラム) 削除範囲
フレーズツールガイドフレーズ移動・伸縮のバー、選択範囲テキスト(iOS独自)
フレーズボタンフレーズボタンとサブボタンを配置、ツールに応じてアイコンを変更、画面拡大率に応じて縮小
フレーズタブツールに応じてアイコンを変更、拡大率に応じて縮小、スクロール状態に応じて移動
音符描画の高速化音符が多くても描画できる速さへ最適化
音符の編集状態選択や変更した時に枠線の色変更
音符音階メロディ音符に音階表示
再生バー曲を再生している時に、再生位置をバーで表示
再生ボタン曲を再生/停止を監視して、状態を変更、再生準備が遅い時はインジケーターを表示
再生速度の表示曲の再生速度を表示(iOS独自)
テスト音のガイド鳴っている音階に色をつける
ドラム音符音符と連符の表示。分割線に乗っていない音符は細く表示(iOS独自)
ドラム盤ピアノ鍵盤の位置にドラムセットを表示
Composition
ダイアログ
フレーズフレーズの作成・設定・挿入、フレーズの長さやリピート回数の設定
曲設定タイトル・テンポ、キー等の曲の設定
トラック選択編集トラックの変更・追加/削除、ボリュームやミュート等の設定
楽器選択トラックの使用楽器変更、楽器のランダム選択・選択リセット(iOS独自)
ドラム楽器一覧使用ドラム楽器をリスト表示。使用楽器の編集や並び替え(iOS独自)
ドラム楽器設定ドラム楽器の音量調整・ミュート、削除・複製
ドラム楽器選択トラックの使用ドラム楽器変更、楽器のランダム選択・選択リセット(iOS独自)
Community
(共通)
UI配置
コミュニティディスプレイとコントローラーを表示。縦持ちと横持ちのレイアウト。どのディスプレイ、コントローラーを使用するかは各コミュニティ画面で派生
カテゴリーリスト群カテゴリー選択、カテゴリーリストを表示。どのカテゴリーリストを表示するかは各コミュニティ画面で派生
ページスクロールリストを表示。スワイプでリスト項目を取得。どのリスト項目を使用するかは各カテゴリーで派生
曲リスト項目各コミュニティ画面で派生系を用意する
リレー曲リスト項目左右にスワイプで前後走者の曲を表示
その他リスト項目曲ID:検索で曲ID一覧を表示、ユーザー:ユーザー検索やいいねリスト等で表示
曲詳細曲の情報と貰ったコメントを表示、送るコメントを編集する
曲の情報曲のタイトル、作者、ランキング順位、タグ、ユーザーの反応等を表示
貰ったコメントテキストとOGP特殊コメントの装飾
ソングビジュア曲再生位置の変更と可視化。曲情報でトロフィー変更。リスト/詳細ボタンで切り替え。シンプルのみ実装でリリース後に追加予定。
カテゴリー選択カテゴリータブ表示。スクロール可能。選択表示。
ユーザーアイコンユーザー画像、プレミアムリングを表示。タップでユーザーページへ
プレイヤー曲の再生、いいね・お気に入り等のボタン。現在の状況を反映再生リスト追加ボタン
設定パネルレイアウト設定、ソングビジュア設定、楽器フィルタ リリース後に実装予定
Community
Square
コミュニティ広場
UI配置
ディスプレイ状況によりカテゴリー説明/ソングビジュアを切り替え。
カテゴリー説明広場カテゴリーの説明
コントローラーカテゴリーリスト群/曲詳細を切り替え
カテゴリーリスト群Squareのカテゴリーリストを切り替えるように派生
リスト項目カテゴリー別にリスト項目を派生(ランキングなら左にランク情報)。コンテスト項目はタップでコンテスト画面へ
イベント詳細コンテストの詳細情報の表示
絞り込み検索
Community
UserPage
ユーザーページ
UI配置
ディスプレイユーザープロフィールを表示。下へスワイプした時に隠れてヘッダーが表示されるように
ユーザープロフィールユーザー情報、紹介文、アクティビティログ等表示
ユーザー情報名前、アイコン、リンクリスト、フォロー欄、紹介文表示
リンクリスト外部リンク(X等)ボタンを並べる
フォロー欄フォロー、ミュート、通知ボタン
アクティビティログ活動レベル、投稿曲数やいいね数など表示
ヘッダー
コントローラーディスプレイに追従
カテゴリーリスト群UserPageのカテゴリーリストを切り替えるように派生
リスト項目開閉するプレイリスト項目を作成。
Community
Contest
コンテスト結果
UI配置
ディスプレイ状況によりコンテスト概要/ソングビジュアを切り替え。
コンテスト概要コンテストのテーマ、内容、提案者の表示
コントローラーカテゴリーリスト群/曲詳細を切り替え
カテゴリーリスト群Contestのカテゴリーリストを切り替えるように派生
リスト項目コンテストの順位や自分の投票数を表示するリスト項目に派生
Community
ダイアログ
リストダイアログいいね・お気に入りをしたユーザーリスト表示、曲を含む再生リストの表示
メッセージアラート通知するテキストを知らせる(DLした時や削除確認など)
プロフィール編集名前、アイコン、紹介文等を編集
プレイリスト詳細プレイリストのタイトル、説明、作者、コメント等を表示
プレイリスト編集タイトル、アイコン、曲リスト等を編集
コンテスト投票開催コンテスト曲の視聴と投票
MIDI詳細曲のテンポ、音符・トラック数、使用楽器等
Composition
Common
作曲共通
データ構造座標とサイズ、状態を保持する。レンダラーやコライダー、通知等のロジック
コンバーターDomainのデータ構造へ変換・逆変換
通知機構Modelに変更があった時に、Viewへ通知して再描画。変更状況を監視してキャッシュ
Changer
曲設定変更
テンポ変更送信MIDI信号の変更
拍子変更フレーズ外音符の削除、横スクロール位置を修正
キー変更送信MIDI Noの増減
鍵盤タイプ変更鍵盤Noに応じて全ての音符位置を修正、縦スクロール位置を修正
編集トラック変更ピアノ鍵盤のサンプラー変更
トラック設定変更トラック名・略称、トラック追加・複製・削除
メロディーツール
FingerTool
指ツール
音符の編集
データ構造フレーズの音符を取得、基点と移動ベクトルを保持して移動する
音符の移動和音や連符は上下のみに制御
音符の影移動中に操作できているかわかりやすいように(iOS独自)
内外判定音符の移動をフレーズ内に留める
衝突判定移動する音符が他の音符に重なったときの挙動
タップ選択タップした音符の子音符も選択・解除
矩形選択囲った音符を選択
音符の入れ替えリズム音符のスライドで重なった音符と入れ替える(iOS独自)
和音の削除和音を移動した時に重なる時に削除する
連符に切り替えリズム音符タップで切り替え
PenTool
ペンツール
音符の作成
データ構造音符を作成・分割・統合、フレーズへ音符を追加する
音符の作成タップで音符を作成。分割線に合わせて長さを決定
音符列の作成スワイプに沿って複数の音符を作成。音階変わる時に音符分割
有無判定タップやスワイプした縦ラインに既に音符があるか判定
音符の移動音符が既にある場合は、作成ではなく移動。一定距離進むと移動終了
音符の分割リズム音符をタップした時、音符を分割、メロディ線に沿ってY位置を動かす
音符の統合2つのリズム音符の間をタップした場合、音符を統合
音符の伸縮リズム音符を左右にスワイプすることで音符の長さを伸縮、始点で分割なし(仕様変更)
音符の消滅音符の伸縮をした時に長さが0になると削除する(iOS独自)
領域差演算音符伸縮で他の音符に重なる時は差演算して他の音符長さを削る
サンプリング補間素早くスワイプしても音符が移動できるようにサンプリング間を補間する
細かい音符分割線内の細かな音符を移動する挙動
EraserTool
消しゴムツール
音符の削除
データ構造和音と連符の認識、フレーズから音符を削除する
音符の削除タップで音符を削除
和音・連符の削除和音・連符をタップで和音・連符のみを削除(iOS独自)
音符種別判定タップした音符が和音・連符・ルート音符なのか判定する
音符列の削除スワイプで指定する削除範囲内の複数の音符を削除。
和音列の削除リズム音符をスワイプで複数の和音のみを削除。(iOS独自)
休符に切り替えリズム音符タップで休符に切り替える
ドラムツール
PenTool
ペンツール
音符の作成
データ構造ドラム音符を作成、フレーズへ音符を追加・削除する
音符の作成・削除タップでドラム音符を作成。既に音符がある場合は削除
音符列の作成スワイプで跨いだ分割線にドラム音符を作成。
音符列の削除左にスワイプした範囲にある複数のドラム音符を削除。(iOS独自)
FingerTool
指ツール
音符の編集
データ構造フレーズのドラム音符を取得、選択、長さを編集して分割する
音符長さ編集音符を左右スワイプで長さを変更。長さがある時、連符になり長さ0の時連符解除
連符数の編集音符を上下にスワイプで連符数を変更(iOS独自)
タップ選択タップした音符を選択・解除
矩形選択囲った音符を選択
EraserTool
消しゴムツール
音符の削除
データ構造音符と連符の認識、フレーズから音符を削除する
音符の削除音符をタップで削除
休符に切り替え連符をタップで休符に切り替える
音符列の削除スワイプで指定する削除範囲内の複数の音符を削除。
PhraseTool
フレーズツール
フレーズの編集
データ構造トラックのフレーズを取得・追加、削除、状態
フレーズの作成・挿入ダイアログで長さとリピートを設定 リピートフレーズは未実装
フレーズの選択2点タップで範囲選択、範囲ガイドタップで選択解除(仕様変更)
フレーズの移動左右スワイプで移動、移動は選択フレーズとスワイプ中のフレーズを含む
フレーズの伸縮サブ編集領域をスワイプした時にフレーズ長さを伸縮、長さ0で削除(iOS独自)
フレーズの貼り付け選択フレーズをコピー・ペースト、サブボタンかフレーズタブタップで挿入、選択解除
周囲有無判定作成する小節の近くにフレーズがあるかの判定、設定できる長さやリピート回数の制御
フレーズボタン・タブツールに応じてフレーズボタン、タブの処理を変更
フレーズの結合連続する2フレーズの接する小節線をタップで結合(iOS独自)
フレーズの分割フレーズをタップで分割(iOS独自)
StampTool
スタンプツール
モチーフの編集
Transform
画面移動
座標変換
画面を上下移動ピアノのスワイプにより
画面を左右移動 スクロールエリアのスワイプにより
画面を拡大・縮小ピンチアウト・インにより基点を画面中心に設定する
画面を拡大・縮小(軸指定)長押しからのドラッグ。ピアノでX軸方向、スクロールエリアでY軸方向
ドラム座標系新しくドラムの座標系を追加。下へ楽器が追加されるため、メロディーと異なり左上原点
MIDI コンバーターCompositionからMIDIのデータ構造へ変換
曲の再生画面左からMIDI再生、Compositionのデータ構造から曲の再生、再生位置の同期
曲の再生(最初から)再生ボタン長押しで最初から再生 最初から再生されるが、画面は最初に移動しない
曲の再生(位置指定)スクロール領域をダブルタップでその位置から再生(iOS独自)
再生速度の変更ドラッグで曲の再生速度を変更(iOS独自)
再生処理の最適化曲に変更がない時はキャッシュを使う、変更通知とキャッシュの管理
Commnity
Common
コミュニティ
データ構造カテゴリ等の曲情報、いいねやお気に入り等のリスポンスを保持
CommunitySongPlayerコミュニティ用にラップした曲プレイヤー
CategoryListsカテゴリーリスト群のモデル。カテゴリー別にフェッチ/キャッシュ
ListInfoカテゴリーリストのモデル、リストのスクロール位置、フェッチするページ番号等
ContextCommunity共通のCommonContextと各画面のContextがある
UserActivityManagerユーザーのアクティビティ(いいね、ミュートユーザー、再生リスト、モチーフ登録、アクセス履歴等)を管理
Service
サービスモデル
ListItemFetcherカテゴリーリスト項目のMLサーバーから取得する
MidiRepositoryMIDIファイルをサーバーから取得して貯める
UserActivityFetcherユーザーの行動をMLサーバーから取得する(再生数、再生リストに含まれているか、コメント等)
MIDI
Common
MIDI共通
データ構造MIDIフォーマットへ出力できる構造
コントローラー曲の読み込みや再生、再生位置の監視や音源の変更などMIDIの扱いを管理する
サンプラーピアノや音符生成時に単体のMidiイベントから音を鳴らす
Service
サービスモデル
MidiPlayerMIDIを再生する
MidiReaderMIDIファイルの読み込み
MidiWriterMIDIファイル出力
Account
Common
アカウント
データ構造ログインできる構造、アカウント情報、ログイン情報、MLユーザー情報
AccountManagerアカウントの管理、ログイン時にMLサーバーと通信
Service
サービスモデル
UserActivityRepositoryユーザーのアクティビティ(いいね、ミュートユーザー、再生リスト、モチーフ登録、アクセス履歴等)を貯める
ServerCommunicationMLサーバーと通信する処理を集約
Domain
データ構造
Json形式
Melody MelodyTrack, MelodyPhrase, NoteContainer, NoteBlock, Note
Drum DrumTrack, DrumPhrase, BeatContainer, Beat
通化 Original, Repeat, Syncの3種のPhraseをジェネリッククラスとプロトコルで抽象化
Service
サービスモデル
SongRederJsonファイルを読み込み、Domainのデータへ変換
SongWriterDomainのデータからJsonファイルへ書き出し
Common
Service
サービスモデル
リポジトリ保存データを管理


実装の詳細

ドラム音符

ドラム音符

ドラム音符は縦線で表示します。分割線上にある音符は太くなります。
連符は音符長さ分の尾ひれがつきます。


Androidからの仕様変更 Androidでは単符でも尾ひれをつけて、連符の色を変えて識別していました。ただリピート音符や選択音符など色を変えて識別する要素は他にもあり、この仕様の紛らわしさが気に入ってませんでした。
iOSでは単符は尾ひれなし、連符は幅分の尾ひれ付きにしました。尾ひれを無くすと見づらくなるため、分割線上の音符は太くしました。
Androidの単符と連符


ドラムペンツール

ドラムペンツール

ドラムフレーズ内の分割線をタップすることで、ドラム音符の作成・削除を切り替えます。
右へスワイプすることで、連続で分割線にドラム音符を置くことができます。

Androidからの仕様変更 Androidでは分割線の間をタップすることで左の分割線にドラム音符を作成していましたが、以前からタップする位置と音符の位置がズレることがわかりにくいとのご指摘がありました。
iOSでは分割線の位置へ直接タップすることでその位置に音符を置くようにして、より直感的な操作にしました。
分割線間(Android)と分割線上(iOS)
左スワイプで削除 (iOS独自)

右スワイプで作成、左にスワイプすると囲った範囲の音符を削除します。
タップで削除することもできますが、もう少し消したい時は消しゴムツールに切り替えなくても消せるのであれば便利かと思います。

左スワイプで削除


ドラム指ツール

ドラム指ツール

音符を左右スワイプで長さを変更します。
長さができると、3連符になります。逆に長さがなくなると、連符が解除されます。
タップや矩形選択で音符を選択して、複数同時に長さを変更することができます。
フレーズタブをタップすると、フレーズ内の音符を全選択します。

上下スワイプで連符数を変更 (iOS独自)

上下にスワイプすることで素早く直感的に連符数を変更します。

上下スワイプで連符数を変更

音符伸ばしガイド線 (iOS独自)

音符の長さを変更時に音符は分割線毎に伸び縮みしますが、伸ばし加減をよりわかりやすくするためのガイドが付きます。

音符伸ばしガイド線


ドラム消しゴムツール

ドラム消しゴムツール

音符をタップして削除します。 連符はタップで休符に切り替えます。
スワイプで矩形選択した範囲の音符を削除します。


ドラムダイアログ

ドラム楽器一覧
ドラム楽器選択
ドラム楽器設定

ドラム楽器一覧で楽器変更や音量を調整します。
ドラム楽器選択ではランダムとリセットボタンを追加しました。
ドラム楽器設定で削除や複製ができます。

ドラム楽器並び替え (iOS独自)

楽器リストをスワイプすることで並び替えします。また削除も簡単にできます。

ドラム楽器並び替え



おわりに

ドラムトラックの実装ができました =3 =3
紹介できないほどの細かい部分(座標変換など)の基盤作りが地味に大変だったけど、なんとかドラム終わりました ^^

Androidで届いている要望をiOSでは最初から盛り込めてよかった!
(完成した後だったら、なかなか手が付けづらいんですよね...バグとか怖いし(´∩`。))
より使いやすくなればと思います。
特にドラム楽器並び替えは嬉しいんじゃないでしょうかᐠ( ᐢ ᵕ ᐢ )ᐟ

次はハーモニートラック??の実装していきます。



【iOS】進捗報告 9 (3大作曲ダイアログ)

musicLine(iOS)についての進捗。
今回は作曲画面の3大ダイアログについて進捗を報告します。

曲設定ダイアログ

トラック選択ダイアログ

楽器選択ダイアログ


実装状況

カテゴリタイトル補足
View
Common
ダイアログ
アラートメッセージユーザーに通知するコメント
数字ピッカー数字(範囲制限)をポップアップダイアルで取得
項目ピッカー特定の値をポップアップのリスト項目で取得
HTMLテキストテキストスタイルを部分的に変えるため、HTML形式に対応したText
文字制限テキスト編集文字制限付きのTextField、制限文字数を超えは赤文字で閉じる時に切り捨て
全画面テキスト編集複数行のテキストを編集する時に、ポップアップ全画面でTextEditorとキーボード表示
FitScrollView閾値高さで スクロールありorなしを切り替える(画面に収まるときはScrollViewにしない)
Composition
ダイアログ
曲設定タイトル・テンポ、キー等の曲の設定
トラック選択編集トラックの変更・追加/削除、ボリュームやミュート等の設定
楽器選択トラックの使用楽器変更、楽器のランダム選択・選択リセット(iOS独自)
Composition
Changer
曲設定変更
テンポ変更送信MIDI信号の変更
拍子変更フレーズ外音符の削除、横スクロール位置を修正
キー変更送信MIDI Noの増減
鍵盤タイプ変更鍵盤Noに応じて全ての音符位置を修正、縦スクロール位置を修正
編集トラック変更ピアノ鍵盤のサンプラー変更
トラック設定変更トラック名・略称、トラック追加・複製・削除


全進捗マップを表示

カテゴリタイトル補足
View
Common
ダイアログ
アラートメッセージユーザーに通知するコメント
数字ピッカー数字(範囲制限)をポップアップダイアルで取得
項目ピッカー特定の値をポップアップのリスト項目で取得
HTMLテキストテキストスタイルを部分的に変えるため、HTML形式に対応したText
文字制限テキスト編集文字制限付きのTextField、制限文字数を超えは赤文字で閉じる時に切り捨て
全画面テキスト編集複数行のテキストを編集する時に、ポップアップ全画面でTextEditorとキーボード表示
FitScrollView閾値高さで スクロールありorなしを切り替える(画面に収まるときはScrollViewにしない)
Composition
UI配置
ガイド表示
ピアノ
スクロールエリア
小節番号
小節線
分割線拡大率によって間隔を変化
フレーズフレーズがないところはフレーズ作成ボタンを表示
ツールボタン 選択中のツールはツール色にハイライトする
メロディーライン ペンツールでの音符作成時の入力線
メロディー音符 音符の先頭にチョボをつける
リズム音符 ベース音符のみ下に表示
サンプルデータ 手入力したサンプルデータの音符を配置
連符連符は数字で表示、拡大率によって省略
ツールガイド(ペン)長さ編集しているリズム音符、伸ばした時の削る範囲音符移動時、移動先の音階をわかりやすくする
ツールガイド(指)移動中の音符影、矩形選択の枠
ツールガイド(消しゴム)削除範囲、和音のみの削除範囲
ツールガイド(フレーズ)フレーズ移動・伸縮のバー、選択範囲テキスト(iOS独自)
フレーズボタンフレーズボタンとサブボタンを配置、ツールに応じてアイコンを変更、画面拡大率に応じて縮小
フレーズタブツールに応じてアイコンを変更、拡大率に応じて縮小、スクロール状態に応じて移動
音符描画の高速化音符が多くても描画できる速さへ最適化
音符の編集状態選択や変更した時に枠線の色変更
音符音階メロディ音符に音階表示
再生バー曲を再生している時に、再生位置をバーで表示
再生ボタン曲を再生/停止を監視して、状態を変更、再生準備が遅い時はインジケーターを表示
再生速度の表示曲の再生速度を表示(iOS独自)
テスト音のガイド鳴っている音階に色をつける
Composition
ダイアログ
フレーズフレーズの作成・設定・挿入、フレーズの長さやリピート回数の設定
曲設定タイトル・テンポ、キー等の曲の設定
トラック選択編集トラックの変更・追加/削除、ボリュームやミュート等の設定
楽器選択トラックの使用楽器変更、楽器のランダム選択・選択リセット(iOS独自)
Community
(共通)
UI配置
コミュニティディスプレイとコントローラーを表示。縦持ちと横持ちのレイアウト。どのディスプレイ、コントローラーを使用するかは各コミュニティ画面で派生
カテゴリーリスト群カテゴリー選択、カテゴリーリストを表示。どのカテゴリーリストを表示するかは各コミュニティ画面で派生
ページスクロールリストを表示。スワイプでリスト項目を取得。どのリスト項目を使用するかは各カテゴリーで派生
曲リスト項目各コミュニティ画面で派生系を用意する
リレー曲リスト項目左右にスワイプで前後走者の曲を表示
その他リスト項目曲ID:検索で曲ID一覧を表示、ユーザー:ユーザー検索やいいねリスト等で表示
曲詳細曲の情報と貰ったコメントを表示、送るコメントを編集する
曲の情報曲のタイトル、作者、ランキング順位、タグ、ユーザーの反応等を表示
貰ったコメントテキストとOGP特殊コメントの装飾
ソングビジュア曲再生位置の変更と可視化。曲情報でトロフィー変更。リスト/詳細ボタンで切り替え。シンプルのみ実装でリリース後に追加予定。
カテゴリー選択カテゴリータブ表示。スクロール可能。選択表示。
ユーザーアイコンユーザー画像、プレミアムリングを表示。タップでユーザーページへ
プレイヤー曲の再生、いいね・お気に入り等のボタン。現在の状況を反映再生リスト追加ボタン
設定パネルレイアウト設定、ソングビジュア設定、楽器フィルタ リリース後に実装予定
Community
Square
コミュニティ広場
UI配置
ディスプレイ状況によりカテゴリー説明/ソングビジュアを切り替え。
カテゴリー説明広場カテゴリーの説明
コントローラーカテゴリーリスト群/曲詳細を切り替え
カテゴリーリスト群Squareのカテゴリーリストを切り替えるように派生
リスト項目カテゴリー別にリスト項目を派生(ランキングなら左にランク情報)。コンテスト項目はタップでコンテスト画面へ
イベント詳細コンテストの詳細情報の表示
絞り込み検索
Community
UserPage
ユーザーページ
UI配置
ディスプレイユーザープロフィールを表示。下へスワイプした時に隠れてヘッダーが表示されるように
ユーザープロフィールユーザー情報、紹介文、アクティビティログ等表示
ユーザー情報名前、アイコン、リンクリスト、フォロー欄、紹介文表示
リンクリスト外部リンク(X等)ボタンを並べる
フォロー欄フォロー、ミュート、通知ボタン
アクティビティログ活動レベル、投稿曲数やいいね数など表示
ヘッダー
コントローラーディスプレイに追従
カテゴリーリスト群UserPageのカテゴリーリストを切り替えるように派生
リスト項目開閉するプレイリスト項目を作成。
Community
Contest
コンテスト結果
UI配置
ディスプレイ状況によりコンテスト概要/ソングビジュアを切り替え。
コンテスト概要コンテストのテーマ、内容、提案者の表示
コントローラーカテゴリーリスト群/曲詳細を切り替え
カテゴリーリスト群Contestのカテゴリーリストを切り替えるように派生
リスト項目コンテストの順位や自分の投票数を表示するリスト項目に派生
Community
ダイアログ
リストダイアログいいね・お気に入りをしたユーザーリスト表示、曲を含む再生リストの表示
メッセージアラート通知するテキストを知らせる(DLした時や削除確認など)
プロフィール編集名前、アイコン、紹介文等を編集
プレイリスト詳細プレイリストのタイトル、説明、作者、コメント等を表示
プレイリスト編集タイトル、アイコン、曲リスト等を編集
コンテスト投票開催コンテスト曲の視聴と投票
MIDI詳細曲のテンポ、音符・トラック数、使用楽器等
Composition
Common
作曲共通
データ構造座標とサイズ、状態を保持する。レンダラーやコライダー、通知等のロジック
コンバーターDomainのデータ構造へ変換・逆変換
通知機構Modelに変更があった時に、Viewへ通知して再描画。変更状況を監視してキャッシュ
Changer
曲設定変更
テンポ変更送信MIDI信号の変更
拍子変更フレーズ外音符の削除、横スクロール位置を修正
キー変更送信MIDI Noの増減
鍵盤タイプ変更鍵盤Noに応じて全ての音符位置を修正、縦スクロール位置を修正
編集トラック変更ピアノ鍵盤のサンプラー変更
トラック設定変更トラック名・略称、トラック追加・複製・削除
FingerTool
指ツール
音符の編集
データ構造フレーズの音符を取得、基点と移動ベクトルを保持して移動する
音符の移動和音や連符は上下のみに制御
音符の影移動中に操作できているかわかりやすいように(iOS独自)
内外判定音符の移動をフレーズ内に留める
衝突判定移動する音符が他の音符に重なったときの挙動
タップ選択タップした音符の子音符も選択・解除
矩形選択囲った音符を選択
音符の入れ替えリズム音符のスライドで重なった音符と入れ替える(iOS独自)
和音の削除和音を移動した時に重なる時に削除する
連符に切り替えリズム音符タップで切り替え
PenTool
ペンツール
音符の作成
データ構造音符を作成・分割・統合、フレーズへ音符を追加する
音符の作成タップで音符を作成。分割線に合わせて長さを決定
音符列の作成スワイプに沿って複数の音符を作成。音階変わる時に音符分割
有無判定タップやスワイプした縦ラインに既に音符があるか判定
音符の移動音符が既にある場合は、作成ではなく移動。一定距離進むと移動終了
音符の分割リズム音符をタップした時、音符を分割、メロディ線に沿ってY位置を動かす
音符の統合2つのリズム音符の間をタップした場合、音符を統合
音符の伸縮リズム音符を左右にスワイプすることで音符の長さを伸縮、始点で分割なし(仕様変更)
音符の消滅音符の伸縮をした時に長さが0になると削除する(iOS独自)
領域差演算音符伸縮で他の音符に重なる時は差演算して他の音符長さを削る
サンプリング補間素早くスワイプしても音符が移動できるようにサンプリング間を補間する
細かい音符分割線内の細かな音符を移動する挙動
EraserTool
消しゴムツール
音符の削除
データ構造和音と連符の認識、フレーズから音符を削除する
音符の削除タップで音符を削除
和音・連符の削除和音・連符をタップで和音・連符のみを削除(iOS独自)
音符種別判定タップした音符が和音・連符・ルート音符なのか判定する
音符列の削除スワイプで指定する削除範囲内の複数の音符を削除。
和音列の削除リズム音符をスワイプで複数の和音のみを削除。(iOS独自)
休符に切り替えリズム音符タップで休符に切り替える
PhraseTool
フレーズツール
フレーズの編集
データ構造トラックのフレーズを取得・追加、削除、状態
フレーズの作成・挿入ダイアログで長さとリピートを設定 リピートフレーズは未実装
フレーズの選択2点タップで範囲選択、範囲ガイドタップで選択解除(仕様変更)
フレーズの移動左右スワイプで移動、移動は選択フレーズとスワイプ中のフレーズを含む
フレーズの伸縮サブ編集領域をスワイプした時にフレーズ長さを伸縮、長さ0で削除(iOS独自)
フレーズの貼り付け選択フレーズをコピー・ペースト、サブボタンかフレーズタブタップで挿入、選択解除
周囲有無判定作成する小節の近くにフレーズがあるかの判定、設定できる長さやリピート回数の制御
フレーズボタン・タブツールに応じてフレーズボタン、タブの処理を変更
フレーズの結合連続する2フレーズの接する小節線をタップで結合(iOS独自)
フレーズの分割フレーズをタップで分割(iOS独自)
StampTool
スタンプツール
モチーフの編集
Transform
画面移動
座標変換
画面を上下移動ピアノのスワイプにより
画面を左右移動 スクロールエリアのスワイプにより
画面を拡大・縮小ピンチアウト・インにより基点を画面中心に設定する
画面を拡大・縮小(軸指定)長押しからのドラッグ。ピアノでX軸方向、スクロールエリアでY軸方向
MIDI コンバーターCompositionからMIDIのデータ構造へ変換
曲の再生画面左からMIDI再生、Compositionのデータ構造から曲の再生、再生位置の同期
曲の再生(最初から)再生ボタン長押しで最初から再生 最初から再生されるが、画面は最初に移動しない
曲の再生(位置指定)スクロール領域をダブルタップでその位置から再生(iOS独自)
再生速度の変更ドラッグで曲の再生速度を変更(iOS独自)
再生処理の最適化曲に変更がない時はキャッシュを使う、変更通知とキャッシュの管理
Commnity
Common
コミュニティ
データ構造カテゴリ等の曲情報、いいねやお気に入り等のリスポンスを保持
CommunitySongPlayerコミュニティ用にラップした曲プレイヤー
CategoryListsカテゴリーリスト群のモデル。カテゴリー別にフェッチ/キャッシュ
ListInfoカテゴリーリストのモデル、リストのスクロール位置、フェッチするページ番号等
ContextCommunity共通のCommonContextと各画面のContextがある
UserActivityManagerユーザーのアクティビティ(いいね、ミュートユーザー、再生リスト、モチーフ登録、アクセス履歴等)を管理
Service
サービスモデル
ListItemFetcherカテゴリーリスト項目のMLサーバーから取得する
MidiRepositoryMIDIファイルをサーバーから取得して貯める
UserActivityFetcherユーザーの行動をMLサーバーから取得する(再生数、再生リストに含まれているか、コメント等)
MIDI
Common
MIDI共通
データ構造MIDIフォーマットへ出力できる構造
コントローラー曲の読み込みや再生、再生位置の監視や音源の変更などMIDIの扱いを管理する
サンプラーピアノや音符生成時に単体のMidiイベントから音を鳴らす
Service
サービスモデル
MidiPlayerMIDIを再生する
MidiReaderMIDIファイルの読み込み
MidiWriterMIDIファイル出力
Account
Common
アカウント
データ構造ログインできる構造、アカウント情報、ログイン情報、MLユーザー情報
AccountManagerアカウントの管理、ログイン時にMLサーバーと通信
Service
サービスモデル
UserActivityRepositoryユーザーのアクティビティ(いいね、ミュートユーザー、再生リスト、モチーフ登録、アクセス履歴等)を貯める
ServerCommunicationMLサーバーと通信する処理を集約
Domain
データ構造
Json形式
Melody MelodyTrack, MelodyPhrase, NoteContainer, NoteBlock, Note
Drum DrumTrack, DrumPhrase, BeatContainer, Beat
通化 Original, Repeat, Syncの3種のPhraseをジェネリッククラスとプロトコルで抽象化
Service
サービスモデル
SongRederJsonファイルを読み込み、Domainのデータへ変換
SongWriterDomainのデータからJsonファイルへ書き出し
Common
Service
サービスモデル
リポジトリ保存データを管理


実装の詳細

曲設定ダイアログ

以下の曲設定を変更します。

  • タイトル
  • テンポ
  • 拍子
  • キー
  • 鍵盤種別

曲設定ダイアログ

曲設定の変更時に、変更した音を確認できるように曲を再生します。
設定変更時にトラック毎に保持しているMIDIキャッシュを全てクリアします。


拍子の変更

拍子変更で、1小節の拍数と1拍の長さを設定するため、小節長さが変わります。
小節長さが短くなる時、フレーズ外に出た音符を削除します。また、音符がフレーズの境目にある時、フレーズ外に出ないように音符長さを短くします。

変更前 4/4
変更後 2/4

なお小節長さを変更すると、横スクロール位置がズレてしまうので、現在の小節位置を維持するように位置を修正します。

また小節長さが短くなる時、フレーズ外の音符を削除して良いかアラートで知らせます。
(今後UNDO/REDO機能が実装されても元に戻せない処理)

変更時アラート


鍵盤種別の変更

鍵盤の変更に応じて、音符のY位置を変更します。
黒鍵盤を挿入する際は音階の変更はありませんが、ツール編集の都合で下からの鍵盤インデックスで保持しているため、音符Y位置の変更が必要です。

黒鍵盤OFF
黒鍵盤ON

なお鍵盤数が変わると、縦スクロール位置がズレてしまうので、画面中心の鍵盤位置を維持するように位置を修正します。

黒鍵盤を除去する場合は、黒鍵盤の音階が変わってしまうため、アラートで知らせます。

変更時アラート

ちなみに、黒鍵盤ON/OFFではピアノの見た目が変わります。OFFの場合は黒鍵盤を使わないので目立たないようにしてます。



トラック 選択/設定 ダイアログ

トラック一覧を表示し、編集するトラックを選択します。
編集トラック選択時に、ピアノ鍵盤のサンプラーをトラックの使用楽器へ変更します。

このダイアログで新しいトラックを追加/複製、削除も行います。
また、以下のトラック設定を変更できます。

  • ボリューム
  • ミュート設定
  • 可視設定
  • トラック名/略称
  • メモ
  • 使用楽器

トラック選択/設定ダイアログ


トラックの音符色

編集トラックの音符は青色ですが、背景トラックは音符色でわかるようにトラック毎に色が変わります。
なお、ミュートトラックは灰色で可視設定で非表示にすることもできます。

トラックの音符色

乗算ブレンディング 背景トラックの描画ブレンドには乗算を使用しています。
重なった部分を見せるために、半透明にしてアルファブレンドすることが一般的ですが、半透明だと重ならないときが見えづらくなるので、乗算ブレンドにしています。
乗算ブレンドでは重なったときのみ色が変わるため、編集トラックの音符よりも目立たないような薄い色を使用している場合に有効です。



楽器選択ダイアログ

トラックの使用楽器を選択します。
ダイアログ開く際に、現在使用している楽器にスクロールします。またカテゴリーを変更する時には、リストの先頭へスクロールします。

楽器選択ダイアログ

楽器選択時に変更した楽器で曲を再生します。
選択した楽器をもう一度タップするとダイアログを閉じます。


ランダム・リセットボタン(iOS独自)

カテゴリーの最後にランダムボタンとリセットボタンを追加しました。
楽器選びに迷った時はランダムボタンで楽器をランダムに選択します。思いもよらぬ曲ができるかも!?
楽器選択で迷ったけど元の楽器へ戻したい時はリセットボタンを使ってください。



他のダイアログ

アラートメッセージ

ユーザーにコメントを通知して、判断を仰ぐダイアログです。
ボタンの数は1, 2, 3と変更でき、選択肢を選ぶことができます。
汎用的に使用できるように、モデルから表示要求して選択肢に応じてコールバックするように作りました。

アラートメッセージ

数字ピッカー

テキストをタップした時にポップアップで数字ダイアログを表示します。
数字の範囲を決めれますが、ステップは1固定です。

数字ピッカー

項目ピッカー

テキストをタップした時に、テキストの下にポップアップでリストを表示します。
リスト項目は数字に限らず、@Bindingで選択した値を取得します。

項目ピッカー

HTMLテキスト

部分的にテキストスタイルを変更できる、HTML形式に対応したTextです。

TextWithHTML("fps : <font size='+5' color='red'>30</font>", defultColor: .blue)

HTMLテキスト

文字制限テキスト編集

文字数制限を設定できるTextFieldです。
制限文字数を超える時は赤文字になります。なお赤文字のままダイアログを閉じると切り捨てになります。

文字制限テキスト編集

全画面テキスト編集

テキストをタップした時に、ポップアップで全体にTextEditorとキーボードを表示します。複数行のテキストを編集する時に、他に余計な項目があると邪魔だったりするので実装しました。

また文字数制限の設定もでき、制限数を超えた時は決定ができなくしてます。

全画面テキスト編集
文字数制限を超えた時
曲再生時の挙動

曲の再生中は鳴っている音階の鍵盤に色をつけます。

鳴っている鍵盤に色

曲再生中に音符・フレーズに変更があれば、色がつきます。
再生中の変更はすぐに音に反映されず、再度再生した時に変更が反映されます。

再生中の音符色



おわりに

作曲で主に使うダイアログ3種はスムーズに実装できましたー^ ^
特に編集トラックの変更は、意味不明な不具合が出るんだろうなと意気込んでましたが、意外と最小限の修正に収まることが出来ました!!
さらに数字ピッカーや項目ピッカーなどは今後のダイアログ作りにも役立ちそうですᐠ( ᐢ ᵕ ᐢ )ᐟ

次からはドラムトラックを実装していきます。



【iOS】進捗報告 8 (コミュニティ)

musicLine(iOS)についての進捗。
コミュニティについて報告します。

カテゴリーリスト
プレイヤー/詳細画面
コンテスト/ユーザーページ


はじめに

今まで作曲画面の進捗を報告していましたが、一時中断してコミュニティの開発を進めてたので今回はコミュニティの進捗です。
最近全然ブログ更新できてなかったので、今回は大ボリュームです!!画像だけでも見てってください〜😂

では、まず画面構成を確認してから実装状況を見ていきたいと思います。


画面構成

Androidアプリのスクショで画面構成を確認します。

コミュニティの3画面
コミュニティ広場
Square
ユーザーページ
UserPage
コンテスト
Contest

コミュニティ広場と命名 コミュニティと言えば、新着やランキングカテゴリー等ある画面を指しますが、設計/実装する時にはコミュニティ広場Squareとします。
これはより正確に認識を合わせるためです。
コミュニティ3画面の構成は似たような作りになっており(特にコミュニティ広場とコンテスト)、共通の処理を使い回したりします。その際に、Community表記だとコミュニティ3画面全体を指すのか、コミュニティ広場を指すのかが名前だけでは分からないのが問題になりました。そのため、Community表記だと3画面全体、Squareだとコミュニティ広場と定義し、クラスや関数名だけで関係性がわかるようにしました。


ディスプレイとコントローラー

コミュニティの3画面は似たような画面構成になっており、各画面をディスプレイDisplayとコントローラーController の領域に分けて設計します。

コミュニティ広場
Square
ユーザーページ
UserPage
コンテスト
Contest


ディスプレイ

ディスプレイDisplayは、画面上部(横持ちだと画面左部)の領域を指します。
広場・コンテストではカテゴリー説明やコンテスト内容が表示され、曲選択でソングビジュアSongVisuaに切り替わります。
ユーザーページのディスプレイはスクロールで隠れるように動作します。

ディスプレイ


コントローラー

コントローラーControllerは、画面下部(横持ちだと画面右部)の領域を指します。
3画面ともヘッダーには横一列にカテゴリータブが並び、選択できるようになっています。(カテゴリーによりヘッダーの一部が変わります)
カテゴリー選択でリストCategoryListが表示され、項目CategoryListItemをタップして曲やコンテストを選択します。
なお、コントローラーは項目の選択だけではなく、詳細画面に切り替えて内容を確認する役割もあります。

コントローラー

画面構成の意義 画面構成を考えることは複数の利点があります。
例えば、画面構成を分析することでコミュニティ3画面で似たような部分がわかり、共通化につながります。また画面構成の名前を決めることで、変数や関数名等の表記ブレを無くし、勘違いによる不具合を防ぎます。さらに画面構成を決めることで進捗報告等の認識合わせする時に、どの部分について言及しているのかが正確にわかります。
ただ、あまり正確に決めすぎると面倒くさくなるので、外枠の大事なところだけに絞る方がいいと思います。やっぱり追加実装や開発を進めていくと設計通りにはいかず、設計書の内容と異なっていきます。その違いを修正するにも労力がいるので、バランスは考えないといけないですね。


実装状況
カテゴリタイトル補足
View
Community
(共通)
UI配置
コミュニティディスプレイとコントローラーを表示。縦持ちと横持ちのレイアウト。どのディスプレイ、コントローラーを使用するかは各コミュニティ画面で派生
カテゴリーリスト群カテゴリー選択、カテゴリーリストを表示。どのカテゴリーリストを表示するかは各コミュニティ画面で派生
ページスクロールリストを表示。スワイプでリスト項目を取得。どのリスト項目を使用するかは各カテゴリーで派生
曲リスト項目各コミュニティ画面で派生系を用意する
リレー曲リスト項目左右にスワイプで前後走者の曲を表示
その他リスト項目曲ID:検索で曲ID一覧を表示、ユーザー:ユーザー検索やいいねリスト等で表示
曲詳細曲の情報と貰ったコメントを表示、送るコメントを編集する
曲の情報曲のタイトル、作者、ランキング順位、タグ、ユーザーの反応等を表示
貰ったコメントテキストとOGP特殊コメントの装飾
ソングビジュア曲再生位置の変更と可視化。曲情報でトロフィー変更。リスト/詳細ボタンで切り替え。シンプルのみ実装でリリース後に追加予定。
カテゴリー選択カテゴリータブ表示。スクロール可能。選択表示。
ユーザーアイコンユーザー画像、プレミアムリングを表示。タップでユーザーページへ
プレイヤー曲の再生、いいね・お気に入り等のボタン。現在の状況を反映再生リスト追加ボタン
設定パネルレイアウト設定、ソングビジュア設定、楽器フィルタ リリース後に実装予定
Community
Square
コミュニティ広場
UI配置
ディスプレイ状況によりカテゴリー説明/ソングビジュアを切り替え。
カテゴリー説明広場カテゴリーの説明
コントローラーカテゴリーリスト群/曲詳細を切り替え
カテゴリーリスト群Squareのカテゴリーリストを切り替えるように派生
リスト項目カテゴリー別にリスト項目を派生(ランキングなら左にランク情報)。コンテスト項目はタップでコンテスト画面へ
イベント詳細コンテストの詳細情報の表示
絞り込み検索
Community
UserPage
ユーザーページ
UI配置
ディスプレイユーザープロフィールを表示。下へスワイプした時に隠れてヘッダーが表示されるように
ユーザープロフィールユーザー情報、紹介文、アクティビティログ等表示
ユーザー情報名前、アイコン、リンクリスト、フォロー欄、紹介文表示
リンクリスト外部リンク(X等)ボタンを並べる
フォロー欄フォロー、ミュート、通知ボタン
アクティビティログ活動レベル、投稿曲数やいいね数など表示
ヘッダー
コントローラーディスプレイに追従
カテゴリーリスト群UserPageのカテゴリーリストを切り替えるように派生
リスト項目開閉するプレイリスト項目を作成。
Community
Contest
コンテスト結果
UI配置
ディスプレイ状況によりコンテスト概要/ソングビジュアを切り替え。
コンテスト概要コンテストのテーマ、内容、提案者の表示
コントローラーカテゴリーリスト群/曲詳細を切り替え
カテゴリーリスト群Contestのカテゴリーリストを切り替えるように派生
リスト項目コンテストの順位や自分の投票数を表示するリスト項目に派生
Community
ダイアログ
リストダイアログいいね・お気に入りをしたユーザーリスト表示、曲を含む再生リストの表示
メッセージアラート通知するテキストを知らせる(DLした時や削除確認など)
プロフィール編集名前、アイコン、紹介文等を編集
プレイリスト詳細プレイリストのタイトル、説明、作者、コメント等を表示
プレイリスト編集タイトル、アイコン、曲リスト等を編集
コンテスト投票開催コンテスト曲の視聴と投票
MIDI詳細曲のテンポ、音符・トラック数、使用楽器等
Commnity
Common
コミュニティ
データ構造カテゴリ等の曲情報、いいねやお気に入り等のリスポンスを保持
CommunitySongPlayerコミュニティ用にラップした曲プレイヤー
CategoryListsカテゴリーリスト群のモデル。カテゴリー別にフェッチ/キャッシュ
ListInfoカテゴリーリストのモデル、リストのスクロール位置、フェッチするページ番号等
ContextCommunity共通のCommonContextと各画面のContextがある
UserActivityManagerユーザーのアクティビティ(いいね、ミュートユーザー、再生リスト、モチーフ登録、アクセス履歴等)を管理
Service
サービスモデル
ListItemFetcherカテゴリーリスト項目のMLサーバーから取得する
MidiRepositoryMIDIファイルをサーバーから取得して貯める
UserActivityFetcherユーザーの行動をMLサーバーから取得する(再生数、再生リストに含まれているか、コメント等)
Account
Common
アカウント
データ構造ログインできる構造、アカウント情報、ログイン情報、MLユーザー情報
AccountManagerアカウントの管理、ログイン時にMLサーバーと通信
Service
サービスモデル
UserActivityRepositoryユーザーのアクティビティ(いいね、ミュートユーザー、再生リスト、モチーフ登録、アクセス履歴等)を貯める
ServerCommunicationMLサーバーと通信する処理を集約


全進捗マップを表示

カテゴリタイトル補足
View
Composition
UI配置
ガイド表示
ピアノ
スクロールエリア
小節番号
小節線
分割線拡大率によって間隔を変化
フレーズフレーズがないところはフレーズ作成ボタンを表示
ツールボタン 選択中のツールはツール色にハイライトする
メロディーライン ペンツールでの音符作成時の入力線
メロディー音符 音符の先頭にチョボをつける
リズム音符 ベース音符のみ下に表示
サンプルデータ 手入力したサンプルデータの音符を配置
連符連符は数字で表示、拡大率によって省略
ツールガイド(ペン)長さ編集しているリズム音符、伸ばした時の削る範囲音符移動時、移動先の音階をわかりやすくする
ツールガイド(指)移動中の音符影、矩形選択の枠
ツールガイド(消しゴム)削除範囲、和音のみの削除範囲
ツールガイド(フレーズ)フレーズ移動・伸縮のバー、選択範囲テキスト(iOS独自)
フレーズボタンフレーズボタンとサブボタンを配置、ツールに応じてアイコンを変更、画面拡大率に応じて縮小
フレーズタブツールに応じてアイコンを変更、拡大率に応じて縮小、スクロール状態に応じて移動
音符描画の高速化音符が多くても描画できる速さへ最適化
音符の編集状態選択や変更した時に枠線の色変更
音符音階メロディ音符に音階表示
再生バー曲を再生している時に、再生位置をバーで表示
再生ボタン曲を再生/停止を監視して、状態を変更、再生準備が遅い時はインジケーターを表示
再生速度の表示曲の再生速度を表示(iOS独自)
テスト音のガイド鳴っている音階に色をつける
Composition
ダイアログ
フレーズフレーズの作成・設定・挿入、フレーズの長さやリピート回数の設定
Community
(共通)
UI配置
コミュニティディスプレイとコントローラーを表示。縦持ちと横持ちのレイアウト。どのディスプレイ、コントローラーを使用するかは各コミュニティ画面で派生
カテゴリーリスト群カテゴリー選択、カテゴリーリストを表示。どのカテゴリーリストを表示するかは各コミュニティ画面で派生
ページスクロールリストを表示。スワイプでリスト項目を取得。どのリスト項目を使用するかは各カテゴリーで派生
曲リスト項目各コミュニティ画面で派生系を用意する
リレー曲リスト項目左右にスワイプで前後走者の曲を表示
その他リスト項目曲ID:検索で曲ID一覧を表示、ユーザー:ユーザー検索やいいねリスト等で表示
曲詳細曲の情報と貰ったコメントを表示、送るコメントを編集する
曲の情報曲のタイトル、作者、ランキング順位、タグ、ユーザーの反応等を表示
貰ったコメントテキストとOGP特殊コメントの装飾
ソングビジュア曲再生位置の変更と可視化。曲情報でトロフィー変更。リスト/詳細ボタンで切り替え。シンプルのみ実装でリリース後に追加予定。
カテゴリー選択カテゴリータブ表示。スクロール可能。選択表示。
ユーザーアイコンユーザー画像、プレミアムリングを表示。タップでユーザーページへ
プレイヤー曲の再生、いいね・お気に入り等のボタン。現在の状況を反映再生リスト追加ボタン
設定パネルレイアウト設定、ソングビジュア設定、楽器フィルタ リリース後に実装予定
Community
Square
コミュニティ広場
UI配置
ディスプレイ状況によりカテゴリー説明/ソングビジュアを切り替え。
カテゴリー説明広場カテゴリーの説明
コントローラーカテゴリーリスト群/曲詳細を切り替え
カテゴリーリスト群Squareのカテゴリーリストを切り替えるように派生
リスト項目カテゴリー別にリスト項目を派生(ランキングなら左にランク情報)。コンテスト項目はタップでコンテスト画面へ
イベント詳細コンテストの詳細情報の表示
絞り込み検索
Community
UserPage
ユーザーページ
UI配置
ディスプレイユーザープロフィールを表示。下へスワイプした時に隠れてヘッダーが表示されるように
ユーザープロフィールユーザー情報、紹介文、アクティビティログ等表示
ユーザー情報名前、アイコン、リンクリスト、フォロー欄、紹介文表示
リンクリスト外部リンク(X等)ボタンを並べる
フォロー欄フォロー、ミュート、通知ボタン
アクティビティログ活動レベル、投稿曲数やいいね数など表示
ヘッダー
コントローラーディスプレイに追従
カテゴリーリスト群UserPageのカテゴリーリストを切り替えるように派生
リスト項目開閉するプレイリスト項目を作成。
Community
Contest
コンテスト結果
UI配置
ディスプレイ状況によりコンテスト概要/ソングビジュアを切り替え。
コンテスト概要コンテストのテーマ、内容、提案者の表示
コントローラーカテゴリーリスト群/曲詳細を切り替え
カテゴリーリスト群Contestのカテゴリーリストを切り替えるように派生
リスト項目コンテストの順位や自分の投票数を表示するリスト項目に派生
Community
ダイアログ
リストダイアログいいね・お気に入りをしたユーザーリスト表示、曲を含む再生リストの表示
メッセージアラート通知するテキストを知らせる(DLした時や削除確認など)
プロフィール編集名前、アイコン、紹介文等を編集
プレイリスト詳細プレイリストのタイトル、説明、作者、コメント等を表示
プレイリスト編集タイトル、アイコン、曲リスト等を編集
コンテスト投票開催コンテスト曲の視聴と投票
MIDI詳細曲のテンポ、音符・トラック数、使用楽器等
Composition
Common
作曲共通
データ構造座標とサイズ、状態を保持する。レンダラーやコライダー、通知等のロジック
コンバーターDomainのデータ構造へ変換・逆変換
通知機構Modelに変更があった時に、Viewへ通知して再描画。変更状況を監視してキャッシュ
FingerTool
指ツール
音符の編集
データ構造フレーズの音符を取得、基点と移動ベクトルを保持して移動する
音符の移動和音や連符は上下のみに制御
音符の影移動中に操作できているかわかりやすいように(iOS独自)
内外判定音符の移動をフレーズ内に留める
衝突判定移動する音符が他の音符に重なったときの挙動
タップ選択タップした音符の子音符も選択・解除
矩形選択囲った音符を選択
音符の入れ替えリズム音符のスライドで重なった音符と入れ替える(iOS独自)
和音の削除和音を移動した時に重なる時に削除する
連符に切り替えリズム音符タップで切り替え
PenTool
ペンツール
音符の作成
データ構造音符を作成・分割・統合、フレーズへ音符を追加する
音符の作成タップで音符を作成。分割線に合わせて長さを決定
音符列の作成スワイプに沿って複数の音符を作成。音階変わる時に音符分割
有無判定タップやスワイプした縦ラインに既に音符があるか判定
音符の移動音符が既にある場合は、作成ではなく移動。一定距離進むと移動終了
音符の分割リズム音符をタップした時、音符を分割、メロディ線に沿ってY位置を動かす
音符の統合2つのリズム音符の間をタップした場合、音符を統合
音符の伸縮リズム音符を左右にスワイプすることで音符の長さを伸縮、始点で分割なし(仕様変更)
音符の消滅音符の伸縮をした時に長さが0になると削除する(iOS独自)
領域差演算音符伸縮で他の音符に重なる時は差演算して他の音符長さを削る
サンプリング補間素早くスワイプしても音符が移動できるようにサンプリング間を補間する
細かい音符分割線内の細かな音符を移動する挙動
EraserTool
消しゴムツール
音符の削除
データ構造和音と連符の認識、フレーズから音符を削除する
音符の削除タップで音符を削除
和音・連符の削除和音・連符をタップで和音・連符のみを削除(iOS独自)
音符種別判定タップした音符が和音・連符・ルート音符なのか判定する
音符列の削除スワイプで指定する削除範囲内の複数の音符を削除。
和音列の削除リズム音符をスワイプで複数の和音のみを削除。(iOS独自)
休符に切り替えリズム音符タップで休符に切り替える
PhraseTool
フレーズツール
フレーズの編集
データ構造トラックのフレーズを取得・追加、削除、状態
フレーズの作成・挿入ダイアログで長さとリピートを設定 リピートフレーズは未実装
フレーズの選択2点タップで範囲選択、範囲ガイドタップで選択解除(仕様変更)
フレーズの移動左右スワイプで移動、移動は選択フレーズとスワイプ中のフレーズを含む
フレーズの伸縮サブ編集領域をスワイプした時にフレーズ長さを伸縮、長さ0で削除(iOS独自)
フレーズの貼り付け選択フレーズをコピー・ペースト、サブボタンかフレーズタブタップで挿入、選択解除
周囲有無判定作成する小節の近くにフレーズがあるかの判定、設定できる長さやリピート回数の制御
フレーズボタン・タブツールに応じてフレーズボタン、タブの処理を変更
フレーズの結合連続する2フレーズの接する小節線をタップで結合(iOS独自)
フレーズの分割フレーズをタップで分割(iOS独自)
StampTool
スタンプツール
モチーフの編集
Transform
画面移動
座標変換
画面を上下移動ピアノのスワイプにより
画面を左右移動 スクロールエリアのスワイプにより
画面を拡大・縮小ピンチアウト・インにより基点を画面中心に設定する
画面を拡大・縮小(軸指定)長押しからのドラッグ。ピアノでX軸方向、スクロールエリアでY軸方向
MIDI コンバーターCompositionからMIDIのデータ構造へ変換
曲の再生画面左からMIDI再生、Compositionのデータ構造から曲の再生、再生位置の同期
曲の再生(最初から)再生ボタン長押しで最初から再生 最初から再生されるが、画面は最初に移動しない
曲の再生(位置指定)スクロール領域をダブルタップでその位置から再生(iOS独自)
再生速度の変更ドラッグで曲の再生速度を変更(iOS独自)
再生処理の最適化曲に変更がない時はキャッシュを使う、変更通知とキャッシュの管理
Commnity
Common
コミュニティ
データ構造カテゴリ等の曲情報、いいねやお気に入り等のリスポンスを保持
CommunitySongPlayerコミュニティ用にラップした曲プレイヤー
CategoryListsカテゴリーリスト群のモデル。カテゴリー別にフェッチ/キャッシュ
ListInfoカテゴリーリストのモデル、リストのスクロール位置、フェッチするページ番号等
ContextCommunity共通のCommonContextと各画面のContextがある
UserActivityManagerユーザーのアクティビティ(いいね、ミュートユーザー、再生リスト、モチーフ登録、アクセス履歴等)を管理
Service
サービスモデル
ListItemFetcherカテゴリーリスト項目のMLサーバーから取得する
MidiRepositoryMIDIファイルをサーバーから取得して貯める
UserActivityFetcherユーザーの行動をMLサーバーから取得する(再生数、再生リストに含まれているか、コメント等)
MIDI
Common
MIDI共通
データ構造MIDIフォーマットへ出力できる構造
コントローラー曲の読み込みや再生、再生位置の監視や音源の変更などMIDIの扱いを管理する
サンプラーピアノや音符生成時に単体のMidiイベントから音を鳴らす
Service
サービスモデル
MidiPlayerMIDIを再生する
MidiReaderMIDIファイルの読み込み
MidiWriterMIDIファイル出力
Account
Common
アカウント
データ構造ログインできる構造、アカウント情報、ログイン情報、MLユーザー情報
AccountManagerアカウントの管理、ログイン時にMLサーバーと通信
Service
サービスモデル
UserActivityRepositoryユーザーのアクティビティ(いいね、ミュートユーザー、再生リスト、モチーフ登録、アクセス履歴等)を貯める
ServerCommunicationMLサーバーと通信する処理を集約
Domain
データ構造
Json形式
Melody MelodyTrack, MelodyPhrase, NoteContainer, NoteBlock, Note
Drum DrumTrack, DrumPhrase, BeatContainer, Beat
通化 Original, Repeat, Syncの3種のPhraseをジェネリッククラスとプロトコルで抽象化
Service
サービスモデル
SongRederJsonファイルを読み込み、Domainのデータへ変換
SongWriterDomainのデータからJsonファイルへ書き出し
Common
Service
サービスモデル
リポジトリ保存データを管理

ざっくり言うとコミュニティ広場(コンテストとユーザーページ関連の部分以外)は大体の実装を完了しました。
細かい部分は色々とありますが。。あとソングビジュアや最近のAndroid追加機能等の実装はリリースしてから少しずつ機能拡充していこうと思います...


実装の詳細

コミュニティView

コミュニティViewの関係図です。

コミュニティViewの関係図

コミュニティを開いた時、エントリーはCommunityRootViewでどの画面CommunitySquareView CommunityUserPageView CommunityContestViewに遷移するかをナビゲートします。各ViewはCommunityViewをベースに派生させており、DisplayView ControllerViewがView構成要素にあります。

例えば、SquareDisplayViewはディスプレイをSquare用に派生させており、コミュニティ広場のカテゴリー説明SquareCategoryDescriptionViewを表示します。曲が選択されている時はSongVisuaViewを表示します。
SquareControllerView はディスプレイをSquare用に派生させており、選択カテゴリーSquareCategoryに応じてリストCategoryListが変わります。新着カテゴリーだと曲カテゴリーリストSongCategoryListに更新され、新着曲項目NewSongCategoryListItemが並びます。

カテゴリーリストCategoryListやカテゴリーリスト項目CategoryListItemは似たようなView構成になるので、全てを1からView構成していくのではなく、同じような部分は共通化して共通Viewを参照するようにしています。

他にも共通のViewはCommonで管理しますが、大きく分けてViewFrameViewPartsがあります。
ViewFrameは外枠をレイアウトするためのViewで、中身のViewを@ViewBuilderで渡して処理を移譲します。例えば、CategoryListsViewはヘッダーにカテゴリーセレクタCategorySelectorScrollViewがあり、選択カテゴリーに応じてリストCategoryListが表示されます。どのCategoryListを表示するかは派生したViewから処理を移譲されます。また、「横スワイプでカテゴリー変更」や「選択カテゴリータブをタップでリストを一番上まで移動」等どのCategoryListsViewでも使われる共通処理をまとめています。
ViewPartsは詳細/リストボタンやユーザーアイコン、プレイヤーなど各画面固有のViewではなく、共通で使われるViewを集約しています。


なぜ共通化をするのか? 理由はコードを改変しやすいようにするためです。
不具合修正や機能追加するとき、一箇所変更すれば良いのが理想です。同じようなコードが転々とあると、複数の箇所を変えなければならない事態になります。
「この箇所を修正する時はこの箇所も変えなければならない」そんなコードが増えると管理も大変です。そんなコードの関係性を覚えておかないと新たな不具合に繋がることもあります。
そのため、できる限り共通化してコードの再利用性を高めます。


CommunityRootView
ナビゲーション、キーボード表示、通知プレイヤー

ナビゲーションについてはNavigationStackSquare UserPage Contestのいずれかの画面遷移します。
画面遷移はCommonContextで管理して環境変数に設定するため、どのViewからでもアクセス可能です。

キーボード表示について、コメント編集時に下から迫り上がりますが、デフォルトだとレイアウトが崩れてしまいます。そのため、デフォルト動作は.ignoresSafeArea(.keyboard)でOFFにして、.onChange(of: configEnvironment.keyboardHeight)でキーボードの高さを取得して手動でオフセット.offset(y: screenOffset)しています。

public class ConfigEnvironment: ObservableObject {
    
    @Published public var keyboardHeight: CGFloat = 0
    
    private let keyboardWillShow = NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)
        .compactMap { $0.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect }
        .map { $0.height }

    private let keyboardWillHide = NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)
        .map { _ in 0.cgf }
    
    public init(){
        keyboardWillShow.merge(with: keyboardWillHide).assign(to: &$keyboardHeight)
    }
}

あと、曲が選択された時.onChange(of: context.selectedSong)に通知プレイヤーを更新します。


CommunityView
ディスプレイ+コントローラー+プレイヤー、縦横のレイアウト

CommunityViewDisplayViewControllerViewPlayerViewをレイアウトします。
また、縦持ちと横持ちを検出して、レイアウトを変更します。

縦持ち
横持ち

DisplayViewControllerViewを各画面で派生させることで、共通ViewCommunityViewへまとめることができます。

Square派生
Contest派生
UserPage派生

プレイヤーPlayerViewは選択曲に応じて、いいねやお気に入りの数を反映する必要があります。ただし、曲の選択はControllerViewの末端で行うため、状態を共有するために環境変数CommonContextを介します。

PlayerView


DisplayView
説明ビュー / ソングビジュア、リスト詳細切り替えボタン

DisplayViewは曲選択により、説明ビューとソングビジュアが切り替わります。
また、曲選択時はリスト詳細切り替えボタンListDetailToggleButtonが表示され、ControllerViewを曲詳細SongDetailViewに切り替えることができます。

DisplayView
ListDetailToggleButton


説明ビューは各画面で派生します。

Square カテゴリーの説明
UserPage ユーザーの紹介文
Contest コンテストの説明

Squareではカテゴリーの説明

ソングビジュアは曲の再生に応じて再生バーを同期させます。
また、曲の情報から新着やランキング等のバッチを表示します。

SongVisuaView
バッチ


ContorollerView
カテゴリーリスト / 曲詳細、カテゴリー選択

ContorollerViewはリスト詳細切り替えボタンListDetailToggleButtonにより、CategoryListsViewSongDetailViewを切り替えるようになってます。

CategoryListsView
SongDetailView
CategoryListsView

CategoryListsViewはカテゴリー選択CategorySelectorScrollViewの下にカテゴリーリストCategoryListがある構成になっています。

CategorySelectorScrollView
CategoryList

どのカテゴリーを使うか、カテゴリーリストに何を表示するかを各画面で派生します。(SquareCategoryListsViewなど)


ジェネリックView
CategorySelectorScrollViewは3画面のカテゴリーに対応できるように型引数があります。
コンストラクタで渡した選択カテゴリーの型を識別してSquareCategory UserPageCategory ContestCategoryのすべてのカテゴリーを並べています。

struct CategorySelectorScrollView<Category: CommunityCategoriable>: View {

    @Binding var selected: Category

    public var body: some View {
        ScrollView(.horizontal, showsIndicators: false) {
            HStack(spacing: 0) {
                ForEach(Array(Category.allCases), id: \.self) { category in
                    ...
                }
            }
        ...

選択カテゴリーで型を識別


2種類のコンテキスト
コンテキストはContextCommonContextがあります。CommonContextはCommunity共通のコンテキストに対して、Contextは各画面ごとのコンテキストになります。
例えば、選択カテゴリーは各画面に状態があるため、Contextにプロパティがあります。
各画面の状態とは、「コミュニティ広場でランキング閲覧中にユーザーページへ推移して再生リストを見た」としたら、選択カテゴリーは複数の状態があるからです。

選択カテゴリー
Square ランキングカテゴリー
UserPage 再生リストカテゴリー


逆に、プレイヤーの選択曲を管理するコンテキストはCommonContextです。
ユーザーページに推移する場合も、選択曲の再生を止めずに推移したいのでコミュニティ全体で1曲の選択です。ユーザーページで曲を選択して初めて、CommonContextのプレイヤー選択曲を変更します。


CategoryList

CategoryListはリスト表示で上下にスクロールできるViewです。他にも、スクロール時にリスト項目CategoryListItemをサーバーから取得する役割があります。
これらは共通の処理でCategoryPagedScrollViewにまとめています。どのリスト項目を表示するかを各カテゴリーで派生します。

ランキング派生
コンテスト派生

また、カテゴリーによってはヘッダーに特有のリスト項目があったり、特有の機能を持たせたりします。

ヘッダーに検索欄
ユーザー検索


CategoryListItem

CategoryListItemはリストに表示される項目でカテゴリー毎など様々なViewがあります。
ただ似たようなViewもあるので、できるだけ共通化して派生します。

例えば、以下の4種類の曲リスト項目SongCategoryListItemは中身は一緒なので外枠だけ変えるように作ります。





SongCategoryListItem

他にも色々なCategoryListItemがあります。


曲ID

ユーザー

コンテスト


バッチとトロフィー
ちなみに、曲リスト項目に表示しているバッチとトロフィーは少し異なります。
トロフィーの方が小さく表示する想定なのでデザインを簡略化してます。

バッチとトロフィー

バッチ
トロフィー


SongDetailView

SongDetailViewは曲情報SongInfoViewの下に曲コメントリストSongCommentsViewがある構成になっています。

SongInfoView
SongCommentsView

さらに下側にコメントを編集して送るコメントテキストフィールドSongCommentTextFieldViewがあります。

SongCommentTextFieldView


ユーザーアイコン
プレミアムユーザーだとユーザーアイコンにプレミアムリングをつけます。

プレミアムリング

また、ユーザーアイコンの画像は毎回サーバーから取得するのでは表示が遅れてしまうため、表示した画像はNukeライブラリでキャッシュしてます。

import NukeUI

struct AccountIconView: View {
    ...
    var body: some View {
        ...
        LazyImage(iconUrl: iconUrl, transaction: .init(animation: .easeIn)) { state in
            ...
        }
        .processors([.resize(width: shortSide)])
        .priority(.high)
        .pipeline(pipeline)
    }
}

なお、Nukeライブラリでキャッシュする時の注意点ですが、ImagePipelineは同じインスタンスを使わないと適切に動作しません。
なぜかメモリが溜まり続ける不具合がありましたが、描画するたびにImagePipelineインスタンス作成していることが原因でした。
.pipeline(ImagePipeline(configuration: .withDataCache))

これでは内部のコンフィグが変わるため、同じURLでも同一画像と認識せずに新たなキャッシュが溜まり続けていました。


ListDialog

曲情報SongInfoViewのユーザーアクションボタンUserActionButtonsをタップすることでリストダイアログListDialogを表示します。

UserActionButtons

ユーザーリスト
再生リストのリスト


共通ダイアログ

ダイアログもコンテキスト同様にDialogsCommonDialogsがあります。CommonDialogsはCommunity共通、Dialogsは各画面ごとに紐づくダイアログを管理しています。
例えば、リストダイアログは各画面に状態があるため、Dialogsにアクセスしてダイアログを表示します。
「曲のいいねユーザーリストを開いて、ユーザーページに推移した」としたら、ユーザーページから曲詳細画面に戻る時には、ユーザーリストを開いた状態をキープしておいてほしいですね。

逆に「ダウンロードのメッセージを表示する」ダイアログはCommonDialogsです。
メッセージはダウンロードした時に遅延して開かれますが、「広場で曲DLして、ユーザーページに推移した」としたら、複数の画面に同じメッセージを表示する必要はないです。



おわりに

正直ちょっと一般ユーザー向けの内容じゃないですね。
内部の認識合わせにも使っているので、妙に詳細な部分とかもあります。
とはいえ公開ブログなので読んで頂いているmL民は、
δ(・ω・`)ん? もしくは ぽかーん( ゚д゚) となっているかと思います!!
ただ、とりあえずリリースに向けてiOS開発頑張っています。
そのことだけでも伝われば嬉しいです🙂

この夏リリース予定でしたが、楽しみにしていたユーザーの皆様本当に申し訳ございません!!
あと1年くらいはかかりそうです🙇
iOSでも存在感のあるアプリに仕上げようと日々磨いていますので、気長に待ってもらえると幸いです😭



Webで聴く!MIDIプレイヤーの実装

今回はWebで快適にMIDIを再生する話。
WebでのMIDI再生は動作が重かったので、MP3に変換して再生しました。

プレイヤー動作



はじめに

musicLineでは、コミュニティでユーザーの投稿した曲を再生できます。
またコミュニティ曲のURLを共有して、他のユーザーに曲を勧めることができます。
しかし、musicLineのアプリを持ってないユーザーは曲を聴くことができず、Playストアに飛ぶようになっています。
もちろんPlayストアでアプリをインストールすると良いですが、そこまでしないと曲を聴けないです😅
そこまでして欲しいと願っていますが。。そもそもiOSはアプリすらまだないです😭

他の方法として共有動画を作成することもできますが、それもちょっと気軽に勧めたいって場合にはレンダリング時間が気になるところです。
それでもXで共有動画で曲を紹介してくれている mL民 に感謝😆✨

なのでもっと気軽に、アプリを超えて、曲を共有することを目指して、
WebでmusicLineコミュニティ内の曲を再生できるようにしました。



実装

WebでのMIDI再生の課題

はじめにWeb(Javascript)で動作するMIDIプレイヤーのライブラリを試してみました。
サーバーからMIDIファイルをDLして、Javascriptで再生するシンプルな実装だったのですが、

  • 再生処理が重くて音が途切れる
    特にモバイルでの動作時は止まることが多い
  • コミュニティの音と大きく異なる
    そもそもサウンドフォント(sf2)が使えない

の課題がありました。

そのため、MIDIファイルを一度音楽ファイル(WAVやMP3)に変換してから、再生する方法に変更しました。


MIDIファイルを音楽ファイルに変換

サーバーから直接MIDIファイルをDLせずに、サーバー(Ruby)で音楽ファイルに変換してDLします。
MIDIからWAVへの変換はFluidSynthを使いました。さらにWAVからMP3への変換にFFmpegを使っています。

この変換する時間はどうしても数十秒は掛かってしまうので、変換したMP3はしばらくキャッシュします。キャッシュしたMP3を使うことで、次訪れるユーザーはすぐに再生できます。
そのため、WAVファイルのままDLしても再生できますが、キャッシュサイズを小さくしたかったので、MP3に圧縮しています。

以上でWebでのMIDI再生の課題が解決できました。

こちらの方法でもWebにアクセスする最初の人はファイルを変換する時間を待たなければいけない問題はあります。
でもアプリをインストールしないと曲を聴けないよりは良いですねえ。


Herokuに外部ライブラリをインポート

より専門的な話になりますが、musicLineのサーバーにFluidSynthライブラリを取り入れるところにも課題があったので紹介します。
musicLineのサーバーはHerokuを使っています。そのため、Herokuの環境下に外部ライブラリを構築する必要があります。FFmpegはHerokuの拡張機能で簡単に取り込みができましたが、FluidSynth拡張機能のBuildPackが用意されていないため、自分でカスタムBuildPackを作る必要がありました。

ちなみに、違う方法(DockerContainerを使った方法)でも環境構築ができるので、こちらも試してみましたがこの方法は辞めました。
ローカルで仮想サーバーを試すときにはDockerContainerを使っているので、そのままHerokuの環境に適用できれば便利だと考えたのですが、

  • 他のBuildPackも使えなくなる
    Herokuが用意しているBuildPackも自分で環境を整えなければならない
  • デプロイ(環境構築)が遅い
    デプロイの際にキャッシュ等を使って最適化されているそう

ということがあり、Herokuを使う利点が失われると思い辞めました。

カスタムBuildPack

devcenter.heroku.com
このページを参考に作ります。
以下の3ファイル作る必要があるのですが、compileファイル以外は他のBuildPackと同じファイルを使って良さそうです。

  • detect​: この buildpack がアプリに適用するか判定
  • compile​: アプリで変換手順を実行するために使用
  • release​: メタデータをランタイムに戻す

compileファイルでライブラリのソースをDL・インストールする処理を記載します。
C++のソースをコンパイル・リンクして、環境変数を設定しています。
なかなか難しい部分でしたが、CMAKE等のC++ビルドツールに使い慣れていれば簡単だったかもしれません。
普段なにげに使っているapt-get等のパッケージ管理ツールはとても便利なんだと思い知らされました。

#!/bin/sh 

BUILD_DIR=$1
CACHE_DIR=$2

# midi->wavへ変換する依存ライブラリlibsndfileをインストール
LIBSND_CACHE_DIR=$CACHE_DIR/libsnd
LIBSND_DIR=$BUILD_DIR/vendor/libsnd

# $LIBSND_CACHE_DIR が存在する時キャッシュを使用
if [ ! -d "$LIBSND_CACHE_DIR" ]; then
    echo "-----> Installing libsndfile"

    LIBSND_SRC_DIR=/tmp/libsnd
    SND_URL="http://www.mega-nerd.com/libsndfile/files/libsndfile-1.0.28.tar.gz"

    mkdir -p $LIBSND_SRC_DIR
    curl -L $SND_URL | tar xz -C $LIBSND_SRC_DIR --strip-components=1

    mkdir -p $LIBSND_CACHE_DIR

    cd $LIBSND_SRC_DIR || return
    ./configure --prefix=$LIBSND_CACHE_DIR
    make
    make install
    echo "-----> libsndfile installation complete"
else
    echo "-----> libsndfile use cache"
fi

mkdir -p $LIBSND_DIR
cp -r $LIBSND_CACHE_DIR/* $LIBSND_DIR


# fluidsynthをインストール
FLUIDSYNTH_CACHE_DIR=$CACHE_DIR/fluidsynth
FLUIDSYNTH_DIR=$BUILD_DIR/vendor/fluidsynth

# $FLUIDSYNTH_CACHE_DIR  が存在する時キャッシュを使用
if [ ! -d "$FLUIDSYNTH_CACHE_DIR" ]; then
    echo "-----> Installing Fluidsynth"

    # FLUIDSYNTH_VERSION="2.3.5"
    FLUIDSYNTH_SRC_DIR=/tmp/fluidsynth
    FLUIDSYNTH_VERSION="2.1.7"
    FLUIDSYNTH_URL="https://github.com/FluidSynth/fluidsynth/archive/refs/tags/v$FLUIDSYNTH_VERSION.tar.gz"

    mkdir -p $FLUIDSYNTH_SRC_DIR
    curl -L $FLUIDSYNTH_URL | tar xz -C $FLUIDSYNTH_SRC_DIR --strip-components=1

    FLUIDSYNTH_BUILD_DIR=$FLUIDSYNTH_SRC_DIR/build
    mkdir $FLUIDSYNTH_BUILD_DIR

    mkdir -p $FLUIDSYNTH_CACHE_DIR

    cd $FLUIDSYNTH_BUILD_DIR || return
    cmake .. -Denable-libsndfile=ON  -DCMAKE_PREFIX_PATH=$LIBSND_DIR
    make
    make install DESTDIR=$FLUIDSYNTH_CACHE_DIR
    echo "-----> Fluidsynth installation complete"
else
    echo "-----> Fluidsynth use cache"
fi

mkdir -p $FLUIDSYNTH_DIR
cp -r $FLUIDSYNTH_CACHE_DIR/* $FLUIDSYNTH_DIR


# 環境変数の追加
mkdir -p $BUILD_DIR/.profile.d
echo "export PATH=\$PATH:$HOME/vendor/fluidsynth/usr/local/bin:$HOME/vendor/libsnd/bin" > $BUILD_DIR/.profile.d/fluidsynth.sh
echo "export LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:$HOME/vendor/fluidsynth/usr/local/lib:$HOME/vendor/fluidsynth/usr/local/lib64:$HOME/vendor/libsnd/lib" >> $BUILD_DIR/.profile.d/fluidsynth.sh



おわりに

今回はWebでMIDIを再生する際に、再生を最適化するためにMP3に変換して再生しました。
WebでMIDIをそのまま再生すると処理が重くモバイルだとまともに再生されないことが誤算でしたが、MP3に変換することでなんとかWebでも再生することができました。
ちなみに同じサウンドフォントを使ってますが、音響ライブラリがアプリと異なるため、音も少し変わります😅

このURLでmusicLineを持っていなければ、Webプレイヤーに移ります。
https://3musicline.com/community/176751
(musicLineを持っていれば、アプリを開きコミュニティに移ります。)

https://3musicline.com/player/176751
(musicLineを持ってるユーザーはこちらのURLでWebプレイヤーを閲覧できます。)

実装の部分は試行錯誤した内容をごちゃごちゃと書いてしまいましたが、試したことを忘れないように備忘録として残しておきます。

ちなみに、最初にアクセスしたユーザーはMP3に変換する時間を待ってもらう必要があります。 頻繁にWebプレイヤーを使うユーザーはアプリをインストールして欲しいですね♪

なので待っている時間はアプリインストールを促す画面を出すようにしています。
ちゃっかり😋

アプリインストール促す画面