平衡点


2006/05/27

_ 肉とビール

突発的に「肉とビールが喰いたい」と騒いだら, 先輩が「家に来いゴルァ(嘘)」と.

そんな訳で突然, 先輩の家へ伺い, 焼肉ビールという贅沢をしました.

ありがたかったです. というかいきなり押し掛けてすいません. S 山さんの奥さん.

S 山さん, またやりましょーねー. 今度はもっと大勢で(違)

_ ToDo[Work

書いておかないと忘れそうなんでメモ.

  • 連合大会のメモをメール
    • 連合大会ってかくと, 労組みたいだな. 念の為, これ地球惑星科学連合大会です.
  • 中学での講義についてメール
  • 計算機のメモリ換装 + 計算結果のまとめ
  • SPMODEL の Web について検討
  • Pr, Pm に関する数値実験のレビュー作成

かな. 明日は使えない人になっちまうけど, 月曜の午前は使える, ハズ.

_ 体調が

半端無い.

  • 熱は無い
  • 下痢が酷い. というか, 水ばっか出やがる.
  • 鼻水も酷い. 透明な奴が沢山出る. 頭も少し重い.

鼻水だけなら花粉症かな, とか思ってんだが(シーズン違う?) 下痢はなんだろ. 久々に牛乳飲み始めたんだけど, その所為かな.

明日どうなってんだべ. 私は.


2013/05/27

_ multipart/mixed と multipart/alternative[Computer

以前 Apple Mail から送信されたメールが Wanderlust で decode できない場合の対処方 なんてことを書いてましたが, 前日 @znz さんに,

「HTML メールで画像とか使う場合もあるし」

といわれて, そういう場合には確かに, と納得してしまった.

とはいえ, 添付ファイルはなんとかならんかなぁ, と思う. (個人的には HTML メールも好きではないが).

_ sysvinit 代替[Computer

今更ながら upstart や systemd の良い点を誰かにサマリして欲しい.

「起動が速い」とかは(少なくとも)私にとってはわざわざ replcae する程の 利点にはならないので, なんかそれ以外の利点を上手く説明して欲しいなぁ, というか.

まあ debian-devel の

あたりを見ていて思った程度なんですけれど.


2021/05/27

_ Amazon Echo Show 8、続き[Computer

前回(Amazon Echo Show 8 - 2021/05/25)の続き.

Echo Show 8 (エコーショー8) HDスマートディスプレイ with Alexa、チャコール Echo Show 8 (エコーショー8) HDスマートディスプレイ with Alexa、チャコール
Amazon

何度からペアリング→解除を繰替えしたら スマホにある音楽を bluetooth 経由で流すことはできた. というわけで Amazon Music はとりあえず保留. Prime 会員なので, Amazon Prime Music は使えるけど, 使うかどうかは未定だな.

音量調節は駄目っぽい. 最小音量でもだいぶ騒々しい. …日本の家屋には向いてないんじゃないかな, これ. 面倒だけど, 細かく音量調節できるスピーカーでも買おうかしらねぇ.

画面が出ることでの恩恵には今のところ与ってないわけですが, 今後どうなることやら.

あ, Nature Remo と連携してのスマート家電(?)は, まあデキているので, 最低限の用途は足りているわけですが. .


2026/05/27

_ JpGU-AGU 2026 に来てます[Work

北海道からだと, 気温 +10℃なので, やっぱりシンドいね.

_ Beamer と pdfpc の組み合わせで発表原稿を表示させつつ, 読み上げをする

読んで字の如く.

発表資料の作成

\usepackage{pdfpc}
\newcommand<>{\talknote}[1]{\only#2{\pdfpcnote{#1}\relax}}

とでもしておいて, スライドの overlay に合わせて

\talknote{
  Thank you for the introduction.
  <br><br>
  Hello everyone.
  My name is Youhei Sasaki from Hokkaido Information University.
  <br><br>
  Today, I would like to talk about This titie.
  <br><br>
  To put it simply, this is a story about ...
}

とでも書いておくと pdfpc の presenter screen に原稿が表示される.

読み上げ音声の作成

あとは TeX ないの \talknote をパースして, Google の Cloud Text-to-Speech API に投げると, 良い感じに読み上げ音声が出てくる(ので, あとはシャドーイング).

スクリプトはこんなん.

import os
import re
import subprocess
from google.cloud import texttospeech

def main():
    # ------------------------------------------------------------------------
    # 設定エリア
    # ------------------------------------------------------------------------
    TEX_FILENAME = 'your_presentation.tex'
    SPEAKING_RATE = 0.7
    PITCH = 0.0
    OUTPUT_DIR = "audio_output"

    # --- 結合時の設定 -------------------------------------------------------
    # スライド間の無音時間(秒)
    SILENCE_DURATION_SEC = 2

    client = texttospeech.TextToSpeechClient()

    with open(TEX_FILENAME, 'r', encoding='utf-8') as f:
        tex_content = f.read()

    frames = re.split(r'\\begin\{frame\}', tex_content)[1:]
    os.makedirs(OUTPUT_DIR, exist_ok=True)
    voice = texttospeech.VoiceSelectionParams(language_code="en-US", name="en-US-Journey-D")

    audio_config = texttospeech.AudioConfig(
        audio_encoding=texttospeech.AudioEncoding.MP3,
        speaking_rate=SPEAKING_RATE,
        pitch=PITCH
    )

    generated_files = []

    for frame_idx, frame_content in enumerate(frames, start=1):
        # --------------------------------------------------------------------
        # \talknote を探す前に、TeXのコメント(%から行末まで)を削除
        # --------------------------------------------------------------------
        frame_content_uncommented = re.sub(r'(?<!\\)%.*', '', frame_content)

        # コメントが除去されたクリーンな文字列から \talknote を抽出
        talknotes = re.finditer(r'\\talknote\s*(?:<([^>]+)>)?\s*\{(.*?)\}', frame_content_uncommented, re.DOTALL)

        for note_idx, note in enumerate(talknotes, start=1):
            overlay = note.group(1) or "1"
            raw_text = note.group(2)

            # <br><br> (あるいは <br>) を区切りとして処理
            chunks = re.split(r'<br\s*/?>\s*<br\s*/?>|<br\s*/?>', raw_text)

            processed_chunks = []
            for chunk in chunks:
                chunk = re.sub(r'\s+', ' ', chunk).strip()
                if chunk:
                    processed_chunks.append(chunk)

            final_text = '\n\n'.join(processed_chunks)

            print("-" * 50)
            print(f"Slide {frame_idx} (Overlay {overlay}) の処理を開始...")

            if not final_text:
                print(f"  -> 原稿が空のため、音声生成をスキップします。")
                continue

            print(f"  [DEBUG] 送信テキスト:\n{final_text}\n")

            filename = f"slide_{frame_idx:02d}_overlay{overlay}.mp3"
            filepath = os.path.join(OUTPUT_DIR, filename)

            try:
                res = client.synthesize_speech(
                    input=texttospeech.SynthesisInput(text=final_text),
                    voice=voice,
                    audio_config=audio_config
                )

                with open(filepath, "wb") as out:
                    out.write(res.audio_content)

                generated_files.append(filepath)
                print(f"  生成完了: {filename}")

            except Exception as e:
                print(f"  エラー発生: {e}")

    # ------------------------------------------------------------------------
    # ffmpeg を利用した無劣化結合 (無音区間の挿入)
    # ------------------------------------------------------------------------
    if generated_files:
        print("=" * 50)
        print(f"ffmpeg を使用して結合し、間に {SILENCE_DURATION_SEC} 秒の無音を挿入...")

        silence_file = os.path.join(OUTPUT_DIR, "silence.mp3")
        subprocess.run([
            "ffmpeg", "-y", "-f", "lavfi", "-i", "anullsrc=r=24000:cl=mono",
            "-t", str(SILENCE_DURATION_SEC), "-c:a", "libmp3lame", silence_file
        ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

        list_file = os.path.join(OUTPUT_DIR, "concat_list.txt")
        with open(list_file, "w", encoding="utf-8") as lf:
            for i, fpath in enumerate(generated_files):
                lf.write(f"file '{os.path.basename(fpath)}'\n")
                if i < len(generated_files) - 1:
                    lf.write(f"file 'silence.mp3'\n")

        combined_filepath = os.path.join(OUTPUT_DIR, "presentation_all.mp3")
        subprocess.run([
            "ffmpeg", "-y", "-f", "concat", "-safe", "0",
            "-i", list_file, "-c", "copy", combined_filepath
        ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

        if os.path.exists(list_file): os.remove(list_file)
        if os.path.exists(silence_file): os.remove(silence_file)

        print(f" 結合完了: {combined_filepath}")
        print("=" * 50)
    else:
        print("結合するファイルがありませんでした。")

if __name__ == "__main__":
    main()
  1. 音声ファイルの結合に ffmpeg を使ってるので別途インストールしておく.
  2. Goocle Cloud API で 「Cloud Text-to-Speech API」を使うので
    • Google Cloud Console でプロジェクトを作成し,「Cloud Text-to-Speech API」を有効化
    • 「IAMと管理」>「サービス アカウント」からキー(JSONファイル)を作成・ダウンロード
    • ダウンロードした JSON ファイルのパスを,環境変数に設定
      $ export GOOGLE_APPLICATION_CREDENTIALS="/path/to/your/service-account-file.json"
      
  3. venv で必要なライブラリのインストール
    • 仮想環境 (.venv) を作成
      $ python3 -m venv .venv
      $ source .venv/bin/activate
      
    • 必要な Python パッケージをインストール
      $ pip install google-cloud-texttospeech
      

でまあ, あとは適宜実行する.

忘れそうなのでここに書いておく.

_ Beamer で画像も covered/uncover を使いたい

これ, デフォルトでこうなっていて欲しんだけれどなぁ.

\RequirePackage{tikz}
% 透過度の設定(デフォルト15%. お好みで)
\newcommand{\coveredopacity}{0.15}
% \coveredincludegraphics 命令の定義
% d<> でオーバーレイ指定, O{} でオプション引数, m で必須引数を受け取る
\NewDocumentCommand{\coveredincludegraphics}{ d<> O{} m }{%
  \IfNoValueTF{#1}{%
    % オーバーレイ指定 (<...>) がない場合は, 通常の \includegraphics
    \includegraphics[#2]{#3}%
  }{%
    % オーバーレイ指定がある場合は, TikZ ノードの opacity を切り替え
    \begin{tikzpicture}[baseline=(current bounding box.south)]%
      \alt<#1>{%
        % 指定されたスライド (uncovered) では opacity=1 (100%)
        \node[opacity=1, inner sep=0pt, outer sep=0pt] {\includegraphics[#2]{#3}};
      }{%
        % それ以外のスライド (covered) では opacity=\coveredopacity (15%)
        \node[opacity=\coveredopacity, inner sep=0pt, outer sep=0pt] {\includegraphics[#2]{#3}};
      }%
    \end{tikzpicture}%
  }%
}

連絡先など

portrait

最近の日記

一覧

Back to Top ▲