npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

et209

v1.0.1

Published

An emulator for the (fictional) ET-209 digital synthesizer chip, in JavaScript for some reason

Downloads

6

Readme

This is an emulator for the (fictional) ET-209 digital synthesizer chip, which was used in the (fictional) Eiling Technologies Artificial Reality System, which was an overengineered, overpriced, overheating 8-bit game console (fictionally) released in the late 80's.

API

All examples given here assume you either embedded this directly into a webpage with <script src="et209.js"> or did something like let ET209 = require('et209'); in your own module, depending on whether you're using a module system or not. (Note that the package name is et209 but the canonical identifier is ET209.)

This section of the ars-emu README contains a lot of vital information about the ET-209.

All ranges in this document are inclusive. "0 through 3" includes the values 0, 1, 2, and 3.

Voice numbers are 0 through 6. The constant ET209.NUM_VOICES, with the value 7, is included for convenience.

The ET-209 does not have an inherent sample rate, but in the ARS it is clocked at precisely 135000000/2816 Hz (≈47940Hz). This value is provided as ET209.SAMPLE_RATE for convenience. Assuming you calculate rate values correctly, you are free to use any value you wish as your sample rate.

Initialization

apu = new ET209();

Creates a new instance of an ET-209 chip, which has just freshly powered on and had a nice, clean reset.

Registers

apu.write_voice_rate(voice, rate);

Sets the raw rate value for the given voice. rate should be in the range 0 to 65535. Since this is the raw rate value, the upper two bits are the pitch slide bits, provided as constants:

  • ET209.RATE_INSTANT_CHANGE: Rate changes take effect instantly. (This is the default, and is defined only for readability.)
  • ET209.RATE_FAST_SLIDE: Rate changes by 1 unit per 4 samples.
  • ET209.RATE_MEDIUM_SLIDE: Rate changes by 1 unit per 8 samples.
  • ET209.RATE_SLOW_SLIDE: Rate changes by 1 unit per 16 samples.
apu.write_voice_waveform(voice, waveform);

Sets the waveform value for the given voice. waveform is in the range 0 to 255. The following constants may be used to build up a meaningful waveform value:

  • ET209.WAVEFORM_INVERT_EIGHTH_FLAG: Invert the first 1/8 of the wave.
  • ET209.WAVEFORM_INVERT_QUARTER_FLAG: Invert the first 1/4 of the wave.
  • ET209.WAVEFORM_INVERT_HALF_FLAG: Invert the first 1/2 of the wave.
  • ET209.WAVEFORM_INVERT_ALL_FLAG: Invert the whole wave.
  • ET209.WAVEFORM_TOGGLE_INVERT_ON_CARRY_FLAG: Toggle ET209.WAVEFORM_INVERT_ALL_FLAG internally after each wavelength.
  • ET209.WAVEFORM_OUTPUT_ACCUMULATOR_FLAG: If set, the high bits of the accumulator are outputted (and possibly inverted), forming a sawtooth wave. (Combine with ET209.WAVEFORM_TOGGLE_INVERT_ON_CARRY_FLAG and you have a triangle wave instead of a sawtooth wave.)
  • ET209.WAVEFORM_PAN_CENTER: Play back at 50% volume through both stereo channels. This results in the same perceived volume as a left or right pan. (This is the default, and is defined only for clarity.)
  • ET209.WAVEFORM_PAN_LEFT: Play back entirely in the left channel.
  • ET209.WAVEFORM_PAN_RIGHT: Play back entirely in the right channel.
  • ET209.WAVEFORM_PAN_FULL: Play back at full volume through both channels. This results in twice the perceived volume as a left, right, or center pan. It is mainly used for low frequency effects, particularly low frequency triangle waves, which have a relatively low perceived volume.
apu.write_voice_volume(voice, volume);

Sets the volume value for the given voice. volume should be in the range 0 to 64 (ET209.VOLUME_MAX), optionally bitwise OR'd with the following constant:

  • ET209.VOLUME_RESET_FLAG: If set, the accumulator will reset in the next sample, i.e. the wave will "start over". You usually want to set this for each "note on".
apu.write_noise_period(period);

Sets the noise period to the given value. period is in the range 0 through 255. Higher value = lower pitched noise.

apu.write_noise_waveform(waveform);

Sets the noise waveform to the given value. waveform is in the range 0 through 255. The low 7 bits are "hold bits"; the more of them are enabled, the lower the perceived noise frequency. The high bit (ET209.PERIODIC_NOISE) changes the noise function from white noise to periodic noise.

apu.write_noise_volume(volume);

Sets the noise volume to the given value. volume should be in the range 0 to 64 (ET209.VOLUME_MAX), optionally bitwise OR'd with the following constant:

  • ET209.VOLUME_RESET_FLAG: If set, the LFSR will reset during the next sample, i.e. the noise will "start over". You usually want to set this for each "note on".

Output

There are three high-level functions for generating output samples; one for mono, one for stereo, and one for headphones. (Switching between them willy-nilly will produce a "filter glitch". For best results, stick to one when possible.)

All three of these functions produce floating-point output in the range -1 to 1.

let output = [];
apu.generate_mono_array(output, length);
// OR
let output = new Float32Array(length);
apu.generate_mono_array(output, length);

Clocks the emulated ET-209 chip enough times to produce length output samples, and writes (filtered) monaural samples to the output array.

let left_output = [];
let right_output = [];
apu.generate_stereo_arrays(left_output, right_output, length);
// OR
let left_output = new Float32Array(length);
let right_output = new Float32Array(length);
apu.generate_stereo_arrays(left_output, right_output, length);

Clocks the emulated ET-209 chip enough times to produce length output samples, and writes (filtered) stereo samples to the left_output and right_output arrays. This closely mimics the usual operating mode of a "real" ET-209.

let left_output = [];
let right_output = [];
apu.generate_stereo_arrays(left_output, right_output, length);
// OR
let left_output = new Float32Array(length);
let right_output = new Float32Array(length);
apu.generate_stereo_arrays(left_output, right_output, length);

Clocks the emulated ET-209 chip enough times to produce length output samples, and writes (filtered) stereo samples to the left_output and right_output arrays. This version uses a simplistic approximation of the HRTF to create three virtual speakers for headphone users.

AudioBuffer output

apu.generate_buffer(output_buffer, headphones);

Calls generate_mono_array, generate_stereo_arrays, or generate_headphone_arrays to fill output_buffer (an AudioBuffer) with output samples. Chooses between them based on the channel count of the AudioBuffer and the boolean value headphones.

Raw Output

You probably want to use the above high-level output functions instead.

let frame = [];
apu.generate_frame(frame);

Clocks the emulated ET-209 chip 128 times, enough to produce a single output sample, then returns the raw, unfiltered, digital output values.

The ET-209's DACs accept input in the range 0 through 511. (It will never actually exceed 504.) This function produces output such that, if you follow the below recommendations, you will arrive at values in the range -256 to 248. This is actually the correct offset, even though it seems to be biased toward the negative... let's just say it's complicated.

The real ET-209 produces two digital outputs, one for each stereo channel. This function returns four, in the following order: center, right, left, and "full".

To produce authentic stereo output:

let leftSample = (frame[0] >> 1) + frame[2] + frame[3];
let rightSample = (frame[0] >> 1) + frame[1] + frame[3];

To produce mono output:

let sample = (frame[0] + frame[1] + frame[2]) * 0.5 + frame[3];

The four pan values are separated. Among other things, this lets you produce 3.1 surround output:

let leftSample = frame[2] + frame[3] * (1/3);
let rightSample = frame[1] + frame[3] * (1/3);
let centerSample = frame[0] + frame[3] * (1/3);
let lfeSample = frame[3];
// (LFE output should actually be low-pass filtered with a cutoff at ≈120Hz)

Other possibilities exist, including headphone-friendly stereo.

For compatibility with (probably extinct) old scripts that assumed mono output, there is a generate_sample function that returns a mono sample directly.

Miscellaneous

apu.reset();

Sends a reset signal to the emulated chip, and zeroes all of its registers. This does not reset the filter status. The physical ET-209's filters are analog components, not affected by the (digital) reset input.

output = ET209.eval_waveform(accum, waveform);

Evaluates a voice waveform with the given accumulator value. accum is the value of the accumulator, in the range 0 to 65535. The returned value is the raw output of the corresponding functional unit of the ET-209, in the range 0 to 63.

This function is provided in case you want to provide waveform previews or the like.