103 lines
2.5 KiB
TypeScript
103 lines
2.5 KiB
TypeScript
/**
|
|
* 音频处理工具
|
|
*
|
|
* 提供音频文件的解析和处理功能
|
|
*
|
|
* @module audio-processor
|
|
* @created 2025-12-14
|
|
*/
|
|
|
|
import { parseBuffer, parseFile } from 'music-metadata'
|
|
import type { IAudioMetadata } from 'music-metadata'
|
|
|
|
/**
|
|
* 音频元数据
|
|
*/
|
|
export interface AudioMetadata {
|
|
duration: number // 时长(秒)
|
|
durationFormatted: string // 格式化时长 (mm:ss)
|
|
format: string // 音频格式
|
|
bitrate?: number // 比特率
|
|
sampleRate?: number // 采样率
|
|
channels?: number // 声道数
|
|
}
|
|
|
|
/**
|
|
* 格式化时长为 mm:ss 格式
|
|
*/
|
|
export function formatDuration(seconds: number): string {
|
|
const mins = Math.floor(seconds / 60)
|
|
const secs = Math.floor(seconds % 60)
|
|
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
|
|
}
|
|
|
|
function toAudioMetadata(metadata: IAudioMetadata): AudioMetadata {
|
|
const duration = metadata.format.duration || 0
|
|
|
|
return {
|
|
duration,
|
|
durationFormatted: formatDuration(duration),
|
|
format: metadata.format.container || 'unknown',
|
|
bitrate: metadata.format.bitrate,
|
|
sampleRate: metadata.format.sampleRate,
|
|
channels: metadata.format.numberOfChannels,
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 解析音频文件获取元数据
|
|
*
|
|
* @param buffer - 音频文件的 Buffer
|
|
* @param mimeType - 音频文件的 MIME 类型
|
|
* @returns 音频元数据
|
|
*/
|
|
export async function parseAudioMetadata(
|
|
buffer: Buffer,
|
|
mimeType?: string
|
|
): Promise<AudioMetadata | null> {
|
|
try {
|
|
const metadata = await parseBuffer(buffer, { mimeType })
|
|
return toAudioMetadata(metadata)
|
|
} catch (error) {
|
|
console.error('[AudioProcessor] Failed to parse audio metadata:', error)
|
|
return null
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 从本地临时文件解析音频元数据,避免大音频整文件进入内存
|
|
*/
|
|
export async function parseAudioMetadataFromFile(
|
|
filePath: string
|
|
): Promise<AudioMetadata | null> {
|
|
try {
|
|
const metadata = await parseFile(filePath)
|
|
return toAudioMetadata(metadata)
|
|
} catch (error) {
|
|
console.error('[AudioProcessor] Failed to parse audio metadata from file:', error)
|
|
return null
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 检查文件是否为音频文件
|
|
*/
|
|
export function isAudioFile(mimeType: string): boolean {
|
|
return mimeType.startsWith('audio/')
|
|
}
|
|
|
|
/**
|
|
* 支持的音频格式
|
|
*/
|
|
export const SUPPORTED_AUDIO_FORMATS = [
|
|
'audio/mpeg', // MP3
|
|
'audio/wav', // WAV
|
|
'audio/x-wav',
|
|
'audio/flac', // FLAC
|
|
'audio/aac', // AAC
|
|
'audio/mp4', // M4A
|
|
'audio/x-m4a',
|
|
'audio/ogg', // OGG
|
|
'audio/webm', // WebM
|
|
]
|