109 lines
3.7 KiB
TypeScript
109 lines
3.7 KiB
TypeScript
import { createWorker, setLogging } from '@ffmpeg/ffmpeg';
|
|
import { AtracdencProcess } from './atracdenc-worker';
|
|
const AtracdencWorker = require('worker-loader!./atracdenc-worker'); // eslint-disable-line import/no-webpack-loader-syntax
|
|
|
|
interface LogPayload {
|
|
message: string;
|
|
action: string;
|
|
}
|
|
|
|
export interface AudioExportService {
|
|
init(): Promise<void>;
|
|
export(params: { format: string }): Promise<ArrayBuffer>;
|
|
info(): Promise<{ format: string | null; input: string | null }>;
|
|
prepare(file: File): Promise<void>;
|
|
}
|
|
|
|
export class FFMpegAudioExportService implements AudioExportService {
|
|
public ffmpegProcess: any;
|
|
public atracdencProcess?: AtracdencProcess;
|
|
public loglines: { action: string; message: string }[] = [];
|
|
public inFileName: string = ``;
|
|
public outFileNameNoExt: string = ``;
|
|
|
|
async init() {
|
|
setLogging(true);
|
|
}
|
|
|
|
async prepare(file: File) {
|
|
this.loglines = [];
|
|
this.ffmpegProcess = createWorker({
|
|
logger: (payload: LogPayload) => {
|
|
this.loglines.push(payload);
|
|
console.log(payload.action, payload.message);
|
|
},
|
|
corePath: '/ffmpeg-core.js',
|
|
// workerPath: '/worker.min.js',
|
|
workerPath: '/worker.dev.js',
|
|
});
|
|
await this.ffmpegProcess.load();
|
|
|
|
this.atracdencProcess = new AtracdencProcess(new AtracdencWorker());
|
|
await this.atracdencProcess.init();
|
|
|
|
let ext = file.name.split('.').slice(-1);
|
|
if (ext.length === 0) {
|
|
throw new Error(`Unrecognized file format: ${file.name}`);
|
|
}
|
|
|
|
this.inFileName = `inAudioFile.${ext[0]}`;
|
|
this.outFileNameNoExt = `outAudioFile`;
|
|
|
|
await this.ffmpegProcess.write(this.inFileName, file);
|
|
}
|
|
|
|
async info() {
|
|
await this.ffmpegProcess.transcode(this.inFileName, `${this.outFileNameNoExt}.metadata`, `-f ffmetadata`);
|
|
|
|
let audioFormatRegex = /Audio:\s(.*?),/; // Actual content
|
|
let inputFormatRegex = /Input #0,\s(.*?),/; // Container
|
|
let format: string | null = null;
|
|
let input: string | null = null;
|
|
|
|
for (let line of this.loglines) {
|
|
let match = line.message.match(audioFormatRegex);
|
|
if (match !== null) {
|
|
format = match[1];
|
|
continue;
|
|
}
|
|
match = line.message.match(inputFormatRegex);
|
|
if (match !== null) {
|
|
input = match[1];
|
|
continue;
|
|
}
|
|
if (format !== null && input !== null) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return { format, input };
|
|
}
|
|
|
|
async export({ format }: { format: string }) {
|
|
if (format === `SP`) {
|
|
const outFileName = `${this.outFileNameNoExt}.raw`;
|
|
await this.ffmpegProcess.transcode(this.inFileName, outFileName, '-f s16be');
|
|
let { data } = await this.ffmpegProcess.read(outFileName);
|
|
return data.buffer;
|
|
} else {
|
|
const outFileName = `${this.outFileNameNoExt}.wav`;
|
|
await this.ffmpegProcess.transcode(this.inFileName, outFileName, '-f wav');
|
|
let { data } = await this.ffmpegProcess.read(outFileName);
|
|
let bitrate: string = `0`;
|
|
switch (format) {
|
|
case `LP2`:
|
|
bitrate = `128`;
|
|
break;
|
|
case `LP105`:
|
|
bitrate = `102`;
|
|
break;
|
|
case `LP4`:
|
|
bitrate = `64`;
|
|
break;
|
|
}
|
|
let result = await this.atracdencProcess!.encode(data.buffer, bitrate);
|
|
return result;
|
|
}
|
|
}
|
|
}
|