VR演奏環境作った。
ゲーミングPCを買いました。 家にちょうどOculus Rift DK2があったのでVR開発をはじめてみました。
できたもの
— あのに(たわし坂2) (@anoChick) 2017年3月26日
MIDIキーボードの入力が仮想空間内のキーボードにいって音を鳴らすやつ。
Unityで作りました。
使ったもの
モデル
GitHub - keijiro/MidiJack: MIDI input plugin for Unity
こんな感じ。良い。
感想
吐きそう
昨日今日とHMDで遊んでたので酔いがひどい。 あとDK2は解像度が低いので楽譜読めないです。
今回はあるものを使ったのでほとんどコードは書いていない。 UnityはいろいろなAssetがあるのでいいね。
今後やりたいこと
せっかくの仮想環境なのでもっと立体音響とかやりたい。 部屋の大きさをかえるとリバーブのパラメータが変わるとか、 サンプリングしたり、トラックをシュッと作ったり、 VRのDAWみたいなことしたい。
Unityでスマホのカメラを使う
僕の同僚かつフレンズのid:hiragramがなんかよくわからないカメラアプリを作ってて凄い。
僕もそういうのやりたいけどiOS開発やったこと無い。
Unityなら出来る。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class CameraController : MonoBehaviour { public WebCamTexture webCameraTexture = null; public GameObject plane; // Use this for initialization void Start () { webCameraTexture = new WebCamTexture (); plane.GetComponent<Renderer>().material.mainTexture = webCameraTexture; webCameraTexture.Play (); } // Update is called once per frame void Update () { } }
うつった。 テクスチャに投影してるだけなので↓のようにも出来る。
Unityでカメラ使うデモ pic.twitter.com/ERQCmh4GiD
— あのに(たわし坂2) (@anoChick) 2017年3月22日
だからなんだって感じではあるけど、 なんかいろいろできそう。
すてにゃんが分報チャンネル消したらしいから僕も消した。
といってもただ便乗しただけじゃなくて、
先週あたりから消そうかどうか悩んでたんですが、 すてにゃんが消したということで踏ん切りがついて僕も消したという感じです。
分報チャンネルの用途
前提として、僕の分報チャンネルの使い方はだいたい以下のような感じでした、
- 業務でのゆるめな悩みつぶやき
- 業務外の技術的なはなし
- 雑談
- にゃーん的感嘆詞
- 自分用bot[栗山さん]
栗山さんbotはYaya製です 他にもwebhook受け取ったり、色々やってくれます
やめた理由
最近Twitterで全然ツイート出来ていないのが辛くて、 なんでツイート出来ないんだろうって考えてみたら、 Twitterと分報チャンネルどっちで言おう→分報チャンネル ってケースが多くあって、結果としてツイート量が減ったんだと思いました。
あと分報チャンネル見てる人って実はそんなに居ないんですよね。 最近社内のSlack利用者がめちゃめちゃ増えてて、ノイズ感すごくなってきたので、 だいたいのチャンネルは入ってるけどミュートしているものと思ってます。(わたしはそう) join数三桁の分報で発信した気になって実は誰も観てないなんてことも普通にありえます。
発信先の分類が面倒で自分の好きにできる領域にPOSTしちゃってるんだと思うんです。
それだけです
情報発信先チャネルの最適化をもっとしていかないといけないなと思いました。
Yaya作った
こんなんつくりました。
導入
1.用意するもの
2.Herokuにデプロイ
https://github.com/anoChick/yaya
↑の[Deploy to Heroku]ボタンを押します
HerokuにログインしていればApp作成画面が出てくると思います。 環境変数をいれていきましょう
[SLACK_API_TOKEN] SLACKのAPIトークンをいれてください。 [ROOT_URL] アプリケーションのROOTURLを入れる所なんですが、まだ生成されていないので適当な文字列を入れておいて下さい。
Deployボタンを押せばデプロイされます。
デプロイが完了したらwebページが生成されるので、そのURLをROOT_URLに設定しておいて下さい。 (Settingsの[Config Variables])でできます。
slackのbotがオンライン状態になったらデプロイ成功です。
動かす
GraphQLのfieldに付くresolveをTypeによって指定する。
GraphQLでDateTimeを扱う時、フォーマットを指定する。 - あのにのに
前回の記事で 「DateTime型とかはクエリ側で出力フォーマットを引数として指定できると便利!」 って話をしました。
ついでに課題として
DateTimeTypeって作ったけど意味なくない..?
いちいちresolveにフォーマット付与を記述するの面倒じゃない?
という物があったのでこれを解決したいと思います。
やること
Typeが**ならresolveでxxをする。と言うような仕組みを作ります。
今回の場合だと 「fieldのTypeがDateTimeTypeの場合、そのfieldに引数[:format]を用意し、resolveではformatに応じで出力フォーマット通りに書こうするようにする。」 になります。
これができるようになると、DateTimeTypeが付いたfieldは全て[:format]が使えるようになります。
ちなみに使用するgemは前回に引き続き
https://github.com/rmosolgo/graphql-ruby
です。
やってく
今回はGraphQL::Define::AssignObjectFieldをモンキーパッチをあてる形で動かしてみます。 GraphQL::Define::AssignObjectField#callの程よくfieldが得られたタイミングで
if field.type.to_s == 'DateTime' field.arguments['format'] = GraphQL::Argument.define(name: 'format', type: -> { GraphQL::STRING_TYPE }) end
ついた!
次にリゾルバを作ります。
class DateTimeTypeFormatResolver def initialize(attr_name) @attr_name = attr_name end def call(obj, args, ctx) return obj[@attr_name].strftime(args[:format]) if args[:format].present? obj[@attr_name] end end
こんな感じ。あとは
if field.type.to_s == 'DateTime' field.arguments['format'] = GraphQL::Argument.define(name: 'format', type: -> { GraphQL::STRING_TYPE }) field.resolve=(DateTimeTypeFormatResolver.new(name)) end
とか書けばok
一応これで完成。
割りと便利な気がする。
今回新たにうまれた課題としては
- 他でリゾルバを記述したくなったらどうするんだ
- この書き方だとModelの属性名とTypeのfield名が一致している場合しかつかえない
次↑について考えます。
あとはその他便利拡張あればやる。
GraphQLでDateTimeを扱う時、フォーマットを指定する。
GraphQLにはScalarTypeというクラスが存在する。
ScalarTypeは配列やオブジェクト(いわゆるkey-valueペア)、enum等ではないタイプの基底クラスになる。
GraphQLではこのScalarTypeをベースとした5つの基本タイプが仕様として定義されている。
- Int - 符号付き32ビット整数
- Float - 倍精度少数
- String - UTF-8文字シーケンス
- Boolean - true or false
- ID - GUID
これだけだとDateTime等で困るので、DateTimeのGraphQLTypeを作ってみる。
date_time_type.rb
graphql-rubyを使う
https://github.com/rmosolgo/graphql-ruby
DateTimeType = GraphQL::ScalarType.define do name 'DateTimeType' description 'ActiveRecord::Type::DateTimeに対応したType' end
このままだとクエリに対する出力結果が
{ "data": { "series": { "created_at": "2017-01-09T18:55:30.000Z" } } }
になる。せっかくGraphQLなので、フォーマットもクエリとして与えられるようにしたい。
created_atフィールドをいじる
普通にcreated_atを一属性として扱うだけなら
field :title, DateTimeType
の記述だけで済むが、今回は引数formatを与えると、その通りに整形してくれるようにする。
field :created_at do type DateTimeType argument :format, types.String resolve ->(obj, args, ctx) { return obj.created_at if args[:format].nil? obj.created_at.strftime(args[:format]) } end
これでqueryを叩く
{ series(id: 3) { created_at(format:"%Y年%m月%d日 %H:%M:%S") } }
↓
{ "data": { "series": { "created_at": "2017年01月09日 18:55:30" } } }
良い。 本当はフォーマットの仕組みをTypeそのものに持たせたいのだけれど、TypeのresultがStringを取ることになるので適切では無さそう。
RailsのカスタムGeneratorを自分で作る
事前に用意したテンプレートを基にファイルを生成するようなコマンドを作る。
今回はGemにしたいのでプラグイン作成の想定でやる。
Railsプラグイン作成環境を用意
bin/rails plugin new sampleplugin
gemspecファイルのTODOになってるところを書き換えて、bundle install
をする。
プラグイン自体はlib
ディレクトリ以下に作っていき、
test/dummy
にrailsプロジェクトがあるのでそこで動作確認をしていく。
Generatorクラスを作る
lib/generators/sample_generator.rb
にgeneratorの処理を記述する
class SampleGenerator < Rails::Generators::Base def initialize(args, *options) super @_args, @_options = args, options end def main # ここに処理を書く end end
これでbin/rails generate sample
などと叩くとmainが実行される。
テンプレートの用意
例えば
<%= @type_name %> = GraphQL::ObjectType.define do name '<%= @model_name %>' end
lib/generators/templates/types.rb
にこんな感じでファイルを作っておく。
テンプレートを使う
class SampleGenerator < Rails::Generators::Base source_root File.expand_path('../templates', __FILE__) def initialize(args, *options) super @type_name ='sample_type' @model_name = 'Sample' end def main template "types.rb", "app/graphql/types/#{@type_name}.rb" end end
できた。