株式会社はてなに入社しました
カンファレンス登壇者・スタッフにこそ知ってほしいマイクの使い方
オフラインの技術カンファレンス・イベントも徐々に復活し賑わいを見せつつある今日この頃、いかがお過ごしでしょうか。
多くの聴衆に等しく声を届けるための道具「マイク」はカンファレンスに欠かせないものとなっています。
普段はアプリケーションエンジニアとして働きつつ、休日にPAエンジニアやステージマネージャーをやっている身から、来場者が発表やコンテンツに集中できるようなマイクの扱い方を簡単にご紹介します。
叩かない
マイクを叩くと低い「ブォンブォン」という不愉快な音が発生するのはもちろん、スピーカーなどの機材が壊れる原因につながります。もちろん意図的に叩いている人はいないと思うのですが、以下のようなケースでつい叩いてしまう人を見かけます:
- 拍手をする、拍手を煽る際にマイクを持ちながら手を叩く
- マイクがONになっているか確認するために叩く
マイクを手に持っている際に拍手をする際には、手と手の代わりに前腕部を叩いて、マイクへの衝撃を軽減し風音が入らないようにするといった工夫ができます。マイクのスイッチを一瞬切ったりミュートにしたりするのも良いのですが、音響業者が準備している際には、利用者が勝手にスイッチを切る行為が推奨されないことがあるので確認しましょう*1。
マイクがONになっているか調べるには、大人しく発声するのが一番です。またカンファレンススタッフ目線では、登壇者ときちんとコミュニケーションを取り、「こちらで登壇者紹介をした後に勝手にマイクがONになります」などと伝えるのも効果的です。
声の出る方向とマイクの位置・向きを合わせる
カンファレンスでの発表時に使うマイクには、多くの場合単一指向性と呼ばれる特性のマイクが選ばれます。これは、特定の方向の音だけを捉えやすいという性質です。発表者が喋りその他の人が聞くというスタイルが多いカンファレンスで、発表者の声だけを拾い多くの聴衆に届けるのにピッタリのマイクです。
そのため、マイクの軸から口が左右にずれてしまうと、一気に音量が小さくなってしまいます。マイクのグリル(先端の丸いあみあみの部分)の方向の延長に自分の口があるかを確認しましょう。また、位置だけでなく向きも重要です。手でマイクを持つ場合には声の出る方向に合わせてマイクの向きを調整しましょう。
小さな卓上スタンドにマイクを立てている形式の場合、立ちながら話している登壇者の口の位置に対してマイクが極端に低く、結果として音を拾えていないケースがよくあります。
マイクスタンドには高さと向きが調整できる機能が備わっているので、登壇前の時間に以下の動画のように、自分の身長や姿勢に合わせて調整しましょう。
グリル部分を掴まない
マイクのグリル(先端の丸いあみあみの部分)の中には、マイクが実際に収音し電気信号に変えるための部品が入っています。
この部分を握ってしまうと、音を拾えなかったり、声がこもってしまう原因になります。グリルのすぐ下の部分を持つと良いでしょう。
ある程度の声量で喋る
マイクの向き・位置・持ち方が良くても、肝心の声が小さすぎると多くの聴衆に聞きやすく発表を届けることはできません。はっきりと大きな声で話せるようにしておきましょう。むしろ、元々声が小さい人ほど、先ほど紹介した方法でなんとかマイクに伝わる信号の大きさを稼ぐべきです。
さて、これまで紹介してきた内容のうち、
- 声の出る方向とマイクの位置・向きを合わせる
- グリル部分を掴まない
- ある程度の声量で喋る
これら3つはどれも、マイクが音をちゃんと拾って大きくクリアな音で聴衆に声を届けるための方法となります。しかし、マイクを通した声のボリュームを上げる方法が違った軸でもう1つあります。それは、スタッフがミキサーやアンプでボリュームを上げるという方法です。なぜこれではいけないのでしょうか。
マイクがとらえた信号を増幅させる度合いをどんどん高めていくと、発表者の声だけでなく今まで拾えていなかったような環境音などもマイクが拾って、増幅されてスピーカーから流れます。ここで、スピーカーから流れた音が再度マイクに拾われるとどうなるでしょうか。音がどんどん増幅されて「キーン」という大きな不快な音が発生してしまいます。ハウリングというやつですね。
適切なマイクの使い方をすることで、過度に音の信号を増幅しなくて済むようになり、結果としてハウリングを防ぐことができるのです。
せっかくのいい発表が聴衆に届かない、あるいは雑音が聞こえて集中できないのはもったいないことだと思っています。よろしければ以上の内容を意識して、より伝わりやすい発表にしてみてはいかがでしょうか。
*1:業者の責任範囲外で音が出なくなるのを防ぐためです。こういった現場では、PAエンジニアがマイクを叩くのを察知してシュッとボリュームを下げてくれることも多いですが、人間の手作業によるものですのでそこに頼りまくるのも良くないです。
登壇ふりかえり:Hatena Engineer Seminar 個人開発回 & Scalaわいわい勉強会 #2
2024年に入って2件登壇しましたので、こちらのエントリで振り返っていきます。
Hatena Engineer Seminar #28 「技術習得を支え続けた私の個人開発ヒストリー」
2024年1月30日に、「個人開発」をテーマとしたHatena Engineer Seminar #28にて登壇しました。
学生の頃からずっと続けてきた個人開発を通して、モノづくりを続けながら扱える技術を次々に増やしていった話と、最近の個人開発で自分の責務を減らすことを目的に進めているモダナイズの話をしました。さらに、企画・開発の両面にフルコミットする個人開発の経験がプロダクトエンジニアと呼ばれつつあるエンジニアの一つのあり方でいることに深く貢献している、だとか、個人開発がエンジニアリングの美学を学ぶ庭になる、というメッセージも伝えました。
話の構成として、自分のこれまでの個人開発の歴史や当時の自分・社会の状況を振り返りながら進めていき、その上で一般化した結論を最後に提示していきました。これに関して社内でも「キーノートっぽい」などという感想をいただいたのですが、まさに狙った効果でした。YAPC::Kyoto 2023の id:onishi さんのキーノートにだいぶ影響されてますね。
主題を伝えるのに年ごと辿る説明方法は明らかに冗長なんだけど、(実際に人生の多くを捧げてきたので)自伝みたいな色付けもしたくて敢えてこうしたのがちゃんと意図通りになったっぽくて安心 https://t.co/NbXG8aqZIB
— Arthur (@Arthur1__) 2024年1月30日
あと、発表の最後にMackerel DrinkUpというオフラインイベントの宣伝をしたのですが、これを見て来ましたと言ってくれた方がいて嬉しかったです。
動画はこちら:
資料はこちら:
Scalaわいわい勉強会 #2「見せ算をScalaで実装してみた」
Scalaわいわい勉強会 #2にてLTをしました。前回のScalaわいわい勉強会でもLTをさせてもらいました。
今回は、M-1 2023の決勝で物議を醸したさや香の見せ算をScalaで実装したという話をしました。
この漫才を見た瞬間から、これScalaで実装しようと思っていました。同じようにプログラミングで実装したいと思った人はいたらしく、Pythonなどで実装した記事がいくつか上がっていますね。でもなぜ僕はScalaを選んだのかというと、以下の画像をご覧ください。
あたかも四則演算に加えてmiseという演算子が本当にあるかのように見えるではありませんか。これは5則目が追加されたという事実の表現として結構大事なことだと思うんですよね。Scalaでは演算子を独自に作成できるので、それを実現する2つの言語仕様を紹介しました。
これだけですとかなり初心者向けの内容になるので、来場者に楽しんで聞いてもらえるかというのがネックではありました。しかし、Scalaわいわい勉強会は初級者から上級者まで楽しめるようにと企画されているものですので、そこは割り切ることにしました。では実際どうだったかというと、以下の記事のように初心者の方もいらしていたようで、反応を見るにビギナー向けのトークができて良かったと強く思いました。
中級者向けにはScala 3でのアップデートに触れる・型レベルプログラミングでの実装を紹介するなどして、うまくバランスが取れたかなあと思っています。ただしScalaの人はM-1を見ないらしい。
資料はこちら:
次の予定は特に決まっていないのですが、Go Conference 2024にはProposalを出す予定です。よろしくお願いします。
あんまり元気じゃないです
今更ですが2月中旬に新型コロナに罹って丸々1週間ほど寝込んでいました。高熱(39度以上が3日間)、咽頭痛、味覚・嗅覚障害あたりが主な症状でした。高熱で何も頭が働かないのが一番しんどかったです。テイクアウトで近所の美味しいラーメンを頼んだら、スープが塩水としか感じられなかったのはおもしろ体験でした。
実はこの期間にいろんな予定を入れてしまっていて、仕事のお休み以外にもいろいろご迷惑をおかけしました。そのうちの1つが従姉妹の結婚式でした。その人にとって人生で1回しかないであろうイベントに参加できなかったのはかなりショックだったのと、いろいろな予定の再調整がしんどくて、身体より精神的苦痛の方が大きかったです。SNSもしばらく見たり書いたりしないようにしていました。
そんな状況かつ、しばらく家に引きこもって誰とも交流していなかったこともあってか、家の外にいるだけで動悸や冷や汗がひどく、あんまりまともに行動できてないです。特に電車ではノイズキャンセリングイヤホンがあっても厳しくて、とにかく端っこにいないと落ち着かないです。見た目は若者なのでシートに座るのも躊躇われる故、居場所がないです。
最近は多少症状がマシになってきたかと思ってポケモンカードの店舗大会に出てみたんですが、手が震えてシャッフルに困りました。よそから見たらめちゃくちゃ挙動不審な感じだったと思います。ただ戦績はびっくりするほど良かったので不思議なものですね。
ということでフットワークの軽さだけが取り柄でしたが、しばらく外出の予定は控えめにさせてもらいます。少しずつリハビリしていければと思うのでよろしくお願いします。
と言ったところでこんな話をするのもアレですが、明日はScalaわいわい勉強会 #2(すでに満席です)のLTで物理登壇予定です。面白い話になるように絶賛仕込み中です。
arm64の場合/proc/cpuinfoでCPUのモデル名が取得できない件とその対策
arm64では/proc/cpuinfoからCPUのモデル名を取得できない
Linuxにはシステムの様子を知ることができる仮想ファイルがいくつかあります。そのうちの一つが/proc/cpuinfoで、その名の通りCPUの情報が以下のように閲覧できます。
$ cat /proc/cpuinfo processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 63 model name : Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz stepping : 2 microcode : 0x1 cpu MHz : 2294.686 cache size : 4096 KB physical id : 0 siblings : 1 core id : 0 cpu cores : 1 apicid : 0 initial apicid : 0 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon rep_good nopl cpuid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm invpcid_single pti fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs itlb_multihit mmio_stale_data bogomips : 4589.37 clflush size : 64 cache_alignment : 64 address sizes : 46 bits physical, 48 bits virtual power management: (略、以下論理コアごと同じような出力が並ぶ)
「Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz」のようなCPUの名前を見たい場合にはmodel nameの行を見れば良いわけです。しかし、このmodel nameは常にあるとは限りません。先ほどの実行例はx86_64のものでしたが、arm64での実行例を見ていきましょう。
$ cat /proc/cpuinfo processor : 0 BogoMIPS : 108.00 Features : fp asimd evtstrm crc32 cpuid CPU implementer : 0x41 CPU architecture: 8 CPU variant : 0x0 CPU part : 0xd08 CPU revision : 3 (略、以下論理コアごと同じような出力が並ぶ)
先ほどと比べて情報量がかなり少なくなっており、model nameの行もないためCPUのモデル名が取得できなくなっています。
なぜこういった仕様になっているかは、Linuxカーネルのコード(下記参照)やパッチのディスカッションを見ることでわかります。
if (compat) seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n", MIDR_REVISION(midr), COMPAT_ELF_PLATFORM);
https://github.com/torvalds/linux/arch/arm64/kernel/cpuinfo.c#L193-L195
まとめると概ね以下の通りです:
- 32bitではarmでもmodel nameが取得できたが64bitではできなくなっている(そういうカーネルのコードになっている)
- arm64ではハードウェアのAPIからmodel nameを取得する術がないため上記実装になっている
lscpuではなぜarm64でもmodel nameが取得できるのか
lscpuというコマンドがあります。Ubuntuにはデフォルトで入っていそうですが、入っていないディストリビューションの場合にはutil-linuxをaptやらyumやらpacmanやらでインストールすると使えるはずです。
こちらのコマンドでもcat /proc/cpuinfo
同様にCPUの情報を閲覧することができます。ここでは本題のModel nameにgrepで絞った結果をお見せします。
$ lscpu | grep "Model name" Model name: Intel(R) Xeon(R) CPU E5-2650 v3 @ 2.30GHz
上記はx86_64での実行結果ですが、なんとlscpuではarm64の場合でもモデル名を取得することができます。
$ lscpu | grep "Model name" Model name: Cortex-A72
これもソースコードから紐解いていきましょう。
lscpu_context_init_paths(cxt); lscpu_read_cpulists(cxt); lscpu_read_cpuinfo(cxt); cxt->arch = lscpu_read_architecture(cxt); lscpu_read_archext(cxt); lscpu_read_vulnerabilities(cxt); lscpu_read_numas(cxt); lscpu_read_topology(cxt); lscpu_decode_arm(cxt);
https://github.com/util-linux/util-linux/sys-utils/lscpu.c#L1359-L1370
lscpu_read_cpuinfoという関数がある通り、lscpuでも基本は/proc/cpuinfoファイルの内容を参照しているようです。しかし、一番下のlscpu_decode_arm関数の中身が気になりますね。
part = parse_model_id(ct); if (part <= 0) goto done; for (j = 0; parts[j].id != -1; j++) { if (parts[j].id == part) { free(ct->modelname); ct->modelname = xstrdup(parts[j].name); break; } }
https://github.com/util-linux/util-linux/sys-utils/lscpu-arm.c#L366-L376
armの場合はlscpu_decode_arm関数から呼び出される上記の処理で、あらかじめなんらかの手段で得たモデルIDをモデル名に変換しているようです。以下のように変換テーブルを自前で管理していて味わい深いですね。
static const struct id_part arm_part[] = { { 0x810, "ARM810" }, { 0x920, "ARM920" }, { 0x922, "ARM922" }, { 0x926, "ARM926" }, ... { 0xd08, "Cortex-A72" }, ...
https://github.com/util-linux/util-linux/sys-utils/lscpu-arm.c#L25-L97
そして、変換元のModel IDはどこから取得しているかというと、これは/proc/cpuinfoにちゃんと含まれていました。「CPU part」というカラムが対応するそうです。冒頭に挙げたarm64の出力例では「0xd08」という値になっているので、変換テーブルを引いた結果、モデル名として「Cortex-A72」が得られるという仕組みです。
Goのプログラムで/proc/cpuinfoを解析してモデル名を取得している際にどうするか
さて、お手持ちのGo製のアプリケーションで、/proc/cpuinfoを解析してCPUのモデル名を取得しているプログラムはありませんか?私はあります。
先ほどご覧いただいたlscpuの実装をgoでも真似すればarm64の対応ができるのですが、あの大量のidとmodel nameの対応マップを自前で用意したり場合分けしたりするのは大変ですよね。ここは巨人の肩に乗っかっていきたいところです。
shirou/gopsutilという、システムの情報を取得する際に便利なgoのライブラリがあり、この中にCPU情報を取得できる関数cpu.Info()
があります。
この実装を読むと、lscpu同様にテーブルを用意し、armの場合にはモデルIDをモデル名に変換しているようです。
case "model", "CPU part": c.Model = value // if CPU is arm based, model name is found via model number. refer to: arch/arm64/kernel/cpuinfo.c if c.VendorID == "ARM" { if v, err := strconv.ParseUint(c.Model, 0, 16); err == nil { modelName, exist := armModelToModelName[v] if exist { c.ModelName = modelName } else { c.ModelName = "Undefined" } } }
https://github.com/shirou/gopsutil/cpu/cpu_linux.go#L247-L259
var armModelToModelName = map[uint64]string{ 0x810: "ARM810", 0x920: "ARM920", 0x922: "ARM922", 0x926: "ARM926", ...
https://github.com/shirou/gopsutil/cpu/cpu_linux.go#L21-L84
ついでにWindowsやFreeBSDなどの様々なOSの対応もできて嬉しいので、自前の実装をこういったメンテされているライブラリに移し替えるのを検討すると良いと思います。
Mackerelのメトリックプラグインをチェックプラグイン化するプラグイン
Mackerelのメトリックプラグインやチェックプラグインは、特定のフォーマットで標準出力に書き出すという要件さえ満たしていればどのように作ってもOKです。Go言語以外でも作れるし、なんならmackerel-agent.confにシェルスクリプトを書いても動きます。標準出力を介してやりとりするのがUNIX哲学っぽくて良いですね。
今回はこの性質を活かして、メトリックプラグインをチェックプラグイン化するチェックプラグインを作ってみたのでご紹介します。
使い方
インストールはコマンド一発です。
sudo mkr plugin install Arthur1/check-value-from-metrics-plugin
次に、mackerel-agent.confに以下のように追記していきます。
+[plugin.checks.check-value-from-mackerel-plugin-anyone] +command = "mackerel-plugin-uptime | /opt/mackerel-agent/plugins/bin/check-value-from-metrics-plugin -target uptime.seconds -gt 559000"
チェックプラグイン化したいメトリックプラグインを実行し、パイプでcheck-value-from-metrics-pluginに渡します。前回の実行結果をファイルに保持して差分値を計算しているような、副作用があるプラグインを指定する際には、-tempfile
オプションを別に設定するなどの注意が必要です。また、シェルのパイプを利用したいので、敢えて配列を使わない記法にしていることに注意してください。(参考: mackerel-agentのコマンド実行と配列指定のススメ)
-target
オプションには監視したいメトリックのキーを書きます。例えば、mackerel-plugin-uptime(uptimeをメトリック化するプラグイン)は
uptime.seconds 558926 1705885503
のような出力をするので、uptime.secondsをtargetに指定しているというわけです。そして、メトリックの比較条件を -gt 559000
のように指定します。この例であれば、uptime.secondsの値が559000よりも大きければチェック監視のアラートを発報します。
ここまで設定してmackerel-agentを再起動して待っていると、以下のようにチェック監視のアラートが発報されました。
使い道
さて、これだけであれば、Mackerel上のホストメトリック監視でもできることをなぜかチェック監視で再現しただけとなります。なぜ敢えてチェック監視で行おうとしているのでしょうか。
チェック監視が他の監視と違うポイントの1つとして、actionが設定できることが挙げられます。チェック監視スクリプトの実行後、その結果を元に任意のコマンドを実行できます。
例えばuptimeが一定以上の値になっていたら1分後にサーバを再起動したい際には以下のようにactionを指定します。
[plugin.checks.check-value-from-mackerel-plugin-anyone]
command = "mackerel-plugin-uptime | /opt/mackerel-agent/plugins/bin/check-value-from-metrics-plugin -target uptime.seconds -gt 559000"
+action = { command = "bash -c '[ \"$MACKEREL_STATUS\" = \"CRITICAL\" ]' && shutdown -r +1" }
メトリックプラグインであるmackerel-plugin-uptimeには、兄弟としてチェックプラグインのcheck-uptimeもあります。ただ一般にメトリックプラグインとチェックプラグインの対が世の中にあるとは限りませんし、自作する時も両方するのは大変ですから、メトリックプラグインをチェックプラグインに変換するプラグインは一定の需要があると思っています。