laser500-wav
Advanced tools
Comparing version 1.1.0 to 1.1.1
@@ -17,14 +17,3 @@ #!/usr/bin/env node | ||
if (options_1.options.input === undefined || options_1.options.output === undefined || (options_1.options.l310 === undefined && options_1.options.l500 === undefined)) { | ||
console.log("Usage: laser500wav -i file -o file [options]"); | ||
console.log(" -i or --input file the VZ file to be converted in WAV"); | ||
console.log(" -o or --output file the file name to be created"); | ||
console.log(" --l500 targets Laser 500/700"); | ||
console.log(" --l310 targets Laser 110/210/310 VZ 200/300"); | ||
console.log(" -s or --samplerate rate the samplerate of the WAV file (96000 default)"); | ||
console.log(" -v or --volume number volume between 0 and 1 (1.0 default)"); | ||
console.log(" --stereoboost boost volume for stereo cables by inverting the RIGHT channel (default off)"); | ||
console.log(" --invert inverts the polarity of the audio (default off)"); | ||
console.log(" --header number of header bytes (128 default as in ROM loader)"); | ||
console.log(" --pulsems n ROM loader pulse width in microseconds (277 default)"); | ||
console.log(" -x or --turbo speed 0=normal ROM loader WAV, 1-4 turbo tape (4 fastest)"); | ||
(0, options_1.printHelp)(); | ||
process.exit(0); | ||
@@ -31,0 +20,0 @@ } |
@@ -13,3 +13,5 @@ export interface CommandLineOptions { | ||
l310: boolean; | ||
address: string; | ||
} | ||
export declare const options: CommandLineOptions; | ||
export declare function printHelp(): void; |
@@ -6,3 +6,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.options = void 0; | ||
exports.printHelp = exports.options = void 0; | ||
const command_line_args_1 = __importDefault(require("command-line-args")); | ||
@@ -20,3 +20,4 @@ exports.options = parseOptions([ | ||
{ name: 'l500', type: Boolean }, | ||
{ name: 'l310', type: Boolean } | ||
{ name: 'l310', type: Boolean }, | ||
{ name: 'address', type: String } | ||
]); | ||
@@ -35,1 +36,17 @@ function parseOptions(optionDefinitions) { | ||
} | ||
function printHelp() { | ||
console.log("Usage: laser500wav -i file -o file [options]"); | ||
console.log(" -i or --input file the VZ file to be converted in WAV"); | ||
console.log(" -o or --output file the file name to be created"); | ||
console.log(" --l500 targets Laser 500/700"); | ||
console.log(" --l310 targets Laser 110/210/310 VZ 200/300"); | ||
console.log(" -s or --samplerate rate the samplerate of the WAV file (96000 default)"); | ||
console.log(" -v or --volume number volume between 0 and 1 (1.0 default)"); | ||
console.log(" --stereoboost boost volume for stereo cables by inverting the RIGHT channel (default off)"); | ||
console.log(" --invert inverts the polarity of the audio (default off)"); | ||
console.log(" --header number of header bytes (128 default as in ROM loader)"); | ||
console.log(" --pulsems n ROM loader pulse width in microseconds (277 default)"); | ||
console.log(" -x or --turbo speed 0=normal ROM loader WAV, 1-4 turbo tape (4 fastest)"); | ||
console.log(" --addr hexaddress puts the turbo loading routine at specific address"); | ||
} | ||
exports.printHelp = printHelp; |
@@ -21,3 +21,4 @@ /// <reference types="node" /> | ||
TURBO_INVERT: boolean; | ||
TURBO_ADDRESS: number | undefined; | ||
} | ||
export declare function VZ_to_WAV(VZ: VZInfo, options: TypedOptions): ArrayBuffer; |
@@ -29,4 +29,5 @@ "use strict"; | ||
function getTurboSamples(tape, turbo) { | ||
var _a; | ||
const { startAddress, program } = tape; | ||
const turbo_address = startAddress + program.length; | ||
const turbo_address = (_a = turbo.TURBO_ADDRESS) !== null && _a !== void 0 ? _a : startAddress + program.length; | ||
const loader_program = (0, turbo_loader_1.getTurboLoader)(tape.laser500, turbo.THRESHOLD, turbo_address, tape.fileType); | ||
@@ -59,3 +60,3 @@ tape.fileType = vz_1.VZ_BINARY; | ||
const { tapeName, fileType, startAddress, program, headerLen, tailLen, laser500 } = tape; | ||
// header | ||
// header | ||
for (let t = 0; t < headerLen; t++) | ||
@@ -72,4 +73,4 @@ header_bytes.push(0x80); | ||
if (laser500) { | ||
// laser 500 has additional bytes and a marker to allow print of file name | ||
// laser 310 elongates the last pulse of the "0" bit to allow print of file name | ||
// laser 500 has additional bytes and a marker to allow print of file name | ||
// laser 310 elongates the last pulse of the "0" bit to allow print of file name | ||
for (let t = 0; t < 5; t++) | ||
@@ -79,3 +80,3 @@ header_bytes.push(0x80); // additional header to allow print of file name | ||
header_bytes.push(0x80); | ||
header_bytes.push(0xff); // end of header | ||
header_bytes.push(0xff); // end of header | ||
} | ||
@@ -92,3 +93,3 @@ // start address | ||
body_bytes.push(program[t]); | ||
// checksum | ||
// checksum | ||
const checksum = (0, checksum_1.calculate_checksum)(program, startAddress, endAddress); | ||
@@ -175,3 +176,3 @@ body_bytes.push((0, bytes_1.lo)(checksum)); | ||
const HEADER_LEN = options.header; | ||
const TAIL_LEN = 4; // 128; | ||
const TAIL_LEN = 4; // 128; | ||
const pulsems = options.pulsems / 1000000; // for a total of 277 microseconds | ||
@@ -184,3 +185,4 @@ const PULSE_SHORT = pulsems * SAMPLE_RATE; | ||
TURBO_HALFPULSE_SIZE: turboparams.TURBO_HALFPULSE_SIZE, | ||
TURBO_INVERT: turboparams.TURBO_INVERT | ||
TURBO_INVERT: turboparams.TURBO_INVERT, | ||
TURBO_ADDRESS: options.address !== undefined ? parseInt(options.address, 16) : undefined | ||
}; | ||
@@ -187,0 +189,0 @@ const fileType = VZ.type; |
@@ -61,6 +61,4 @@ "use strict"; | ||
bytes.push(0x00); | ||
console.log("TURBO TAPE INFO:"); | ||
console.log(`address: ${startAddress.toString(16)}`); | ||
console.log(`length: ${length.toString(16)}`); | ||
console.log(`checksum: ${checksum.toString(16)}`); | ||
console.log(`program: ${(0, bytes_1.hex)(startAddress, 4)}-${(0, bytes_1.hex)(startAddress + length - 1, 4)} (${length} bytes)`); | ||
console.log(`checksum: ${(0, bytes_1.hex)(checksum, 4)}`); | ||
return bytes; | ||
@@ -67,0 +65,0 @@ } |
@@ -14,2 +14,3 @@ "use strict"; | ||
const relocated = relocate(loader_program, relocate_address, asm_info); | ||
console.log(`turbo loader routine at ${(0, bytes_1.hex)(relocate_address, 4)}-${(0, bytes_1.hex)(relocate_address + loader_program.length - 1, 4)}`); | ||
// for debug purposes | ||
@@ -16,0 +17,0 @@ { |
{ | ||
"name": "laser500-wav", | ||
"version": "1.1.0", | ||
"version": "1.1.1", | ||
"description": "Laser310/500 program to WAV (tape) converter", | ||
@@ -5,0 +5,0 @@ "bin": { |
@@ -10,3 +10,3 @@ #!/usr/bin/env node | ||
import { options } from './options'; | ||
import { options, printHelp } from './options'; | ||
import { VZ_BINARY, unpackvz } from "./vz"; | ||
@@ -17,14 +17,3 @@ import { VZ_to_WAV } from "./tape_creator"; | ||
if(options.input === undefined || options.output === undefined || (options.l310===undefined && options.l500===undefined)) { | ||
console.log("Usage: laser500wav -i file -o file [options]"); | ||
console.log(" -i or --input file the VZ file to be converted in WAV"); | ||
console.log(" -o or --output file the file name to be created"); | ||
console.log(" --l500 targets Laser 500/700"); | ||
console.log(" --l310 targets Laser 110/210/310 VZ 200/300"); | ||
console.log(" -s or --samplerate rate the samplerate of the WAV file (96000 default)"); | ||
console.log(" -v or --volume number volume between 0 and 1 (1.0 default)"); | ||
console.log(" --stereoboost boost volume for stereo cables by inverting the RIGHT channel (default off)"); | ||
console.log(" --invert inverts the polarity of the audio (default off)"); | ||
console.log(" --header number of header bytes (128 default as in ROM loader)"); | ||
console.log(" --pulsems n ROM loader pulse width in microseconds (277 default)"); | ||
console.log(" -x or --turbo speed 0=normal ROM loader WAV, 1-4 turbo tape (4 fastest)"); | ||
printHelp(); | ||
process.exit(0); | ||
@@ -31,0 +20,0 @@ } |
@@ -15,2 +15,3 @@ import commandLineArgs from 'command-line-args'; | ||
l310: boolean; | ||
address: string; | ||
} | ||
@@ -29,3 +30,4 @@ | ||
{ name: 'l500', type: Boolean }, | ||
{ name: 'l310', type: Boolean } | ||
{ name: 'l310', type: Boolean }, | ||
{ name: 'address', type: String } | ||
]) as CommandLineOptions; | ||
@@ -42,1 +44,17 @@ | ||
} | ||
export function printHelp() { | ||
console.log("Usage: laser500wav -i file -o file [options]"); | ||
console.log(" -i or --input file the VZ file to be converted in WAV"); | ||
console.log(" -o or --output file the file name to be created"); | ||
console.log(" --l500 targets Laser 500/700"); | ||
console.log(" --l310 targets Laser 110/210/310 VZ 200/300"); | ||
console.log(" -s or --samplerate rate the samplerate of the WAV file (96000 default)"); | ||
console.log(" -v or --volume number volume between 0 and 1 (1.0 default)"); | ||
console.log(" --stereoboost boost volume for stereo cables by inverting the RIGHT channel (default off)"); | ||
console.log(" --invert inverts the polarity of the audio (default off)"); | ||
console.log(" --header number of header bytes (128 default as in ROM loader)"); | ||
console.log(" --pulsems n ROM loader pulse width in microseconds (277 default)"); | ||
console.log(" -x or --turbo speed 0=normal ROM loader WAV, 1-4 turbo tape (4 fastest)"); | ||
console.log(" --addr hexaddress puts the turbo loading routine at specific address"); | ||
} |
@@ -13,3 +13,3 @@ import { hex, hi, lo } from "./bytes"; | ||
tapeName: string; | ||
fileType: VZFILETYPE; | ||
fileType: VZFILETYPE; | ||
startAddress: number; | ||
@@ -29,3 +29,4 @@ program: Buffer; | ||
TURBO_HALFPULSE_SIZE: number; | ||
TURBO_INVERT: boolean; | ||
TURBO_INVERT: boolean; | ||
TURBO_ADDRESS: number|undefined; | ||
} | ||
@@ -35,3 +36,3 @@ | ||
const { header_bytes, body_bytes } = tapeStructure(tape); | ||
// header | ||
@@ -41,6 +42,6 @@ const header_bits = bytesToBits(header_bytes); | ||
const header_samples = pulsesToSamples(header_pulses, tape); | ||
// gap between header and body in Laser310 | ||
let gap: number[] = tape.laser500 ? [] : getGapSamples(tape); | ||
// body | ||
@@ -50,44 +51,44 @@ const body_bits = bytesToBits(body_bytes); | ||
const body_samples = pulsesToSamples(body_pulses, tape); | ||
const samples = header_samples.concat(gap).concat(body_samples); | ||
return samples; | ||
} | ||
function getTurboSamples(tape: Tape, turbo: TurboTape) { | ||
const { startAddress, program } = tape; | ||
const turbo_address = startAddress + program.length; | ||
const loader_program = getTurboLoader(tape.laser500, turbo.THRESHOLD, turbo_address, tape.fileType); | ||
const turbo_address = turbo.TURBO_ADDRESS ?? startAddress + program.length; | ||
const loader_program = getTurboLoader(tape.laser500, turbo.THRESHOLD, turbo_address, tape.fileType); | ||
tape.fileType = VZ_BINARY; | ||
tape.startAddress = turbo_address; | ||
tape.program = loader_program; | ||
const { header_bytes, body_bytes } = tapeStructure(tape); | ||
const header_bits = bytesToBits(header_bytes); | ||
const header_pulses = bitsToPulses(header_bits); | ||
const header_samples = pulsesToSamples(header_pulses, tape); | ||
// gap between header and body in Laser310 | ||
let gap: number[] = tape.laser500 ? [] : getGapSamples(tape); | ||
// body | ||
const body_bits = bytesToBits(body_bytes); | ||
const body_pulses = bitsToPulses(body_bits); | ||
const body_samples = pulsesToSamples(body_pulses, tape); | ||
const body_samples = pulsesToSamples(body_pulses, tape); | ||
const turbo_bytes = getTurboBytes(startAddress, program); | ||
const turbo_bits = bytesToBits(turbo_bytes); | ||
const turbo_samples = TT_bitsToSamples(turbo_bits, tape, turbo); | ||
const samples = header_samples.concat(gap).concat(body_samples).concat(turbo_samples); | ||
return samples; | ||
} | ||
function invertSamples(samples: number[]) | ||
@@ -97,32 +98,32 @@ { | ||
} | ||
function tapeStructure(tape: Tape) { | ||
function tapeStructure(tape: Tape) { | ||
const header_bytes = []; | ||
const body_bytes = []; | ||
const { tapeName, fileType, startAddress, program, headerLen, tailLen, laser500 } = tape; | ||
// header | ||
// header | ||
for(let t=0; t<headerLen; t++) header_bytes.push(0x80); | ||
for(let t=0; t<5; t++) header_bytes.push(0xfe); | ||
// file type | ||
header_bytes.push(fileType); | ||
header_bytes.push(fileType); | ||
// file name | ||
for(let t=0; t<tapeName.length; t++) header_bytes.push(tapeName.charCodeAt(t)); | ||
header_bytes.push(0x00); | ||
header_bytes.push(0x00); | ||
if(laser500) { | ||
// laser 500 has additional bytes and a marker to allow print of file name | ||
// laser 310 elongates the last pulse of the "0" bit to allow print of file name | ||
// laser 500 has additional bytes and a marker to allow print of file name | ||
// laser 310 elongates the last pulse of the "0" bit to allow print of file name | ||
for(let t=0; t<5; t++) header_bytes.push(0x80); // additional header to allow print of file name | ||
for(let t=0; t<10; t++) header_bytes.push(0x80); | ||
header_bytes.push(0xff); // end of header | ||
for(let t=0; t<10; t++) header_bytes.push(0x80); | ||
header_bytes.push(0xff); // end of header | ||
} | ||
// start address | ||
body_bytes.push(lo(startAddress)); | ||
body_bytes.push(hi(startAddress)); | ||
// end address | ||
@@ -132,17 +133,17 @@ const endAddress = startAddress + program.length; | ||
body_bytes.push(hi(endAddress)); | ||
// program | ||
for(let t=0; t<program.length; t++) body_bytes.push(program[t]); | ||
// checksum | ||
// checksum | ||
const checksum = calculate_checksum(program, startAddress, endAddress); | ||
body_bytes.push(lo(checksum)); | ||
body_bytes.push(hi(checksum)); | ||
// terminator | ||
for(let t=0; t<tailLen; t++) body_bytes.push(0x00); | ||
for(let t=0; t<tailLen; t++) body_bytes.push(0x00); | ||
return { header_bytes, body_bytes }; | ||
} | ||
function bytesToBits(bytes: number[]): number[] { | ||
@@ -163,3 +164,3 @@ const bits = []; | ||
} | ||
function bitsToPulses(bits: number[]): Pulse[] { | ||
@@ -174,11 +175,11 @@ const pulses: Pulse[] = []; | ||
} | ||
function pulsesToSamples(tapeBits: Pulse[], tape: Tape): number[] { | ||
const samples = []; | ||
let ptr = 0; | ||
const { SAMPLE_RATE, VOLUME, PULSE_LONG, PULSE_SHORT } = tape; | ||
for(let t=0; t<tapeBits.length; t++) { | ||
if(tapeBits[t]==="S") { | ||
if(tapeBits[t]==="S") { | ||
for(;ptr<PULSE_SHORT; ptr++) samples.push(VOLUME); ptr -= PULSE_SHORT; | ||
@@ -190,21 +191,21 @@ for(;ptr<PULSE_SHORT; ptr++) samples.push(-VOLUME); ptr -= PULSE_SHORT; | ||
for(;ptr<PULSE_LONG; ptr++) samples.push(-VOLUME); ptr -= PULSE_LONG; | ||
} | ||
} | ||
} | ||
return samples; | ||
} | ||
function getGapSamples(tape: Tape): number[] { | ||
const samples = []; | ||
let ptr = 0; | ||
const { VOLUME, PULSE_SHORT } = tape; | ||
for(let t=0; t<11; t++) { | ||
for(let t=0; t<11; t++) { | ||
for(;ptr<PULSE_SHORT; ptr++) samples.push(-VOLUME); ptr -= PULSE_SHORT; | ||
} | ||
return samples; | ||
} | ||
export function VZ_to_WAV(VZ: VZInfo, options: TypedOptions) { | ||
@@ -215,24 +216,25 @@ const laser500 = options.l500 && !options.l310; | ||
// on the real machine. One the emulator the minimum is 18000 Hz | ||
const SAMPLE_RATE = options.samplerate; | ||
const VOLUME = options.volume; | ||
const HEADER_LEN = options.header; | ||
const TAIL_LEN = 4; // 128; | ||
const HEADER_LEN = options.header; | ||
const TAIL_LEN = 4; // 128; | ||
const pulsems = options.pulsems/1000000; // for a total of 277 microseconds | ||
const PULSE_SHORT = pulsems * SAMPLE_RATE; | ||
const PULSE_SHORT = pulsems * SAMPLE_RATE; | ||
const PULSE_LONG = PULSE_SHORT * 2; | ||
const turboparams = decodeBitSize(options.turbo, SAMPLE_RATE, laser500); | ||
const turbo: TurboTape = { | ||
THRESHOLD: turboparams.THRESHOLD, | ||
TURBO_HALFPULSE_SIZE: turboparams.TURBO_HALFPULSE_SIZE, | ||
TURBO_INVERT: turboparams.TURBO_INVERT | ||
}; | ||
const turbo: TurboTape = { | ||
THRESHOLD: turboparams.THRESHOLD, | ||
TURBO_HALFPULSE_SIZE: turboparams.TURBO_HALFPULSE_SIZE, | ||
TURBO_INVERT: turboparams.TURBO_INVERT, | ||
TURBO_ADDRESS: options.address !== undefined ? parseInt(options.address,16) : undefined | ||
}; | ||
const fileType = VZ.type; | ||
const tape: Tape = { | ||
tapeName: VZ.filename, | ||
fileType, | ||
fileType, | ||
startAddress: VZ.start, | ||
@@ -248,8 +250,8 @@ program: Buffer.from(VZ.data), | ||
}; | ||
console.log(`target is ${tape.laser500 ? 'Laser 500' : 'Laser 310'} `); | ||
console.log(`target is ${tape.laser500 ? 'Laser 500' : 'Laser 310'} `); | ||
console.log(`SAVING ${fileType === VZ_BASIC ? "T" : "B"}: '${VZ.filename}' from $${hex(VZ.start,4)}, ${VZ.data.length} bytes`); | ||
let samples: number[]; | ||
// normal tape | ||
@@ -259,14 +261,14 @@ if(options.turbo === undefined) { | ||
} | ||
else { | ||
else { | ||
samples = getTurboSamples(tape, turbo); | ||
} | ||
// invert audio samples if --invert option was given | ||
if(options.invert) samples = invertSamples(samples); | ||
// fix_cassette_port(samples, SAMPLE_RATE); | ||
const f_samples = new Float32Array(samples); | ||
const f_samples_inv = new Float32Array(invertSamples(samples)); | ||
const wavData = { | ||
@@ -276,8 +278,7 @@ sampleRate: SAMPLE_RATE, | ||
}; | ||
const wavoptions: WavEncoder.Options = { bitDepth: 16, float: false, symmetric: false }; | ||
const buffer = WavEncoder.encode.sync(wavData, wavoptions); | ||
return buffer; | ||
} | ||
@@ -6,3 +6,3 @@ // ************************************************************************ | ||
import { calculate_checksum } from "./checksum"; | ||
import { hi, lo } from "./bytes"; | ||
import { hex, hi, lo } from "./bytes"; | ||
import { Tape, TurboTape } from "./tape_creator"; | ||
@@ -76,8 +76,6 @@ | ||
for(let t=0;t<64;t++) bytes.push(0x00); | ||
console.log(`program: ${hex(startAddress,4)}-${hex(startAddress+length-1,4)} (${length} bytes)`); | ||
console.log(`checksum: ${hex(checksum,4)}`); | ||
console.log("TURBO TAPE INFO:"); | ||
console.log(`address: ${startAddress.toString(16)}`); | ||
console.log(`length: ${length.toString(16)}`); | ||
console.log(`checksum: ${checksum.toString(16)}`); | ||
return bytes; | ||
@@ -84,0 +82,0 @@ } |
import { hex } from "./bytes"; | ||
import { turbo_L310_asm_info } from "./turbo_L310_asm_info"; | ||
import { turbo_L500_asm_info } from "./turbo_L500_asm_info"; | ||
import { VZ_BINARY } from "./vz"; | ||
@@ -16,2 +17,4 @@ type AsmInfo = typeof turbo_L310_asm_info | typeof turbo_L500_asm_info; | ||
console.log(`turbo loader routine at ${hex(relocate_address,4)}-${hex(relocate_address+loader_program.length-1,4)}`); | ||
// for debug purposes | ||
@@ -18,0 +21,0 @@ { |
AI-detected possible typosquat
Supply chain riskAI has identified this package as a potential typosquat of a more popular package. This suggests that the package may be intentionally mimicking another package's name, description, or other metadata.
Found 1 instance in 1 package
106358
2889
0