SVX日記

2004|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|12|
2024|01|02|03|04|05|06|07|08|09|10|11|12|
2025|01|02|03|04|

2025-04-12(Sat) 今日も桜・アンド・デッドコレクション

  宿で7時起床。買い込んだ焼きそばとおにぎりが朝食。食べたらチェックアウトし、歩いて三度淡墨桜を観に行く。ヒドい渋滞が起きているのを尻目に。いや、これは関わりたくないレベルの混雑だわ。泊まってよかった。

  やはり桜は、陽が当たってないとな。しかし、結構な風が吹いているのに、一枚たりとも散らない。100%の満開状態と言えよう。やはりイイねぇ。青空に映える。納得して撤収。

  画像の説明

  宿のクルマに戻り、別に理由はないが、まずは通行止めの157号のデッドエンドに向かう。いつ開くのかと思ったら、書いてないんでやんの。納得して戻る。

  画像の説明 画像の説明

  続いて県道255号を北上する。なんでも157号の「倉見渓谷は避けるべき、猫峠経由が望ましい」という記述を見てから、折越峠を抜けてみたくて仕方なかったのだ。んが、冬期という理由ではなく、崩落で通行止めらしい。まぁ、よくあることだ。それを知った上で、上大須ダムでも楽しもうかと向かうのだ。

  それにしても、県道255号はものすごい快走路だ。ほぼ2車線幅が確保されている。多少の酷道を期待しただけに拍子抜けだ。アッサリと折越峠への分岐に到着。まずは、直進して上大須ダムへ向かう。ちょっと落石が多くて気を使うが。

  画像の説明

  んが、上大須ダムから北の道がフェンスで塞がれている。ガチョーン。まぁ、行っても何もないところだからなぁ……と、思ったら、どうもそっちも崩落らしい。ならばよし。また来るための理由ができたってもんさ。

  画像の説明

  折越峠の入り口には橋があるが、渡った先に遮断機だ。あっちもこっちも通行止めだが、そうなるような場所を選んで向かっているのだから仕方ない。いつか通れる日を楽しみに、納得して戻る。

  行くべきところ(?)には行ったので帰路につく。帰りは県道91号を通る。途中、堤防の上に桜の並木があったので下をくぐってみる。彦坂という場所らしい。いい感じの桜吹雪だ。やはり、花見は車上に限るな。酒呑めないけど。

  15時には帰宅してしまうが、つかれて昼寝。やっぱり歳かしらん。


2025-04-11(Fri) 桜・アンド・デッドコレクション

  花粉症の症状の大小って、なにか法則があるのかしらん。今年は例年より飛散量が多い、という予測だったのに、なんでかしらんが自分はだいぶ軽症。目も鼻もちょっと痒いけど、特に何もしないで済む程度だ。

  そんなら、というわけで、前回の遠出から大して経っていないが、また遠出することにした。宿の割引に使えるポイントが余っているし。別にどこでもいいのだが、根尾の宿が空いている。ちょっと近いが、何年かぶりに、のんびりと淡墨桜でも観に行こうかしらん。

  ちょっと前、樽見から南東に抜けるのに418号を使ったのだが、酷道かと思ったら、ずっと集落が続いていて驚かされた。今回はそれを逆に使おう。

  家をのんびり出たら、22号が漫然と渋滞気味で参る。どうにか岐阜を抜け、郊外に出たところでスーパーで買物。樽見にはスーパー、コンビニの類がなく、素泊まりだと買い込んでいかないと詰むのだ。予備として保存の効くものも買いつつ、スガキヤで昼飯も済ます。

  画像の説明

  通り道なので、岐阜レトロミュージアムに寄ってみる。オペレーションウルフをプレイ。コンティニューするがクリアできず。山のぼりゲームはクリア。オートレストランコーナーは意外と充実していたが、昼のラーメンのせいで食べられず。パチンコには興味がないので、雰囲気だけ味わって1時間を待たず退出。でも、いつまでも在ってほしい場所だな。

  画像の説明

  418号から県道200号を北上する。別に用はないが、デッドエンドをコレクションするためだ。最後の方はだいぶ道が荒れてきたが、行き止まりに到達。少し散策して、納得して戻る。

  418号の脇には多数の桜が咲いていて、車上からの花見が捗る。この時期、なかなかよいドライブコースだ。ゆっくり流すが、そうこうしているうちに樽見だ。宿にチェックイン。

  画像の説明

  淡墨桜へ歩いて向かう。久々の再会であるが、既に山の日陰になっていて、冴えない感じ。そこそこ眺めたら散歩。すぐ北にある、鷲巣谷第1砂防堰堤へ。なぜかここは滝の裏に入れるのだ。まぁ、入ってみたもののたいしたことはなかったが。

  画像の説明 画像の説明

  そのまま散歩を続けたが、ちょっと強行しすぎて道の駅近くまで行ってしまった。帰って風呂、買い込んだ晩飯を食い、改めて夜にライトアップされた淡墨桜へ。これはこれでいいな。すっかり空いているし。

  画像の説明

  帰ったら、内なる宇宙を読み進めたり、スマホでF1のバーレーンのプラクティスを観たりしつつ、おやすみである。


2025-04-07(Mon) 安藤⇔歌川広重

  広重美術館に行きそこねたからか、妙に東海道五十三次の浮世絵が気になってきてしまった。なんか子供の頃に菓子のオマケに小さなカードが付いていた気がするのだが……ハイクラウンチョコだっけ? ……って、調べてみたら永谷園のお茶づけだった。そらそうかw。

  ちょうど抽選でカードのフルセットが当たるキャンペーンを実施中ということなので、カミさんにひとつ買ってきてもらったら「沼津」が出た。子供の頃は、なんじゃこら、と思っていたが、歳を取ったからか、結構しみじみと眺められてしまう。

  画像の説明

  応募マーク3枚で1口ということなので、さらにふたつ買ったら、由比が出た。大当たりやないか。うひひ。

  しかし「歌川広重」だっけ? 「安藤広重」じゃなくて? ……と、思って調べたら、以前は「安藤広重」とされていたらしいが、現在はペンネームである「歌川広重」正しいとされているらしい。いつの間にか、GNPがGDP、ECがEUになったようなもんか。

  3パックも買ったので、お茶づけだらけになってしまった。ここしばらくは、昼ご飯のお供は、粉末の赤だしみそ汁の代わりにお茶づけだな。すまんな、永谷園……と、思ったら、粉末の赤だしみそ汁も永谷園だったわ。強いな、永谷園w。


2025-04-06(Sun) 瞬間再燃F1ブーム

  始まりは学生時代の修学旅行の夜であった。ぼちぼち寝る時間というところで、同室の誰かが「F1観ようぜ!」とテレビを点けた。当時は興味がなかったので、寝たいのに迷惑だと思った。オープンホイールのクルマをカッコイイとは思わなかったし。しかし、観ているうちに引き込まれていた。もしかしたら、あれは1990年のアメリカグランプリだったかも。セナとアレジのバトルに見覚えがある。あれですっかりアレジのファンになってしまった。

  で、1991, 93, 94年と鈴鹿に行き、その後もしばらくは深夜の番組を楽しみに観ていたが、日本グランプリを富士でやったことにはシラけたのを覚えている。気づけば、地上波での放送もなくなり、ニュースのヘッドラインを読む程度の興味レベルに。2016年には、気まぐれに鈴鹿にプラクティスの1日目だけ観に行ったりもしたが、いつしかレギュレーションもチームもドライバもあやふやな認識レベルにまで落ちてしまっていた。

  んが。今シーズンの頭。日本人ドライバの角田の評価が不当に低い、というようなニュースを目にしたかと思ったら、いきなりトップチームの一角であるレッドブルに昇格が決定だと!? トップチームに日本人というのは、ようやくの悲願の達成ではないか。Red Bullは飲まないし、ORACLEも大キラいだけれども、ちょうど鈴鹿から出走とのこと。そりゃ、観戦するしかないぜ! ……と思ったら、やっぱり地上波ではやらないらしい。

  世界的なスポーツなのに、本国でテレビ中継なしって、新幹線の停車駅なのに鈍行しか止まらないみたいなのありかよ、と思いつつ、こうなりゃしゃーない。CSのフジテレビNEXTを契約するぜ!

  画像の説明

  自分は例のフジテレビ問題については擁護寄りだ。番組が始まってみると、いつものTRUTH、いつもの解説陣で実家に帰ったような気分だ。まさに、そういうのでいいんだよフジテレビって感じ。しかし、みんな白髪だらけ、シミだらけ、爺さんだらけになっとるなw。人のことも言えんけども。

  結局、金、土、日と、ほぼF1ベッタリで過ごしてしまった。まぁ、角田はやや残念だったし、決勝もやや退屈ではあったが、徐々にレギュレーションもチームもドライバも認識がクッキリとしてきて、それなりのドラマが楽しめた。なんだか、以前に比べてすべてが煮詰まりすぎていて、ものすごい接戦で息苦しいほどだったな。でも、ニュースのヘッドラインを読むだけで済ましていたら、間違いなくもったいないと思える内容ではあったよ。

  フジテレビNEXTは最低5月末までの契約になる。しばらくは観戦できるなぁ。


2025-04-05(Sat) 年貸しキャンプ場の内覧に行く

  キャンプブームも陰りつつあるらしいが、そんなことには関係なく、だいぶ前や、ちょっと前にカジったりしているオイラである。

  そんなところにカミさんが年貸しのキャンプ場があるという情報を持ち込んできた。1年間で10万弱。高いようにも思えるが、1年間専有だ。特段、他に何の費用も発生しないというのもいい。

  というわけで、内覧会というのに参加してきた。屋外なのに内覧会というのもヘンな気がするが、敷地「内」といわれれば、まぁ、そのとおりではある。

  画像の説明

  んが、想像以上にワイルド。キャンプ場というよりは、完全に山林。傾斜地。岩もゴロゴロ。各々25m四方と割当は相当に広いのだが、テントを張れる場所があるか、ないか、という感じ。これは、あまりにも上級者向けだなぁ。せせらぎ近くの区画は、心地よい音を子守唄にできそうでもあり、実に惜しいのだが。

  まぁ、契約するつもり満々で行ったわけでもないので、今回は見送り。だいぶ遠いしな。半分はドライブがてらだったのだが、実にオープンドライブに絶好の気候であった。♪もういくつ寝るとぉ〜、灼熱地獄ぅ〜♪


2025-03-22(Sat) 今日も「由比」を旅する

  昨日、旧東海道の散歩を済ませてしまったが、当初の予定では、昨日は宿でゆっくりし、本日、散歩をする予定であった。んが、良い感じの景色、良い感じの負荷でもあるので、今日も、今度は逆から通ってみることにした。「あらゆる道は双方向に通過したらクリア」というルールもあるしね。

  ついでに、由比は桜えびが名物ということで、桜えび丼が食べられるという由比漁港を目指すことにした。歩いて峠を超え、由比の駅を通り過ぎ、漁港へ。それほど厳密に時間調整したわけではないが、開店の30分ほど前に着いた。もう何人か並んでいる。それほどのものなのか。

  画像の説明

  生桜えび丼の大盛りと、かきあげと、桜えびの味噌汁のフルコースを頼む。ふむ……むむむ……これ、旨いのか? テーブルのだし醤油で食べるが、肝心の桜えびの味がわからない。後半、だし汁をかけてお茶漬け風にするが、だし汁は効いているものの、やっぱり桜えびの味がわからない。エビのカラの食感だけが虚しい。かきあげも、さして特別感はない。味噌汁はうまかったが、単なる味噌汁としてだ。

  まぁ、漁の開始の直前の時期らしく、冷凍モノだったのが原因かもしれない。それはそれとしても、そりゃ、漁港で出されていれば期待は高まるよね。ビジュアルもピンクと緑のコントラストが美しいし。でも、なんでも新鮮なものをそのまま載っければ旨くなると決まっているものでもないだろう。今回はピンとこなかったが、そのうち別のところでもう一度くらい食ってみようかな、とは思うけれども。

  広重美術館にも行きたかったが、ちょっと歩きでは距離があるのでまた今度。由比駅から電車で興津駅まで戻り、駿河健康ランドからクルマで帰路につく。

  帰りも、また静岡で渋滞。降りて迂回。蒲郡バイパスも混んでそうなので、降りようと思ったが「あらゆる道は双方向に通過したらクリア」ルールを発動して無理して通ってみる。やっぱり渋滞。ろくでもねーな。

  意外と早めに家に着いたが、結構な疲労で、テレビをつけてボケーッとABEMAのマクロスチャンネルに合わせたらマクロス7のラストだった。うーむ。歌はいいけど、話の展開は所詮は当時モノだなぁ。特に理由もなくピンチになり、特に理由もなくピンチを脱する。最後はこんなんだったっけ? と思いつつ、こんなんだったような気もする。いつも、もうちょっとなんだよなぁ。


2025-03-21(Fri) 「由比」を旅する

  前から興味があったのだが「由比」を旅してきた。

  「由比」という場所は、山と海に挟まれた極めて狭い場所で、鉄道と、主要道と、高速道が密集している変な場所である。一応、観光地っぽい場所もあるが、観光地とまでは言えず、割と地味な場所と言っていい。しかし、通過するたび、そのガーリッシュな名前や、景色に好感を抱いていて、いつかその極めて妙な地形を散歩して体感してみたかったのである。

  で、開通したばかりの蒲郡バイパスを通って向かったのだが……ひどい渋滞だ。開通したばかりだから交通が集中しているからなのか? 新しい開通区間以外の区間に渋滞が増えている。名古屋〜浜松間がまるごと使い物にならない道になってしまった感じだな。

  さらに静岡でも渋滞。これは前からあったが、こんなにガッチリ動かなかったっけ? 降りて迂回してしまった。で、なんとか興津の駿河健康ランドに到着。

  チェックインして、興津駅に向かう。途中、たいやき屋を見つけたので、たいやきをカジりながら駅へ。電車でひと区間、由比まで乗る。そこから、狭い場所に押し込んだような、まるで離島のような雰囲気を漂わせる集落を楽しみながら、旧東海道を薩埵峠へ向かう。

  画像の説明

  途中から道はグイグイと高度を上げる。何の柑橘類か、やたらと実っている木々の中を抜ける。そして、振り返ると、絶景である。

  画像の説明

  そう大した距離でもなく薩埵峠へ。一休みして、先へ進むとあっという間に下に降り、興津の集落である。これはよい散歩道だなぁ。

  朝飯と晩酌を買って、宿に戻る。風呂はまぁまぁ。メシは混雑もありややイマイチ。「内なる宇宙」を読み始めつつ、おやすみである。


2025-03-19(Wed) 「星を継ぐもの」シリーズを読み進める

  長らく水曜は歌のレッスンの日で、その直前にはカラオケ屋で練習するのがルーティーンだったのだが、行きつけがツブれたり、その代わりとなる店が満室だったりで、仕方なく近所の丸善で時間をツブすことが多くなった。先日「アグレッサーズ 戦闘妖精・雪風」のサイン本を買ったのも、その経緯で起きたことである。

  で、別に忘れていたわけではないのだが、その時に書棚に見かけて「読まねば」と思ったのが「ミネルヴァ計画」だ。

  だいぶ前。2015年末だ。なんとなく評判の高い「星を継ぐもの」を読み始めた。冒頭部分があまりにつまらないので読み飛ばす、という珍しい経験をしつつ、そこからのあまりの面白さにグイグイと引き込まれ、そしてラスト、2段オチには悶絶させられた。

  なぜかその続編の「ガニメデの優しい巨人」と「巨人たちの星」はオーディオブックで購入したのだが、ガニメデはその結末に感心させられたものの、巨人たちは結末の記憶が曖昧。そして、その時点で続編の「内なる宇宙(上)(下)」は出ているものの、最終巻の「Mission to Minerva」は未訳と知って、ちょっとテンションが下がって宙ぶらりんな状態にしてあった。

  で、最近になって、最終巻が「ミネルヴァ計画」として出版されると聞いて、そんな長らく放置されていた作品なんて微妙なデキなのでは……と思ったものの、イザ書棚に並んでいるのを見ると……その気になってくるんだよなぁ。まぁ、食い飽きたソバでも、目の前にあれば食いたくなる、みたいなもんか。

  しかし問題は「巨人たちの星」の結末の記憶が曖昧なこと……えーいッ! こうなったら全部を復習してやるぜッ! ということで、巨人三部作をオーディオブックで聴き返すことにした。最初はどれだけかかるのやらと思ったが、星を継ぐものに約1週間、ガニメデに約2週間、巨人たちに約2週間と、良いペースで聴き進めることができた。ややこしいストーリではあるが、ジョギング中でも問題なく聴けるものなんだなぁ。結局、巨人たちは結末まで聴いてなかったようだ。ジェヴレン人が出てくる直前くらいで止まっていた。そこまでがつまらないとまでは言わないが、そこからグッと面白くなって、そしてラスト、2段オチに悶絶。またやられた。

  画像の説明

  で、途中「インサイト 戦闘妖精・雪風」が入ったりもしたのだが……意外な伏兵が間に入ってきた。「人体、なんでそうなった?」だ。まさに、書店で偶然の出会った本だ。SFではなく理科学書。パラパラと中身を確認するが、絶対に面白いとしか思えない。というか「星を継ぐもの」シリーズが人類の進化を扱っていることもあり、間に読むのにピッタリすぎるのだ。まるでダンチェッカー先生の課外授業だ。結局、ポチって読んだのだが、期待以上の面白さだった。

  要するに、生物の進化の基本は変異体と淘汰なのだが、そのネガティブ面に都度ツッコミを入れるという内容で、久々に実に目からウロコな内容であった。自分的には「利己的な遺伝子」「話を聞かない男、地図が読めない女」と並んで、人生の見方を変えてくれる一冊に挙げるに十分な名著だ。

  さて! 次は満を持して「内なる宇宙」だな! (だいぶ)待ってろよ「ミネルヴァ」!


2025-03-09(Sun) ついにデビューのチャンスが!

  最近、風呂での30分の回復の間、AbemaTVを観て過ごすことが多いのだが、なんとマクロスチャンネルなんてのが新設されていた。

  自分はガンダムよりも断然マクロス派。映画の「愛・おぼえていますか」に衝撃を受けて以降、人生に少なくない割合の影響が出ている。ん? でも、期間限定チャンネルなの? ……ふーん……と、数日後にその理由に気づいた。「『新マクロス』超時空歌姫オーディション2025」だとぉ!? そのタイアップだったんかい。

 

  次の新作はサンライズと組んで、というのは知っていたが、遂に新歌姫の募集にまでこぎつけたんだなぁ。今回はオーディション用に新曲が用意されているらしい。「アイ to アイ」とな。仮歌なんてのも公開されている。仮歌、なんて仕事があるってことも、ヴォーカル修行を始めてから知ったのだが、それを聴くのは初めてだな……。

 

  ……う、うまい。曲自体も「グッ」とくるが、仮歌の方も、微妙にシャウト気味でスゴい迫力が出せてるやんか。いい声だ。この人でもいいくらい。

  最近、自分に「初めて聴いた」時に「グッ」とくるか、こないか、という評価ポイントがあることに気づいた(まぁ、何回か聴いてから好きになることもあるが)、ワルキューレの3枚目とかには、ほとんどそれがなかった。FireBomberの新譜にも、だ。単なる好みなのかもしれないが、自分の中には明らかな差がある。

  「アイ to アイ」には「ある」。「射手座☆午後九時 Don't be late」の時に似た衝撃を感じる。よく聴けばメロディも歌詞もやっつけ的にも思えなくもないが、なにしろ勢いがある。

  しかも、歴代の歌姫がデモするという企画も熱すぎる。らしさ全開の鈴木みのりも、全開で絞り出してくるMay'nも圧巻。福山芳樹は何してんだ、と思ったら、来週のお楽しみなんかいッ! いや、これは、オレも歌ってみたいッ! ……って思ったら、既にJOY SOUNDで歌えるようになってんのか。うぉぉ、歌うぜぇ。まずは、聴き込んで覚えるぜぇ。そして出撃ッ!

  20回くらい歌ったが、これは難度が高い。キーは-5だが、男性としては高目だ。最初のオクターブジャンプ、一気に低めから入って再ジャンプ、サビは高音が連続するし、畳み掛ける様に速くて休む場所も少ない。ピッチも採りにくいところが多い。んが、楽しい。実に挑み甲斐ある曲だ。

  オーディション用に公開しているのだから「うたスキ動画」にアップしてそのまま応募できるのかと思ったら、録画はできないようだ。なんでや? なので、その場で適当にiPhoneで録画してみた。オレの歌を聴けぇ!

 

  ベストテイクではないし、まだ修正できる部分はあるが、まぁ、悔しくも現状の実力を反映した結果だと認めざるを得ない。6年も修行を続けてこんなもんかと思わなくもないが、それでも声の音域や表情を鍛えてきたからこそ、パッとそれらしくは歌えるようになったのだと思える。

  エントリー資格は「日本国内在住の13歳~22歳の女性」とのこと。年齢は17歳と439ヶ月だからいいとして、女性ってのがなぁ……でも、今やLGBTQ+の時代だ。なんとかなるやもしれん……ならんか。せめて、その次の作品は「マクロス・ロック・オブ・エイジズ」にして、シニア枠のオッサンを主人公に据えていただきたいのだが……来世に期待するか……。


2025-03-07(Fri) ALSAでPulseAudioで音を鳴らす

  OSSアプリを書いたら、ALSAアプリも、PulseAudioアプリも書いてみたくなった。それを順に辿ることでサウンド機能の進化を体験できるかもしれない。

  しかし情報が少ない。Cで書くのは面倒だからRubyで書きたい。GEMにALSAのバインディングくらいあんじゃないの? えぇい、AIに聞いちゃえ。「RubyでALSAで音を鳴らすプログラムを書いてください」。そのまんまだ。

  出てきた……て、なんだこれ。GEMを使ってない。FFIてナニ? 調べたら「Foreign function interface」とある。え。Ruby上でバインディングを書けるってこと!? そういうのもあるのか! 知らんかった。

  前にもあったが、サンプルコード的なものを書かせると、AIはちゃんとしたものを出してくる。ほぼそのまま動いたが、あちこちオレ風にリライトして仕上げたのが以下。その作業を通じてコードはオレの血肉となるのだ。

#!/usr/bin/env ruby
 
# $ bundle add ffi
require 'bundler/setup'
 
require 'ffi'
include Math
 
module ALSA
    extend FFI::Library
    ffi_lib 'asound'
 
    # https://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html
    attach_function :snd_pcm_open, [:pointer, :string, :int, :int], :int
    attach_function :snd_pcm_set_params, [:pointer, :int, :int, :uint, :uint, :int, :uint], :int
    attach_function :snd_pcm_avail, [:pointer], :int
    attach_function :snd_pcm_writei, [:pointer, :pointer, :ulong], :long
    attach_function :snd_pcm_close, [:pointer], :int
 
    SND_PCM_STREAM_PLAYBACK = 0
    SND_PCM_FORMAT_S16_LE = 2
    SND_PCM_ACCESS_RW_INTERLEAVED = 3
end
 
p_pcm = FFI::MemoryPointer.new(:pointer)
name = 'default'                                # 'hw:2,0', 'plughw:2,0'
ALSA.snd_pcm_open(p_pcm, name, ALSA::SND_PCM_STREAM_PLAYBACK, 0) == 0 or raise('snd_pcm_open failed.')
pcm = p_pcm.read_pointer
 
channels = 1
rate = 44100
ALSA.snd_pcm_set_params(pcm, ALSA::SND_PCM_FORMAT_S16_LE, ALSA::SND_PCM_ACCESS_RW_INTERLEAVED, channels, rate, 1, 500000) == 0 or raise('snd_pcm_set_params failed.')
 
freq = 440
duration = 2
p_buffer = FFI::MemoryPointer.new(:int16, frames = 2048)
omega = 2.0 * PI * freq / rate
theta = 0
(duration * rate).times {|p|
    p_buffer.put_int16(p % frames * 2, (sin(theta += omega) * 32700).to_i)
    if((p + 1) % frames == 0)
        a0 = ALSA.snd_pcm_avail(pcm)
        ALSA.snd_pcm_writei(pcm, p_buffer, frames) < 0 and raise('snd_pcm_writei failed.')  # blocking
        puts('%s: %5d -> %5d' % [Time.now.strftime('%H:%M:%S.%N'), a0, ALSA.snd_pcm_avail(pcm)])
    end
}
 
ALSA.snd_pcm_close(pcm)

  引き続き、PulseAudio版。こっちも情報が少ない。Simple APIのサンプルは見つかったが、発声中にブロッキングされる仕様では、ゲームに使えない。Asynchronous APIを使うべきだが……無闇に複雑な前処理が要るんだなぁ。結局、CのサンプルをRubyのFFI向けに書き直した。

#!/usr/bin/env ruby
 
# $ bundle add ffi
require 'bundler/setup'
 
require 'ffi'
include Math
 
module PulseAudio
    extend FFI::Library
    ffi_lib 'pulse'
 
    # https://freedesktop.org/software/pulseaudio/doxygen/mainloop_8h.html
 
    # pa_mainloop *pa_mainloop_new(void);
    attach_function :pa_mainloop_new, [], :pointer
    # pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m);
    attach_function :pa_mainloop_get_api, [:pointer], :pointer
    # pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name);
    attach_function :pa_context_new, [:pointer, :string], :pointer
 
    # void (*pa_context_notify_cb_t)(pa_context *c, void *userdata);
    callback :pa_context_notify_cb, [:pointer, :pointer], :void
    # void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata);
    attach_function :pa_context_set_state_callback, [:pointer, :pa_context_notify_cb, :pointer], :void
 
    # int pa_context_connect(pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api);
    attach_function :pa_context_connect, [:pointer, :string, :int, :pointer], :int
 
    # pa_context_state_t pa_context_get_state(const pa_context *c);
    attach_function :pa_context_get_state, [:pointer], :int
 
    # pa_stream* pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map);
    attach_function :pa_stream_new, [:pointer, :string, :pointer, :pointer], :pointer
 
    # void (*pa_stream_request_cb_t)(pa_stream *p, size_t nbytes, void *userdata);
    callback :pa_stream_request_cb, [:pointer, :int, :pointer], :void
    # void pa_stream_set_write_callback(pa_stream *p, pa_stream_request_cb_t cb, void *userdata);
    attach_function :pa_stream_set_write_callback, [:pointer, :pa_stream_request_cb, :pointer], :void
 
    # int pa_stream_connect_playback(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags, const pa_cvolume *volume, pa_stream *sync_stream);
    attach_function :pa_stream_connect_playback, [:pointer, :string, :pointer, :int, :pointer, :pointer], :int
 
    # int pa_stream_write(pa_stream *p, const void *data, size_t nbytes, pa_free_cb_t free_cb, int64_t offset, pa_seek_mode_t seek);
    attach_function :pa_stream_write, [:pointer, :pointer, :int, :pointer, :int, :int], :int
 
    # int pa_mainloop_run(pa_mainloop *m, int *retval);
    attach_function :pa_mainloop_run, [:pointer, :pointer], :int
    # int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval);
    attach_function :pa_mainloop_iterate, [:pointer, :int, :pointer], :int
 
    PA_CONTEXT_NOAUTOSPAWN      = 1
 
    PA_CONTEXT_UNCONNECTED      = 0
    PA_CONTEXT_CONNECTING       = 1
    PA_CONTEXT_AUTHORIZING      = 2
    PA_CONTEXT_SETTING_NAME     = 3
    PA_CONTEXT_READY            = 4
    PA_CONTEXT_FAILED           = 5
    PA_CONTEXT_TERMINATED       = 6
 
    PA_SAMPLE_U8                = 0
    PA_SAMPLE_ALAW              = 1
    PA_SAMPLE_ULAW              = 2
    PA_SAMPLE_S16LE             = 3
    PA_SAMPLE_S16BE             = 4
 
    PA_SEEK_RELATIVE            = 0
    PA_SEEK_ABSOLUTE            = 1
    PA_SEEK_RELATIVE_ON_READ    = 2
    PA_SEEK_RELATIVE_END        = 3
end
 
class Pa_sample_spec < FFI::Struct
    layout(
        :format,    :int,
        :rate,      :uint32,
        :channels,  :uint8,
    )
end
 
class Userdata < FFI::Struct
    layout(
        :gain,      :int,
        :omega,     :double,
        :theta,     :double,
        :data,      :pointer,
    )
end
 
def pa_context_notify
    FFI::Function.new(:void, [:pointer, :pointer]) {|c, p_userdata|
        state = PulseAudio.pa_context_get_state(c)
        puts('state: %d' % state)
        case(state)
          when PulseAudio::PA_CONTEXT_UNCONNECTED
          when PulseAudio::PA_CONTEXT_CONNECTING
          when PulseAudio::PA_CONTEXT_AUTHORIZING
          when PulseAudio::PA_CONTEXT_SETTING_NAME
          when PulseAudio::PA_CONTEXT_READY
 
            ss = Pa_sample_spec.new
            ss[:format] = PulseAudio::PA_SAMPLE_S16LE
            ss[:rate] = 44100
            ss[:channels] = 1
 
            stream = PulseAudio.pa_stream_new(c, 'SineWave', ss, nil)
            puts('stream: 0x%016X' % stream)
 
            PulseAudio.pa_stream_set_write_callback(stream, pa_stream_request, p_userdata)
 
            r = PulseAudio.pa_stream_connect_playback(stream, nil, nil, 0, nil, nil)
            puts('connect_playback: %d' % r)
 
          when PulseAudio::PA_CONTEXT_FAILED
          when PulseAudio::PA_CONTEXT_TERMINATED
        end
    }
end
 
def pa_stream_request
    FFI::Function.new(:void, [:pointer, :int, :pointer]) {|p, nbytes, p_userdata|
        userdata = Userdata.new(p_userdata)
        data = userdata[:data]                                  # ループの外にある必要!?
        nbytes.times {|t|
            v = userdata[:gain] * sin(userdata[:theta] += userdata[:omega])
            data.put_int16(t * 2, v.to_i)
#           userdata[:data].put_int16(t * 2, v.to_i)            # これだとなぜか SEGV...
        }
        r = PulseAudio.pa_stream_write(p, userdata[:data], nbytes, nil, 0, PulseAudio::PA_SEEK_RELATIVE)
        puts('stream_write(%d): %d' % [nbytes, r])
    }
end
 
#-------------------------------------------------------------------------------
#
#   Main
#
mainloop = PulseAudio.pa_mainloop_new()
puts('mainloop: 0x%016X' % mainloop)
 
mainloop_api = PulseAudio.pa_mainloop_get_api(mainloop)
puts('mainloop_api: 0x%016X' % mainloop_api)
 
context = PulseAudio.pa_context_new(mainloop_api, 'SineWaveAsync')
puts('context: 0x%016X' % context)
 
userdata = Userdata.new
userdata[:gain] = 32700
userdata[:omega] = 2.0 * PI * 440 / 44100
userdata[:theta] = 0
userdata[:data] = FFI::MemoryPointer.new(:int16, 32768)
PulseAudio.pa_context_set_state_callback(context, pa_context_notify, userdata)
 
r = PulseAudio.pa_context_connect(context, nil, PulseAudio::PA_CONTEXT_NOAUTOSPAWN, nil)
puts('context connect: %d' % r)
 
#r = PulseAudio.pa_mainloop_run(mainloop, nil)
loop {
    r = PulseAudio.pa_mainloop_iterate(mainloop, 0, nil)
    print('.')
    sleep(0.01)
}

  んが、セグメンテーションフォルト連発。音は出るものの、すぐに落ちてしまう。うーむ。久々に動かない地獄を長々と這いずり回ってしまった。でも、PulseAudioで音を出す手順は習得できたし、それでよしとするか。常に同じ症状が出ないので、メモリの扱い周りに問題があるのだろうが、FFI特有のアレコレに振り回されるのは本意ではない。

  ちょっと今回は長すぎるグダグダで疲れてしまった。サウンド関係はしばらく倉庫に押し込んで別のことをやることにするよ、パトラッシュ。