// recover from audacity crash // usage: // node audacity_rescue.js [sourcedir] [result_file.wav] [mono|stereo] // the mono or stereo option is optional, the default is mono. // // Description: // This script will sort all files on modification date. // If you create a backup, make sure you use `cp -a` to preserve the modification date // or create a zip. // The resulting file will pretend to be a wave file (because of the .wav extension), but // is in fact a Audacity simple block file. You will have to open the resulting file with // audacity and then export it as a normal file. const fs = require('fs'); const pathLib = require('path'); const pj = pathLib.join; const srcdirname = process.argv[2]; const result_file = process.argv[3]; const type = process.argv[4]; if (!(srcdirname && result_file)) { console.log("Need both a source dir and a target file"); process.exit(1); } if (!type) type = 'mono'; if (! (type === 'mono' || type === 'stereo')) { console.log('invalid audio format'); } console.log('source dir name: ', srcdirname); console.log('result_file', result_file); // we need all files in the subdirectories of dirname // sorted by date const allFiles = []; function readFiles (dir) { const names = fs.readdirSync(dir); names.forEach(n => { const fullPath = pj(dir, n); const stats = fs.statSync(fullPath); if (stats.isDirectory()) { readFiles(fullPath); } else { if (pathLib.extname(n) === ".au") { allFiles.push({ name: fullPath, time: stats.mtime.getTime()}) } } }); } console.log('searching and sorting files by date'); readFiles(srcdirname); allFiles.sort( (a, b) => { return a.time - b.time; }); if (type === 'stereo') { console.log('writing result files'); const f = pathLib.parse(result_file); const left_fn = pathLib.join(f.root, f.dir, f.base + '_L' + f.ext); const right_fn = pathLib.join(f.root, f.dir, f.base + '_R' + f.ext); const fhL = fs.openSync(left_fn, 'w'); const fhR = fs.openSync(right_fn, 'w'); let targetPosL = 0; let targetPosR = 0; const numFiles = allFiles.length; allFiles.forEach( (f, i) => { console.log(`reading ${f.name} (${i} of ${numFiles})`); const buf = fs.readFileSync(f.name); const offset = (i === 0 || i === 1) ? 0: buf.readUInt16LE(4); if (i % 2 === 0) { // assume left targetPosL += fs.writeSync(fhL, buf, offset, buf.length-offset, targetPosL); } else { // assume right targetPosR += fs.writeSync(fhR, buf, offset, buf.length-offset, targetPosR); } }) fs.closeSync(fhL); fs.closeSync(fhR); } else { // now merge all files in the result console.log('writing result file'); const fh = fs.openSync(result_file, 'w'); let targetPos = 0; const numFiles = allFiles.length; allFiles.forEach( (f, i) => { console.log(`reading ${f.name} (${i} of ${numFiles})`); const buf = fs.readFileSync(f.name); const offset = i === 0? 0: buf.readUInt16LE(4); targetPos += fs.writeSync(fh, buf, offset, buf.length-offset, targetPos); }); fs.closeSync(fh); } console.log('Done');