Category talk:Wren-sound
Appearance
Source code
/* Module "sound.wren" */
import "io" for File
/* Wav enables the creation of simple .wav files for playing by external utiliies. */
class Wav {
// Private method to convert a 16-bit unsigned integer 'x'
// to a list of 2 bytes in little-endian format.
static fromInt16LE_(x) {
var bytes = List.filled(2, 0)
bytes[0] = x & 255
bytes[1] = (x >> 8) & 255
return bytes
}
// Private method to convert a 32-bit unsigned integer 'x'
// to a list of 4 bytes in little-endian format.
static fromInt32LE_(x) {
var bytes = List.filled(4, 0)
bytes[0] = x & 255
bytes[1] = (x >> 8) & 255
bytes[2] = (x >> 16) & 255
bytes[3] = (x >> 24) & 255
return bytes
}
// Creates or overwrites an existing .wav file on disk using the given sample rate.
// Such files are always single channel and use the PCM format.
static create(filePath, data, sampleRate) {
if (filePath.type != String) Fiber.abort("File path must be a string.")
if (data.type != List || data.count == 0 || data[0].type != Num || !data[0].isInteger) {
Fiber.abort("Data must be a non-empty list of whdr.")
}
if (sampleRate.type != Num || !sampleRate.isInteger || sampleRate < 1) {
Fiber.abort("Sample rate must be a positive integer.")
}
var dataLength = data.count
var hdrSize = 44
var fileLen = dataLength + hdrSize - 8 // file size - 8
// buffers
var buf2 = List.filled(2, 0)
var buf4 = List.filled(4, 0)
// WAV header
var whdr = []
whdr.addAll("RIFF".bytes)
whdr.addAll(fromInt32LE_(fileLen)) // fileLen
whdr.addAll("WAVE".bytes)
whdr.addAll("fmt ".bytes)
whdr.addAll(fromInt32LE_(16)) // length of format data (= 16)
var temp = fromInt16LE_(1)
whdr.addAll(temp) // type of format (= 1 (PCM))
whdr.addAll(temp) // number of channels (= 1)
var temp2 = fromInt32LE_(sampleRate)
whdr.addAll(temp2) // sample rate (= sr)
whdr.addAll(temp2) // sr * bps(8) * channels(1) / 8 (= sr)
whdr.addAll(temp) // bps(8) * channels(1) / 8 (= 1)
whdr.addAll(fromInt16LE_(8)) // bits per sample (= 8)
whdr.addAll("data".bytes)
whdr.addAll(fromInt32LE_(dataLength)) // size of data section
// write header and data to file
File.create(filePath) { |file|
for (b in whdr) file.writeBytes(String.fromByte(b))
for (b in data) file.writeBytes(String.fromByte(b))
}
}
}