はじめに
以下の「node-speaker」を使って、Node.js 上で PCM(Pulse-Code Modulation)オーディオデータを、直接スピーカーから再生する、という内容を試しました。
●speaker - npm
https://www.npmjs.com/package/speaker
これを試した背景
今回の内容をやろうと思った背景は、Google I/O 2025 で発表された以下の音楽生成を使い、Node.js で受信したデータから音を鳴らす、ということをやりたかったためです。
●Music generation | Gemini API | Google AI for Developers
https://ai.google.dev/gemini-api/docs/music-generation
●Lyria RealTime - Google DeepMind
https://deepmind.google/models/lyria/realtime/
ちなみに、上記のサンプルコード内の音を鳴らす処理は「// Application logic: buffer and play using Web Audio API etc.」と書いてあり、何らか自分で用意する必要がある状態でした。
実際に試していく
今回、node-speaker は初めて使うので、「シンプルな音のデータを単純に鳴らす」ということだけやってみます。
まず公式ページ上のサンプルを見てみると、以下が書かれています。
const Speaker = require('speaker');
// Create the Speaker instance
const speaker = new Speaker({
channels: 2, // 2 channels
bitDepth: 16, // 16-bit samples
sampleRate: 44100 // 44,100 Hz sample rate
});
// PCM data from stdin gets piped into the speaker
process.stdin.pipe(speaker);
これだけだと、音は鳴らない状態です。
音を鳴らす
下準備
今回の内容を試す下準備として、node-speaker をインストールします。
※ ちなみに、自分がこれを試している環境は Mac です
npm install speaker
自前の実装
鳴らす音の元データを作る部分と、それを鳴らす部分とを実装してみました。
import Speaker from "speaker";
const speaker = new Speaker({
channels: 2,
bitDepth: 16,
sampleRate: 44100,
signed: true,
float: false,
});
const durationSec = 2;
const freq = 440; // Hz
const sampleRate = 44100;
const totalSamples = sampleRate * durationSec;
let i = 0;
// 1サンプルあたり4バイト (ステレオ×16bit)
const CHUNK_SIZE = 1024; // サンプル数
function writeChunk() {
if (i >= totalSamples) {
speaker.end();
return;
}
const count = Math.min(CHUNK_SIZE, totalSamples - i);
const buf = Buffer.alloc(count * 4);
for (let j = 0; j < count; j++, i++) {
const t = i / sampleRate;
const v = Math.round(Math.sin(2 * Math.PI * freq * t) * 32767);
buf.writeInt16LE(v, j * 4); // 左
buf.writeInt16LE(v, j * 4 + 2); // 右
}
if (!speaker.write(buf)) {
speaker.once("drain", writeChunk);
} else {
setImmediate(writeChunk);
}
}
writeChunk();
これを実行すると、短い時間、シンプルな音が鳴るのが確認できました。
とりあえず、Node.js で node-speaker を使ってスピーカーから音を鳴らす、という内容は実現できました。
【追記】
その後、当初やりたかった「Gemini API での音楽生成に使う」というのも、無事に実装できました。
(やたらと文字が出力されているのは、実装を試す途中でエラーが出たり、エラーは出ないけど音が鳴らなかったりという状態になって、データ受信や各処理の動作を確認するデバッグ情報を出してるためです)