Skip to main content
Glama
test-audio-generator.js7.58 kB
import { promises as fs } from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); /** * Test audio file generator * Creates minimal valid audio file structures for testing */ export class TestAudioGenerator { /** * Create a minimal MP3 file with ID3 tag */ static async createTestMP3(filePath, options = {}) { const { title = 'Test Song', artist = 'Test Artist', duration = 10, bitrate = 128 } = options; // Basic ID3v2.3 header const id3Header = Buffer.from([ 0x49, 0x44, 0x33, // "ID3" 0x03, 0x00, // Version 2.3 0x00, // Flags 0x00, 0x00, 0x00, 0x7F // Size (127 bytes) ]); // TIT2 frame (Title) const titleFrame = this.createID3Frame('TIT2', title); // TPE1 frame (Artist) const artistFrame = this.createID3Frame('TPE1', artist); // Minimal MP3 frame header (fake audio data) const mp3Frame = Buffer.from([ 0xFF, 0xFB, 0x90, 0x00, // MP3 frame sync + header ...Array(100).fill(0x00) // Dummy audio data ]); const fileContent = Buffer.concat([id3Header, titleFrame, artistFrame, mp3Frame]); await fs.writeFile(filePath, fileContent); } /** * Create a minimal WAV file */ static async createTestWAV(filePath, options = {}) { const { sampleRate = 44100, channels = 2, bitsPerSample = 16, durationSeconds = 1 } = options; const dataSize = sampleRate * channels * (bitsPerSample / 8) * durationSeconds; const fileSize = 36 + dataSize; const header = Buffer.alloc(44); // RIFF header header.write('RIFF', 0); header.writeUInt32LE(fileSize, 4); header.write('WAVE', 8); // fmt chunk header.write('fmt ', 12); header.writeUInt32LE(16, 16); // fmt chunk size header.writeUInt16LE(1, 20); // audio format (PCM) header.writeUInt16LE(channels, 22); header.writeUInt32LE(sampleRate, 24); header.writeUInt32LE(sampleRate * channels * (bitsPerSample / 8), 28); // byte rate header.writeUInt16LE(channels * (bitsPerSample / 8), 32); // block align header.writeUInt16LE(bitsPerSample, 34); // data chunk header.write('data', 36); header.writeUInt32LE(dataSize, 40); // Generate simple sine wave data const audioData = Buffer.alloc(dataSize); for (let i = 0; i < dataSize / 2; i++) { const sample = Math.sin(2 * Math.PI * 440 * i / sampleRate) * 32767; audioData.writeInt16LE(sample, i * 2); } const fileContent = Buffer.concat([header, audioData]); await fs.writeFile(filePath, fileContent); } /** * Create a minimal FLAC file */ static async createTestFLAC(filePath, options = {}) { const { sampleRate = 44100, channels = 2, bitsPerSample = 16 } = options; // FLAC signature const flacSignature = Buffer.from('fLaC', 'ascii'); // STREAMINFO metadata block (mandatory) const streamInfo = Buffer.alloc(42); streamInfo[0] = 0x80; // Last metadata block flag + block type (0) streamInfo.writeUIntBE(34, 1, 3); // Block length streamInfo.writeUInt16BE(16, 4); // Min block size streamInfo.writeUInt16BE(4096, 6); // Max block size streamInfo.writeUIntBE(0, 8, 3); // Min frame size streamInfo.writeUIntBE(0, 11, 3); // Max frame size streamInfo.writeUIntBE((sampleRate << 12) | ((channels - 1) << 9) | ((bitsPerSample - 1) << 4), 14, 4); // Minimal frame data (just header) const frameHeader = Buffer.from([0xFF, 0xF8, 0xC8, 0x00]); const fileContent = Buffer.concat([flacSignature, streamInfo, frameHeader]); await fs.writeFile(filePath, fileContent); } /** * Create a minimal OGG file */ static async createTestOGG(filePath, options = {}) { // OGG page header const oggHeader = Buffer.from([ 0x4F, 0x67, 0x67, 0x53, // "OggS" 0x00, // Version 0x02, // Type flag (first page of logical bitstream) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Granule position 0x01, 0x02, 0x03, 0x04, // Serial number 0x00, 0x00, 0x00, 0x00, // Page sequence number 0x00, 0x00, 0x00, 0x00, // Checksum (would need to be calculated) 0x01, // Page segments 0x1E // Segment table (30 bytes) ]); // Minimal Vorbis identification header const vorbisHeader = Buffer.from([ 0x01, // Packet type ...Buffer.from('vorbis', 'ascii'), // "vorbis" 0x00, 0x00, 0x00, 0x00, // Version 0x02, // Channels 0x44, 0xAC, 0x00, 0x00, // Sample rate (44100) ...Array(16).fill(0x00) // Padding ]); const fileContent = Buffer.concat([oggHeader, vorbisHeader]); await fs.writeFile(filePath, fileContent); } /** * Create an ID3 frame */ static createID3Frame(frameId, content) { const contentBuffer = Buffer.from(content, 'utf8'); const frame = Buffer.alloc(10 + contentBuffer.length + 1); frame.write(frameId, 0); frame.writeUInt32BE(contentBuffer.length + 1, 4); frame.writeUInt16BE(0, 8); // Flags frame[10] = 0x00; // Text encoding (ISO-8859-1) contentBuffer.copy(frame, 11); return frame; } /** * Create test files for comprehensive testing */ static async createTestSuite(assetsDir) { await fs.mkdir(assetsDir, { recursive: true }); // Create various format samples await this.createTestMP3(path.join(assetsDir, 'sample.mp3'), { title: 'Sample MP3', artist: 'Test Artist', duration: 5 }); await this.createTestWAV(path.join(assetsDir, 'sample.wav'), { sampleRate: 44100, channels: 2, durationSeconds: 2 }); await this.createTestFLAC(path.join(assetsDir, 'sample.flac')); await this.createTestOGG(path.join(assetsDir, 'sample.ogg')); // Create files with different characteristics await this.createTestWAV(path.join(assetsDir, 'mono.wav'), { channels: 1, durationSeconds: 1 }); await this.createTestWAV(path.join(assetsDir, 'high-res.wav'), { sampleRate: 96000, bitsPerSample: 24, durationSeconds: 1 }); await this.createTestMP3(path.join(assetsDir, 'long-track.mp3'), { title: 'Long Track', duration: 300 // 5 minutes }); await this.createTestMP3(path.join(assetsDir, 'short-sfx.mp3'), { title: 'Sound Effect', duration: 2 }); // Create problematic files for error testing await fs.writeFile(path.join(assetsDir, 'corrupted.mp3'), 'Not a real MP3 file'); await fs.writeFile(path.join(assetsDir, 'empty.wav'), ''); // Create a file with partial header await fs.writeFile(path.join(assetsDir, 'partial.flac'), 'fLaC\x00'); console.log(`Test audio files created in ${assetsDir}`); } /** * Clean up test files */ static async cleanupTestSuite(assetsDir) { try { const files = await fs.readdir(assetsDir); for (const file of files) { await fs.unlink(path.join(assetsDir, file)); } await fs.rmdir(assetsDir); console.log(`Test files cleaned up from ${assetsDir}`); } catch (error) { console.warn(`Cleanup warning: ${error.message}`); } } } // Create test files if run directly if (import.meta.url === `file://${process.argv[1]}`) { const assetsDir = path.join(__dirname, 'assets'); await TestAudioGenerator.createTestSuite(assetsDir); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/DeveloperZo/mcp-audio-inspector'

If you have feedback or need assistance with the MCP directory API, please join our Discord server