カウンタ
今日:00000005
全体:00034120

 JoyKeyMapper v1.2.0 をリリースした / magicien 

リリースしたのが1週間くらい前だったように思うのですが、こちらに書くのを完全に忘れていました。
Switch用ファミコン、スーパーファミコンコントローラに対応しました。
JoyKeyMapper

Switch用コントローラは他にNESやゲームキューブコントローラがあるのですが、こちらはまたの機会に。モンスターボールPlusはそもそもMacへの接続の仕方がよく分からなかった。もしかしたら先にリングコンに対応するかもしれない。
Joy-Conは他にも色々とセンサーが入っていて、まだまだ遊び足りないです。

2020/08/20(Thu) 02:13:58

 SwitchのコントローラでMIDIを再生するツールを作った / magicien 

JoyConSwiftの開発を進める中で、コントローラ振動機能をテストする必要があったので、ついでにMIDIを読み込む機能も追加してツール化しました。
ダウンロード:JoyfulPlayerのReleasesからJoyfulPlayer-vX.X.X.dmgのような名前をダウンロードしてください。

Proコンで UNDERTALE の Megalovania を再生した動画↓


技術的な解説

動画にも書いた通り、コントローラの振動は、リニア振動モーターなるものが使われており、Joy-Conには1つ、Proコンには2つ、このモーターが入っています。

学研さんと「HD振動」のヒミツについて調べてみました。 | トピックス | Nintendo

このモーターは、上下方向と左右方向でそれぞれ別の周波数で振動させることができるため、一つのモーターで同時に2つの音を発生させることができます。例えば、上下方向に 262Hz、左右方向に 440Hz で振動させると、ドとラの和音が鳴るわけです。Proコンには、モーターが2つ入っているので、最大で4和音まで再生できることになります。
実は2軸で指定できる周波数の範囲に差があり、1つは 40.88〜626.29Hz、もう1つは 81.75〜1252.57Hz が指定できるようです。音階にすると、E1〜D#5、E2〜D#6くらい。

Rumble data table

音楽の世界では、一般的に1オクターブを12分割していますが、このモーターで指定できる周波数は1オクターブにつき16段階なので、正確な音階は表現できません。今回作ったツールでは、一番近い周波数を選ぶことでそれっぽい音を鳴らすようにしています。絶対音感がある人には、とても気持ち悪いかもしれませんが、正直なところ自分には音がずれているのかどうか、よくわかりませんでした。(そもそもコントローラは楽器ではない)
課題として、特定の周波数の範囲でコントローラ全体が共鳴してしまい、うるさい、という問題があります。おそらくコントローラによって共鳴する周波数が違うので、真面目に音量調整しようとするとかなり苦労しそうです。上の動画では音声編集ツールを使ってある程度音量差を抑えていますが、それでも特定の音がかなりうるさく感じるでしょう。

MIDIファイルの解析には、MidiParserを使わせていただきました。このシンプルかつ強力なライブラリのおかげで、MIDIファイルの解析で特に困ったことはありませんでした。

自分の中で新たなチャレンジとして取り組んだのは、SwiftUIによるインタフェースの作成でした。VueやReactを使ったことがある人は割ととっつきやすいと思います。JavaScriptより型が厳密である分、SwiftUIの方が安心感があります。まだ発展途上の段階で、APIの追加・変更が多いので、もう少し落ち着くまで待つのも手だと思います。

2020/08/19(Wed) 02:16:39

 JoyKeyMapper v1.0.1 をリリースした / magicien 

JoyKeyMapperをアップデートしました。

修正内容は、
・一部のアプリで補助キーが効かない問題を修正
・App Storeの日本語対応
です。

キーの押下イベントを送信する時に、どの補助キーが押されているかのフラグを一緒に引数として渡しているのですが、Blender等の一部アプリでは、そのフラグを見ていないようで、補助キーの押下イベントを別途先に送っておく必要があるようです。例えば、Command+Zで取り消しするキー割り当てをしていた場合、

修正前:Zキー押下イベント+Commandキーフラグ
修正後:Commandキー押下イベント、Zキー押下イベント+Commandキーフラグ

のようになります。ボタンを離した時の処理も同様。
実際に使ってもらうと、色々と改善点が見つかりますね。今後も少しずつ改善していきたいです。

2020/06/17(Wed) 19:31:02

 Mac の Unreal Engine 4.25.1 でMMDモデル・モーションを一発で読み込む / magicien 

MMDモデル・モーションを読み込むUE4用プラグイン「IM4U」をMacに対応させた。
プラグインのダウンロードはここから。詳細は続きに。

(モデル:ロボ子さん(© 2019 cover corp.)、モーション:あざとかわいいターン

オリジナルのIM4Uは既に開発停止してしまっているが、UE4.24向けにアップデートした方がいたので(tekifuta/IM4U)、これをMac UE4.25.1でビルドできるように修正した。(Mac UE 4.24 以前では動かないと思う)

インストール方法

今のところバイナリは配布していないので、プロジェクト毎にインストールする必要がある。

1. UE4.25.1のプロジェクトを作成する。
2. 作成したプロジェクトのパスに Plugins ディレクトリを作成する。(自分の環境だと、/Users/ユーザ名/Documents/Unreal Projects/プロジェクト名/Plugins)
3. Plugins ディレクトリの下に IM4U のGithubリポジトリを丸ごとダウンロードする。
("git clone https://github.com/magicien/IM4U.git" コマンドか、Githubのページの "Clone or download" > "Download ZIP" でダウンロードしたZIPを展開する)
4. UEのプロジェクトを開き直すと、IM4Uをビルドするか聞かれるので、ビルドする。
5. あとは他のモデル・モーションファイルと同様にpmd/pmx/vmdファイルが読み込める。


以下はまだ対応できていないもの。後で対応するかもしれない。
・ルートボーンが無い(複数ある)PMDモデル対応
・モーション読み込み時にIKを適用する(UEにもIKの機能があるが、モーション自体にIK計算後のボーン位置を焼き込んだ方が良いだろう)
・物理演算対応(剛体だけだっけ?)
・英語対応(UI、コード中のコメント)
・リファクタリング

英語対応だけしておけば、残りは誰かが勝手にやってくれるかもしれない。

2020/06/15(Mon) 00:25:57

 Epic Online Services のAccount IDからProduct User IDを取得する / magicien 

Epic Online Services のSDKでフレンドのプレゼンスを取得・監視する」の続き。

EOSでP2P通信するために、自分と相手のProduct User IDを指定する必要がある。ログイン・フレンド検索で使うIDは、Epic Account IDなので、Epic Account IDに紐づくProduct User IDを別途取得しないといけない。

よくよく調べると、このアカウント周りの処理は、やれることが多い分、処理内容もかなり複雑で、まだ理解しきれていない部分が多い。ライブラリ側でもう少し複雑さを隠蔽してくれてもいいのに。

今回は、一番簡単であろう、外部アカウントIDとして Epic Games を使った場合の流れについて。


まず、Epic Account ID と、Product User ID の関係を図にすると、次のようになる、はず。

フレンドはEpic Account IDで管理されているが、P2P通信はゲームに紐づいたProduct User IDを指定する。そのため、フレンドとP2P通信をするには、Epic Account ID から Product User ID を取得しなければならない。

Epic Account ID

EpicのアカウントのIDは、Epic Gamesでユーザ登録すれば発行される。Epic Account IDは、ユーザに紐づくので、基本的に一人一つだけ割り当てられることになる。

Epic Account IDとExternal IDの関係

実は、Epic Gamesでユーザ登録しなくても、他のアカウント管理システムに紐づいて Epic Account ID の発行ができる。Apple、Nintendo、PSN、...で認証されたユーザのIDに紐付けて、Epic Account IDが発行される。外部アカウントのユーザID一つに紐づけられるEpic Account IDは一つだけ。逆に、一つの Epic Account ID を、複数の外部アカウントに紐付ける事はできる。

Organization User ID?

ドキュメントによると、Organization User IDなるものがあるらしい。が、SDK上にはそれらしいものが見当たらない。謎。
実際は、External IDからProduct User IDに紐づいているように思える。

External IDとProduct User IDの関係

Product User IDは、ゲーム毎に発行されるユーザID。External ID一つにつき、Product User IDが一つ紐づく。複数のExternal IDで一つのProduct User IDが共有できる。

※PSのIDとゲームA用のProduct User ID(Product User A1)が既に紐づいている場合は、同じゲーム内で別のProduct User ID(Product User A2)に紐づけることはできない。

ユーザ、フレンドのEpic Account IDからProduct User IDを取得する


プレイヤー(Local User)のEpic Account IDは、ログイン時に取得できる。
さらに、Account IDからアクセストークンを取得、EOS_Connect_Loginにアクセストークンと外部アカウント(今回はEpic Games)を指定することで、プレイヤーのProduct User IDが取得できる。

フレンドのEpic Account IDは、EOS_Friends_QueryFriends のフレンド検索結果から得られる。この Epic Account ID を、外部アカウントのIDとして使う。EOS_Connect_QueryExternalAccountMappings に フレンドの Epic Account ID と、ユーザの Product User ID を渡して、フレンドの Product ID を取得する。
EOS_Connect_QueryExternalAccountMappings には、複数のフレンドの外部アカウントIDを渡せるので、一回のクエリでProduct User IDをまとめて取得できる。


文章にしようとすると、かなり複雑になってしまう。本当は、プレイヤーのProduct User IDが無い場合に、EOS_Connect_CreateUser でIDを作らないといけなかったり、既存のProduct User IDに外部アカウントを関連づけるために EOS_Connect_LinkAccount を呼んだりする場合があって、より複雑になる。(公式ドキュメント参照)

今回はここまで。

2020/06/06(Sat) 17:37:38

 JoyKeyMapper がフランス語で紹介されていた / magicien 

先日公開した JoyKeyMapper がフランス語で紹介されていました。ありがとうございます!
JoyKeyMapper Mac – Manettes de Jeu en Souris et Clavier (gratuit)


Google先生に頼りながら読んだ感じだと、ちゃんと使ってレビューしてくれたみたいで嬉しいです。Switchの発売から3年以上経って、今さらツールを作っても微妙かな、と思っていたのですが、過去に作られたツールは最新のOSで動かなかったりするようで、後発には後発のメリットがあるようです。

2020/06/01(Mon) 01:17:37

 Epic Online Services のSDKでフレンドのプレゼンスを取得・監視する(Swift) / magicien 

「Epic Online Services のSDKでログインしたユーザの情報を取得する」の続き。
フレンドのプレゼンス(オンライン・オフラインの状態、「〜をプレイ中」みたいなテキスト)を取得・監視する。


大まかな流れ

1. フレンド一覧を取得するクエリを発行する。
2. 取得したフレンドID一覧を基にさらに情報取得する(今回はプレゼンスを取得するクエリを発行する)。また、プレゼンスの変更を監視する。
3. プレゼンス取得結果を確認する。
4. プレゼンスに変更があった場合にこの関数が呼ばれる。

プレゼンスの監視対象が自分だけなのか、フレンドも含まれるかが未確認。(確認後に記事を更新予定)

上記コードには処理を書いていないが、不要になった監視は、EOS_Presence_RemoveNotifyOnPresenceChanged で止める必要がある。

追記1(5/31):現状、同じOrganizationに登録されているユーザしかフレンドとして認識されないようだ。アプリの審査が通れば、他のユーザもフレンドとして認識されるのかもしれない。
追記2(6/5):ドキュメントにアプリの審査が通るまで同じOrganizationのユーザとしかやりとりできない旨が書いてあった。("Initially, you will only be able to interact with other users within your organization. After your application has passed review, it can be distributed to any users within the Epic ecosystem.")
今回はここまで。

続き:Epic Online Services のAccount IDからProduct User IDを取得する

2020/05/31(Sun) 02:43:29

 Epic Online Services のSDKでログインしたユーザの情報を取得する(Swift) / magicien 

「Epic Online Services のSDKでログインするまでの流れ」の続き。
ログインしたユーザの情報を取得する。


大まかな流れ

1. ログインする(前回の内容)
2. ログインしたユーザのIDを取得する
3. ユーザの情報を取得するためのクエリを送る
4. クエリの結果を取得する

ログインの時に EOS_Platform_GetAuthInterface(platformHandle) で EOS_Auth_XXX の関数呼び出しに必要なハンドルを取得したように、ユーザ関連の EOS_UserInfo_XXX の関数呼び出しに必要なハンドルは EOS_Platform_GetUserInfoInterface(platformHandle) で取得する。
他の関数の場合も同じように機能(Interface)毎にハンドルを取得する必要があるようだ。取得したハンドルをキャッシュして使いまわして良いかどうかは不明。
(Interface一覧は公式のドキュメント参照:Interfaces | Epic Online Services
EOS_Auth_GetLoggedInAccountsCount は、これまでにログインしたアカウントの数を返す関数のようだけれど、Macで使うケースはあまり無いかもしれない。PS4のようなコンシューマ機なら一つのマシンで二人同時ログインするような用途は考えられる。

情報取得の際に渡すオプションの "LocalUserId" は、ログイン中のユーザID(リクエスト送信者)、"TargetUserId" は、情報取得対象のユーザID。今回は、ログインしたユーザ自身の情報を取得したいので、TargetUserIdにも自分のIDを指定している。

追記:EOS_UserInfo_CopyUserInfo でコピーしたデータは、EOS_UserInfo_Release で明示的に解放する必要があるっぽい。

今回はここまで。

続き:Epic Online Services のSDKでフレンドのプレゼンスを取得・監視する


2020/05/29(Fri) 00:31:11

 Epic Online Services のSDKでログインするまでの流れ(Swift) / magicien 

Epic Online Services のSDKをSwiftから使うの続き。

C++のサンプルをそのまま書き換えれば動くけれど、GUIに関わる部分を排除してログインに必要な処理のみをSwiftに書き換えると次のようになる。

大まかな流れ

1. アプリの初期化(EOS_Initialize)
2. ログ用コールバックの設定(EOS_Logging_SetCallback)
3. プラットフォームの初期化(EOS_Platform_Create)
4. Tick用コールバックの設定(CVDisplayLinkStart -> EOS_Platform_Tick)
5. ログイン処理(EOS_Auth_Login)

EOSの内部処理は EOS_Platform_Tick をトリガとして処理が進んでいくので、定期的に(毎フレーム)EOS_Platform_Tick を呼ぶ必要があることに注意。
3. で必要なIDがどこに書いてあるかは、 「Epic Online Services のサンプルをMacでコンパイルして動かす」の「6.4. Product情報を集める」を参照。

文字列の型を変換する

APIで文字列を渡す部分はC言語用に直さないといけないので、
let productName = "Test".cString(using: .ascii)
productName?.withUnsafeBufferPointer {
    initOptions.ProductName = $0.baseAddress
}
こんな感じで String から UnsafePointer に変換して渡す。

今回はここまで。

続き:Epic Online Services のSDKでログインしたユーザの情報を取得する(Swift)

2020/05/24(Sun) 22:03:35

 Epic Online Services のSDKをSwiftから使う / magicien 

Epic Online Services のサンプルをMacでコンパイルして動かすの続き。

Epic Online Services のMac向けSDKは、dylib(動的ライブラリ)の形で配布されており、Swiftから直接使うことができない。Swiftから、このライブラリを使うための手順は次の通り。


普通のdylibなら、module.mapとXcodeのパス設定追加でSwiftから使えるようになる。

1. ライブラリ用ファイル構成

Xcodeで作ったプロジェクトの中にライブラリ用ディレクトリを作る。
プロジェクトルート/
 ┗ Frameworks/
   ┗ EOSSDK-Mac-Shipping/
     ┣ libEOSSDK-Mac-Shipping.dylib (ダウンロードしたSDKの SDK/Bin/libEOSSDK-Mac-Shipping.dylib をコピー)
     ┣ module.map (後で作る)
     ┗ Headers/ (ダウンロードしたSDKの SDK/Include をディレクトリごとコピー)
       ┣ eos_achievements.h
       ┣ ...

2. libEOSSDK-umbrella.h を作る

インポートするヘッダをまとめたファイルを一つ作る。
基本的に全てのヘッダファイルを記載するのだけれど、後述 (6.) のエラー対応のために "eos_ui_keys.h" と "eos_result.h" を除外する。

3. module.mapを作る

これは基本的にテンプレート通り。"EOSSDK" がSwiftからimportするときの名前になる。

4. libEOSSDK-Mac-Shipping.dylib をプロジェクトに登録する

libEOSSDK-Mac-Shipping.dylib をXcodeにドラッグ&ドロップする。


TARGET の Frameworks, Libraries, and Embedded Content に libEOSSDK-Mac-Shipping.dylib が登録されていることを確認(無ければドラッグで追加)し、Embed & Sign (または Embed Without Signing)に設定する。


5. パス設定追加

プロジェクトのパス設定を追加する。

・Search Paths > Library Search Paths
"$(PROJECT_DIR)/Frameworks/EOSSDK-Mac-Shipping" を追加

・Swift Compiler - Search Paths > Import Paths
"$(PROJECT_DIR)/Frameworks/EOSSDK-Mac-Shipping" を追加

6. EOSのヘッダファイルを修正

本来ならこの段階で使えるようになるが、clangのプリプロセッサの問題なのか、一部ヘッダでエラーが出るので修正する。
規約に引っかかりそうなので、修正後のファイルを載せないが、次のように修正する。

・eos_ui_types.h
eos_ui_keys.h の中身を丸ごとコピーして 101行目の 「#include "eos_ui_keys.h"」 の部分にペースト

・eos_common.h
eos_result.h の中身を丸ごとコピーして 15行目の 「#include "eos_result.h"」の部分にペースト

・eos_ui_keys.h を削除
・eos_result.h を削除

7. 使う

module.map に設定した名前でインポートする。
import EOSSDK

今回はここまで。

続き:Epic Online Services のSDKでログインするまでの流れ(Swift)

2020/05/24(Sun) 20:35:54