initial commit
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Convert raw PCM to WAV format for easier playback and verification
|
||||
function pcmToWav(pcmBuffer, outputPath, sampleRate = 24000, channels = 1, bitDepth = 16) {
|
||||
const byteRate = sampleRate * channels * (bitDepth / 8);
|
||||
const blockAlign = channels * (bitDepth / 8);
|
||||
const dataSize = pcmBuffer.length;
|
||||
|
||||
// Create WAV header
|
||||
const header = Buffer.alloc(44);
|
||||
|
||||
// "RIFF" chunk descriptor
|
||||
header.write('RIFF', 0);
|
||||
header.writeUInt32LE(dataSize + 36, 4); // File size - 8
|
||||
header.write('WAVE', 8);
|
||||
|
||||
// "fmt " sub-chunk
|
||||
header.write('fmt ', 12);
|
||||
header.writeUInt32LE(16, 16); // Subchunk1Size (16 for PCM)
|
||||
header.writeUInt16LE(1, 20); // AudioFormat (1 for PCM)
|
||||
header.writeUInt16LE(channels, 22); // NumChannels
|
||||
header.writeUInt32LE(sampleRate, 24); // SampleRate
|
||||
header.writeUInt32LE(byteRate, 28); // ByteRate
|
||||
header.writeUInt16LE(blockAlign, 32); // BlockAlign
|
||||
header.writeUInt16LE(bitDepth, 34); // BitsPerSample
|
||||
|
||||
// "data" sub-chunk
|
||||
header.write('data', 36);
|
||||
header.writeUInt32LE(dataSize, 40); // Subchunk2Size
|
||||
|
||||
// Combine header and PCM data
|
||||
const wavBuffer = Buffer.concat([header, pcmBuffer]);
|
||||
|
||||
// Write to file
|
||||
fs.writeFileSync(outputPath, wavBuffer);
|
||||
|
||||
return outputPath;
|
||||
}
|
||||
|
||||
// Analyze audio buffer for debugging
|
||||
function analyzeAudioBuffer(buffer, label = 'Audio') {
|
||||
const int16Array = new Int16Array(buffer.buffer, buffer.byteOffset, buffer.length / 2);
|
||||
|
||||
let minValue = 32767;
|
||||
let maxValue = -32768;
|
||||
let avgValue = 0;
|
||||
let rmsValue = 0;
|
||||
let silentSamples = 0;
|
||||
|
||||
for (let i = 0; i < int16Array.length; i++) {
|
||||
const sample = int16Array[i];
|
||||
minValue = Math.min(minValue, sample);
|
||||
maxValue = Math.max(maxValue, sample);
|
||||
avgValue += sample;
|
||||
rmsValue += sample * sample;
|
||||
|
||||
if (Math.abs(sample) < 100) {
|
||||
silentSamples++;
|
||||
}
|
||||
}
|
||||
|
||||
avgValue /= int16Array.length;
|
||||
rmsValue = Math.sqrt(rmsValue / int16Array.length);
|
||||
|
||||
const silencePercentage = (silentSamples / int16Array.length) * 100;
|
||||
|
||||
console.log(`${label} Analysis:`);
|
||||
console.log(` Samples: ${int16Array.length}`);
|
||||
console.log(` Min: ${minValue}, Max: ${maxValue}`);
|
||||
console.log(` Average: ${avgValue.toFixed(2)}`);
|
||||
console.log(` RMS: ${rmsValue.toFixed(2)}`);
|
||||
console.log(` Silence: ${silencePercentage.toFixed(1)}%`);
|
||||
console.log(` Dynamic Range: ${20 * Math.log10(maxValue / (rmsValue || 1))} dB`);
|
||||
|
||||
return {
|
||||
minValue,
|
||||
maxValue,
|
||||
avgValue,
|
||||
rmsValue,
|
||||
silencePercentage,
|
||||
sampleCount: int16Array.length,
|
||||
};
|
||||
}
|
||||
|
||||
// Save audio buffer with metadata for debugging
|
||||
function saveDebugAudio(buffer, type, timestamp = Date.now()) {
|
||||
const homeDir = require('os').homedir();
|
||||
const debugDir = path.join(homeDir, 'cheating-daddy-debug');
|
||||
|
||||
if (!fs.existsSync(debugDir)) {
|
||||
fs.mkdirSync(debugDir, { recursive: true });
|
||||
}
|
||||
|
||||
const pcmPath = path.join(debugDir, `${type}_${timestamp}.pcm`);
|
||||
const wavPath = path.join(debugDir, `${type}_${timestamp}.wav`);
|
||||
const metaPath = path.join(debugDir, `${type}_${timestamp}.json`);
|
||||
|
||||
// Save raw PCM
|
||||
fs.writeFileSync(pcmPath, buffer);
|
||||
|
||||
// Convert to WAV for easy playback
|
||||
pcmToWav(buffer, wavPath);
|
||||
|
||||
// Analyze and save metadata
|
||||
const analysis = analyzeAudioBuffer(buffer, type);
|
||||
fs.writeFileSync(
|
||||
metaPath,
|
||||
JSON.stringify(
|
||||
{
|
||||
timestamp,
|
||||
type,
|
||||
bufferSize: buffer.length,
|
||||
analysis,
|
||||
format: {
|
||||
sampleRate: 24000,
|
||||
channels: 1,
|
||||
bitDepth: 16,
|
||||
},
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
);
|
||||
|
||||
console.log(`Debug audio saved: ${wavPath}`);
|
||||
|
||||
return { pcmPath, wavPath, metaPath };
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
pcmToWav,
|
||||
analyzeAudioBuffer,
|
||||
saveDebugAudio,
|
||||
};
|
||||
Reference in New Issue
Block a user