Loading files
import fs from 'fs'
import http from 'http'
import path from 'path'
import wae from 'web-audio-engine'
import { hideBin } from 'yargs/helpers'
import yargs from 'yargs/yargs'
import shiftPitch from './pitch-shift.js'
const AudioContext = wae.RenderingAudioContext
/**
* @description download wav file from tts server
* @param {string} url
* @param {string} path
* @param {object} options
*/
async function download(url, path, options) {
return new Promise((resolve, reject) => {
// let count = 0
console.log(`url: ${url}`)
http.get(url, (res) => {
const data = []
res.on('data', (d) => {
data.push(d)
// console.log(`Downloading (${count++})`)
})
res
.on('close', () => {
const rawData = Buffer.concat(data)
console.log('Downloaded')
const context = new AudioContext()
context.decodeAudioData(rawData).then((audioBuffer) => {
if (options.shift !== 1) {
shiftPitch(audioBuffer, options.shift)
const source = context.createBufferSource()
source.buffer = audioBuffer
let ended = false
source.onended = () => {
ended = true
console.log('ended')
}
source.connect(context.destination)
source.start()
const tick = 0.1
let currentTime = 0
while (!ended) {
context.processTo(currentTime)
currentTime = currentTime + tick
}
const audioData = context.exportAsAudioData()
context.encodeAudioData(audioData).then((audioData) => {
fs.writeFileSync(path, Buffer.from(audioData))
})
} else {
fs.writeFileSync(path, Buffer.from(rawData))
}
resolve()
})
})
.on('error', (e) => {
console.log(`Got error: ${e.message}`)
file.end()
reject()
})
})
})
}
// generate speeches
async function generate(options) {
for (const [key, text] of Object.entries(speeches)) {
const file = `${options.output}/${key}.wav`
if (fs.existsSync(file)) {
fs.unlinkSync(file, (err) => {
if (err) {
console.log(err)
return
}
})
}
const url = `http://${options.host}:${options.port}/api/tts?text=${text}`
// NOTE: need to await coz current tts-server supports one request at a time
await download(url, file, options)
}
}
const options = []
const argv = yargs(hideBin(process.argv)).argv
// read TTS server configuration
const manifest = JSON.parse(fs.readFileSync('./host/app/manifest_local.json'))
const config = manifest.config
console.debug(manifest.config)
options.host = config.tts?.host
options.port = config.tts?.port
if (argv.host) options.host = argv.host
if (argv.port) options.port = argv.port
if (!options.host || !options.port) {
throw new Error('specify tts.host and tts.port in host/app/manifest_local.json or --host --port options required')
}
const cwd = process.cwd() // save CurrentDiredtory (firmware Directory)
process.chdir(process.env.INIT_CWD) // change CurrntDirectory to npm run was executed direcory
const input = argv.input
if (input) {
console.log(`cwd :${process.cwd()}`)
console.log(`input :${input}`)
options.input = path.resolve(input)
if (input !== options.input) {
console.log(` (${options.input})`)
}
} else {
if (fs.existsSync('./speeches.js')) {
console.log(`cwd :${process.cwd()}`)
console.log('input :./speeches.js')
options.input = path.resolve('./speeches.js')
} else {
process.chdir(cwd) // change CurrentDirectory to saved(firmware Directory)
console.log(`cwd :${process.cwd()}`)
console.log('input :./host/modules/audio/assets/sounds/speeches_ja.js')
options.input = path.resolve('./host/modules/audio/assets/sounds/speeches_ja.js')
}
console.log(` (${options.input})`)
}
const output = argv.output
if (output) {
options.output = path.resolve(output)
console.log(`output:${output}`)
if (output !== options.output) {
console.log(` (${options.output})`)
}
} else {
if (fs.existsSync(`${path.dirname(options.input)}/assets`)) {
console.log('output:./assets')
options.output = `${path.dirname(options.input)}/assets`
console.log(` (${options.output})`)
} else {
options.output = path.dirname(options.input)
console.log(`output:${options.output}`)
}
}
const { speeches, SynthProps } = await import(`file://${options.input}`)
options.shift = SynthProps?.shift ?? 1.5
if (argv.shift) options.shift = argv.shift
generate(options)
f1d839032This file is pinned to the selected release. Download the original to open it in your design tool.