壁ツェーン

オンギャーの思考回路

【ASMR】失恋duino.php SUMMER

この記事は mstdn.maud.io Advent Calendar 2019 の 2 日目の記事です。

昨日は VanBackfat(背脂) さんの 末代珍走団2019年活動報告 - ゲロ日記 でした。 FH4 買う買うつって半年たってしまいました。 FH4 の代わりに買った が……


f:id:kb10uy:20191201174258j:plain 「今日は、 *nix で日下夏稀の公式サイトを作ってみるッスよ!!」

(某ホームページ作成サービスの話は含まれていません)


1. 失恋

僕のフォロワーでこの件を覚えている方も多いのではないでしょうか。ちょうど3ヶ月たちましたが未だにショックです。そりゃそうでしょう。

FAQ

  • 誰に失恋したの?
    • 大学の同級生。
    • もみあげが長い。
    • なんとなくほっておけない感じがする(思い上がりである可能性)。
    • かわいい(当社比)。
  • NG だった理由は?
    • 既に彼氏がいた。
    • もしこれが優しいウソだったら……と思うと夜も眠れないので考えないことにしています。
  • 初恋?
    • はい。
  • 何年好きだったの?
    • 2年半。言い方を変えると入学時から。
  • 諦めた?
    • いいえ。

所感

未だにショックと言いましたが、それ以上に自分が告白してしまったという事実が未だに恥ずかしいです。思い出すたびに「あ゛ぁ~」みたいな感じで悶えてしまうほどには。 21 年も生きてきて一度も女子に面と向かって「好き」と言ったことがなかったんですよ。ほめて。

でもこのとき伝えてくれた内容がかなり、こう、心にしみました。救われたというか。

…別に絶交みたいな感じになってしまったわけではないので、なんとかしていきたいです。この感情と恋の行方を。

2. PHPFFI

PHP 7.4 でついに標準ライブラリ入りしてしまった FFI 。前々から宣言していた通り、ShortStoryServer では独自構文のパーサーを Rust に移植し、既に Playground ページでは WASM 化されたそれを利用してリアルタイムでプレビューができるようになっています。

で!これを PHP でも使いたいわけじゃないですか。今実装ダブってますからね。正しく、 PHP に標準で FFI が入ったことは渡りに舟なわけです。Rust ならば C ライブラリとしても吐けますしね。特に何も考えずに Rust に移植しましたが、これは思わぬアドバンテージでした。

……さて。パーサーということは文字列でございます。FFI と文字列。嫌な予感がしますね。Rust で実装しているとなると malloc した領域を返すということもあんまりやりたくありません。どうしたものでしょうか。

これに対して僕が考えた解決策の一つは、「PHP 側で確保した固定長バッファに順次書き込んでいき PHP 側で連結する」というものです。連結コストが高そうですがまあしょうがないでしょう。 char * を返させてくれ。

予備実験: PHP に可変長な文字列をなんかこううまいこと渡す

やっていきましょう。適当に Rust のライブラリープロジェクトを作ります。可変長文字列の受け渡しができればよいので、「ランダムな英数字の文字列を返す」ものでも作りましょうか。Laravel とか FuelPHPStr::random みたいなやつです。

Cargo.toml (抜粋)

rand crate を利用します。最近分布関連が別 crate に分離したみたいですね。まあ今回はその辺は使わないんですが、統計学的な分布が大量に用意されているので便利です。

[lib]
crate_type = ["cdylib"]

[dependencies]
libc = "0.2.66"
rand = "0.7.2"

src/lib.rs

実際に s3wf2-rs で利用することを考えて、バッファー部分とは別に出力状態を表すコンテキストオブジェクトを定義しておきます。

use libc::{c_char, c_int, size_t};
use rand::prelude::*;

static RANDOM_CHARS: &'static [u8] =
    b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

pub struct Context {
    random: ThreadRng,
    count: usize,
}

#[repr(C)]
pub struct FfiStringBuffer {
    buffer: [c_char; 8192],
    written: size_t,
    finished: c_int,
}

#[no_mangle]
pub extern "C" fn create_context(count: size_t) -> *mut Context {
    Box::into_raw(Box::new(Context {
        random: thread_rng(),
        count,
    }))
}

#[no_mangle]
pub extern "C" fn destroy_context(context: *mut Context) {
    unsafe { std::mem::drop(Box::from_raw(context)) }
}

#[no_mangle]
pub extern "C" fn read_next_string(context: *mut Context, buffer: *mut FfiStringBuffer) {
    let ctx: &mut Context;
    let buf: &mut FfiStringBuffer;
    unsafe {
        ctx = &mut *context;
        buf = &mut *buffer;
    }
    if buf.finished == 1 {
        return;
    }

    let write_size = usize::min(ctx.count, 8192);
    buf.written = write_size;
    for i in 0..write_size {
        buf.buffer[i] = RANDOM_CHARS[ctx.random.gen_range(0, RANDOM_CHARS.len())] as i8;
    }

    ctx.count -= write_size;
    if ctx.count == 0 {
        buf.finished = 1;
    }
}

sample.php

PHP の中に C 言語のような文字列が出現するの率直にキモいですね。まあそんなこと言ってられないので、 C 言語で対応するような構造体と関数の定義を書いていきます。 Rust 側での Context 構造体は opaque pointer として扱い、扱いを Rust 側に一任することで安全性を確保します。多分これであってると思うけど……。

<?php

$ffi = FFI::cdef('
    struct ffi_context;

    struct ffi_string_buffer {
        char buffer[8192];
        size_t written;
        int finished;
    };

    struct ffi_context *create_context(size_t length);
    void destroy_context(struct ffi_context *context);
    void read_next_string(struct ffi_context *context, struct ffi_string_buffer *buffer);
', __DIR__ . '/target/release/libphp_ffi_test.so');

$buffer = $ffi->new('struct ffi_string_buffer');
$context = $ffi->create_context(32000);

while ($buffer->finished !== 1) {
    $ffi->read_next_string($context, FFI::addr($buffer));
    echo "{$buffer->written} bytes written." . PHP_EOL;
    $currentString = FFI::string($buffer->buffer, $buffer->written);
    echo $currentString . PHP_EOL;
}

実行する

まあ見てのとおり 32000 bytes 要求してるので 8192 bytes のバッファからは当然溢れるわけで、複数回 read_next_string が呼ばれることが想定されます。

cargo build --release
strip target/release/libphp_ffi_test.so
php sample.php

strip したのに特に意味はありませんが、 ArchLinux 上で実験している限りではだいたい 200KB ぐらいになります。デカいんだか小さいんだか……

肝心の実行結果は……

8192 bytes written.
XbAsa9DkTptDoEsh4ZPWSlvLDR8YUciL...
8192 bytes written.
AffSLJN2hAuzvaRfxYgyqBYqpGNbRO11...
8192 bytes written.
bljvisQWlc2usVVYPDQGr1EVx7jm7OmV...
7424 bytes written.
mFiwI0gRotdnvWlHgMY68Be750ihk1Gs...

成功ですね!! これで安心して PHP 側でも s3wf2-rs を利用できます。


f:id:kb10uy:20191201180934j:plain 「kb10udemy は、世界最大級のオンライン射精プラットフォーム!」

(某オンライン学習プラットフォームの話もこの下には含まれていません)


3. 音声作品

ささやき彼女 冬子2

www.dlsite.com

  • ヒ ○○○○○●○ 主
  • 上 ○○○○○●○ 下
  • 仏 ○○○○○●○ 欲

上記失恋事件の直後に買った作品です。 セリフの間のおき方や喘ぎ感が傷付いた心をふわっと包みました。

地味でぼっちなクラスメイトに告白したらベタ惚れされて夜の電話で愛を囁かれまくる一週間

www.dlsite.com

  • ヒ ○○○○○●○ 主
  • 上 ○●○○○○○ 下
  • 仏 ●○○○○○○ 欲

上記失恋事件から1ヶ月ぐらいたったころに買った作品です。 説明文にもありますがASMRではないです。一応。

黒崎愛さんが元気付けられるのを感じて元気付けられた気がしました。良い話。

4. Maixduino

前回の記事の続きみたいな内容です。

BME280

mstdn.maud.io

秋月の BME280 キットを SPI バスにぶら下げて、 SSD1331 に温度・湿度・気圧を表示させました。制御コードは、値の補正だけデータシートのコードをほぼそのまま引っ張ってきてそれ以外はだいたい自作しました。多分……

ILI9341

mstdn.maud.io

調子に乗って ILI9341 が載ってる QVGA サイズの TFT LCD もやっちゃいました。これはそこそこサイズがあるのでちょっと大きめの JPEG 画像を表示させたりしています。ILI9341 に限らないんですが LCD の初期化シーケンスって何かと秘伝のタレ状態になりがちです。僕も初期化時に送信するバイト列は Adafruit のライブラリのやつをそのまま使っています。

mstdn.maud.io

これ作った後に色々ググったんですけど JPEG デコード部分が遅すぎる気がするんですよね……。JPEGデコードではなく SD カードからファイルを読む部分が遅いという説もあるので、一旦メモリにファイルを全部読んでしまってからそれをデコードするようにすれば改善するかもしれません。

やるか。

TJpgDec は入力用の関数(JPEG ストリームを読み込む)、出力用の関数(デコードされたビットマップを適切なデバイスに出力する)、それとワークとして 3092bytes のメモリ領域を要求します。 よくあるマイコンだと最後のワーク容量がなかなかデカくて厳しいところですが、 Maixduino には SRAM が 6MB (その気になれば 8MB) も載っているので、大した胸囲ではありません。……それは夏稀のことでしょうが。脅威ではありません。

というわけでファイルを全部読んでからそれをJPEGデコードします。

/**
 * RAM 上の領域から読み込む
 */
uint16_t jpegio_input_memory(JDEC *jdec, uint8_t *buff, uint16_t ndata) {
    JpegDevice *device = reinterpret_cast<JpegDevice *>(jdec->device);
    size_t rest = device->memory.size - device->memory.current;
    size_t readSize = rest < ndata ? rest : ndata;

    if (buff) {
        memcpy(buff, device->memory.data + device->memory.current, readSize);
    }
    device->memory.current += readSize;
    return readSize;
}

結果からいうと大して速くなりませんでした。チキショー!

5. オンゲキ

mstdn.maud.io

最近やっと 15.70 に乗りました。次は 15.80 ですね……

オンゲキ SUMMER で追加された中からのおすすめ

  • Baqeela
    • 安心と信頼の owl*tree
    • 緑ホールドのところがたのしい
  • Lazy Addiction
    • 爽快感抜群
    • 後半はつらい
  • Desperado Waltz
    • 夕方にやれ
    • マケマセンカラ! の後は……どうするんだろう……
  • HONEY-Q
    • ホールド終点の音が気持ちいい
  • 人類みなセンパイ!
    • 「センパイ!」のところとかあと「おつおつおー」のところのPV再現が光る
  • フィクサー
    • Baqeela
    • Rule the World!
    • 人類みなセンパイ!
    • を合わせたような楽しい譜面。これオンゲキ初参戦のすきやき奉行ってマ?
  • SILENT BLUE
    • これも PV 再現が良い
    • 脳トレは案外できる

あとがき

今回は複数のトピックをざっくばらんに書いていくスタイルにしてみました。結果として長めになってしまいましたが……。 今週の輪講用のスライドを作らなければいけなかったはずなんですが、書きたいことが大量に降ってきてしまったので、「書きたいときに書く」というモットーに従ってガーっと書き上げました。

mstdn.maud.io のほうについては、 Einsamkeit の開発が難航していることもあってしばらく他のサーバーにメインのアカウントを移すことはないと思うので、来年もよろしくお願いします。

明日は Fagnux さんの記事です。


f:id:kb10uy:20191201184950j:plain 「AAAAAAHHHHHHH」