Skip to main content

[JAMDAC]

# =============================================================================
# JAMDAC (FRAMEWORK FILE) VERSION 2025-10-26
# =============================================================================
# THIS FILE DEFINES THE MMIO TYPES USED WITH THE IO::AUDIO_QUEUES ARRAY,
# WHICH CONTROLS THE JAMDAC SOUND SYSTEM.

# -----------------------------------------------------------------------------
# A SOUND PARAMETER THAT CAN BE CONTROLLED BY AN IO_ENVELOPE
CLASS IO_DYNAMIC # 5 BYTES
# 0..2 = INSTRUMENT ENVELOPES
# 3..4 = GLOBAL ENVELOPES
#
# +32 = ENABLE ENVELOPE, IF DISABLED THEN "HIGH" IS USED
# +64 = ENABLE PITCH_FACTOR CONTROL
# +128 = ENABLE MOD_FACTOR CONTROL
VAR CONTROL: BYTE

# THE VALUE WHEN L=0 IN THE ENVELOPE GRAPH
VAR LOW: PAIR

# THE VALUE WHEN L=255 IN THE ENVELOPE GRAPH
VAR HIGH: PAIR
END CLASS

# -----------------------------------------------------------------------------
CLASS IO_ENVELOPE # 20 BYTES
VAR SAMPLES_PER_T: PAIR

# 1 = SUSTAIN; WITHOUT THIS FLAG, SUSTAIN_INDEX IS IGNORED
# 2 = LOOPING
# 4 = STAIRSTEPS INSTEAD OF INTERPOLATION
VAR FLAGS: BYTE

# INDEX OF THE GRAPH POINT TO BE HELD UNTIL A "RELEASE INSTRUMENT" COMMAND
VAR SUSTAIN_INDEX: BYTE # [JAMDAC PLUS]

# EIGHT (L, T) PAIRS
# L: 0..255 --> LOW..HIGH OF IO_DYNAMIC LEVEL
# T: 0..255 --> 0..255*SAMPLES_PER_T TIME STEP SIZE
# IF A POINT HAS T=0, IT CREATES AN OPEN INTERVAL WITH A DISCONTINUITY.
# IF TWO CONSECUTIVE POINTS HAVE T=0, THEN THE SECOND POINT AND REMAINDER
# ARE DISCARDED. IF THE EIGHTH POINT HAS T>0, IT INTERPOLATES TO L=GRAPH[0].
INSET GRAPH: BYTE[SIZE 16]
END CLASS

# -----------------------------------------------------------------------------
CLASS IO_WAVE # SIZE 30
# 0=NONE, 1=TRIANGLE, 2=SAW, 3=PULSE, 4=NOISE
VAR OSCILLATOR_SHAPE: BYTE

# UNITS: HERTZ
INSET OSCILLATOR_HZ: IO_DYNAMIC

# UNITS: S6.10 FIXED POINT
INSET OSCILLATOR_LEVEL: IO_DYNAMIC

# UNITS: S6.10 FIXED POINT, RANGE 0.0 .. 1.0
# 0.0 PRODUCES CONSTANT OUTPUT OF -1.0
# 1.0 PRODUCES CONSTANT OUTPUT OF 1.0
INSET PULSE_WIDTH: IO_DYNAMIC

# 0 = NONE
# 1 = LOWPASS
# 2 = BANDPASS
# 3 = HIGHPASS
# 4 = NOTCH
# 5 = PEAK
VAR FILTER_KIND: BYTE

# UNITS: HERTZ INDICATING THE FILTER'S CUTOFF FREQUENCY
INSET FILTER_HZ: IO_DYNAMIC

# UNITS: S6.10 FIXED POINT, RANGE 0.0 .. 1.0
VAR FILTER_RESONANCE: PAIR

# UNITS: S6.10 FIXED POINT
INSET OUTPUT_LEVEL: IO_DYNAMIC

# 0=DRY, 1=CHANNEL EFFECT
VAR APPLY_EFFECT: BYTE
END CLASS

# -----------------------------------------------------------------------------
CLASS IO_WAVE_WITH_DIGITAR EXTENDS IO_WAVE # SIZE 43
# +1 = ENABLE DIGITAR
# +2 = ENABLE DIGITAR LOWPASS SMOOTHING
# +4 = ENABLE INPUT GATE
# NOTE: WAVE_B'S DIGITAR USES THE SAME BUFFER AS THE CHANNEL EFFECT, SO
# ENABLING WAVE_B'S DIGITAR WILL DISABLE THE CHANNEL EFFECT.
VAR DIGITAR_MODE: BYTE # [JAMDAC PLUS]

# 1.0 = SIMPLE STRING
# 0.5 = DRUMS
# 0.0 = PLUCKED BOTTLE
# UNITS: S6.10 FIXED POINT
VAR DIGITAR_BLEND: PAIR # [JAMDAC PLUS]

# DELAY LOOP LENGTH = 22,050 HZ / DIGITAR_HZ - 0.5
# UNITS: HERTZ
INSET DIGITAR_HZ: IO_DYNAMIC # [JAMDAC PLUS]

# NORMALLY THIS IS ALWAYS 1.0, BUT THE DIGITAR CAN BE USED
# FOR CONVENTIONAL DELAY LOOP EFFECTS
# UNITS: S6.10 FIXED POINT
INSET DIGITAR_FEEDBACK: IO_DYNAMIC # [JAMDAC PLUS]
END CLASS

# -----------------------------------------------------------------------------
CLASS IO_CHANNEL_EFFECT # SIZE 30
# UNITS: S6.10 FIXED POINT
INSET DISTORTION_GAIN: IO_DYNAMIC

# AMOUNT OF DELAY, MEASURED IN SAMPLES. VALUE MUST BE BETWEEN 1 AND 2205,
# OTHERWISE THE OUTPUT IS ZERO.
INSET DELAY_SAMPLES: IO_DYNAMIC

# UNITS: S6.10 FIXED POINT
INSET DELAY_FEEDBACK: IO_DYNAMIC

# UNITS: S6.10 FIXED POINT
INSET DRY_LEVEL: IO_DYNAMIC

# UNITS: S6.10 FIXED POINT
INSET PREDELAY_LEVEL: IO_DYNAMIC

# UNITS: S6.10 FIXED POINT
INSET POSTDELAY_LEVEL: IO_DYNAMIC
END CLASS

# -----------------------------------------------------------------------------
CLASS IO_INSTRUMENT # SIZE 222
INSET ENVELOPES: IO_ENVELOPE[INSET 3]

INSET WAVE_A: IO_WAVE_WITH_DIGITAR
INSET WAVE_B: IO_WAVE_WITH_DIGITAR
INSET WAVE_C: IO_WAVE

INSET CHANNEL_EFFECT: IO_CHANNEL_EFFECT

# UNITS: S6.10 FIXED POINT
INSET LEFT_LEVEL: IO_DYNAMIC

# UNITS: S6.10 FIXED POINT
INSET RIGHT_LEVEL: IO_DYNAMIC

# UNITS: S6.10 FIXED POINT
INSET REVERB_LEVEL: IO_DYNAMIC # [JAMDAC PLUS]

# 1=STEREO LEFT CHANNEL IS DELAYED
VAR APPLY_WIDENER: BYTE
END CLASS

# -----------------------------------------------------------------------------
CLASS IO_REVERB # SIZE 24
# UNITS: BUFFER ARRAY SIZE MEASURED IN SAMPLES
INSET STAGE_DELAY_SIZES: PAIR[SIZE 6] # [JAMDAC PLUS]

# UNITS: S6.10 FIXED POINT
INSET STAGE_FEEDBACKS: PAIR[SIZE 6] # [JAMDAC PLUS]
END CLASS

# -----------------------------------------------------------------------------
CLASS IO_AUDIO_EVENT # SIZE 5
# 0 = LOAD INSTRUMENT OPERAND = ADDRESS OF IO_INSTRUMENT
# OR NULL TO RESET
# 1 = TRIGGER INSTRUMENT OPERAND = MOD_FACTOR IN HIGH PAIR;
# PITCH_FACTOR IN LOW PAIR
# (VALUES ARE S6.10 FIXED POINT)
# * 2 = RELEASE INSTRUMENT
# * 3 = LOAD GLOBAL ENVELOPE #3 OPERAND = ADDRESS OF IO_ENVELOPE
# OR NULL TO RESET
# * 4 = LOAD GLOBAL ENVELOPE #4 OPERAND = ADDRESS OF IO_ENVELOPE
# OR NULL TO RESET
# * 5 = TRIGGER GLOBAL ENVELOPE OPERAND = #3 OR #4
# * 6 = RELEASE GLOBAL ENVELOPE OPERAND = #3 OR #4
# * 7 = LOAD GLOBAL REVERB OPERAND = ADDRESS OF IO_REVERB
# OR NULL TO RESET
#
# 8 = WAIT OPERAND = NUMBER OF ADDITIONAL SAMPLES
# 9 = SYNC OPERAND = SYNC GROUP (0..5) IN BYTE 3;
# CHANNEL COUNT (1..6) IN BYTE 4
# * 10 = RAMPDOWN 30 SAMPLES
#
# * THESE FEATURES REQUIRE JAMDAC PLUS
VAR KIND: BYTE

VAR OPERAND: INT
END CLASS

# -----------------------------------------------------------------------------
CLASS IO_AUDIO_QUEUE # SIZE 512
# ADDRESS OF WHERE THE NEXT EVENT WILL BE WRITTEN BY THE APP
VAR WRITE_ADDRESS: INT

# ADDRESS OF THE NEXT EVENT TO BE READ BY THE AUDIO SYSTEM
# QUEUE IS EMPTY WHEN: WRITE_ADDRESS = READ_ADDRESS
# QUEUE IS FULL WHEN: WRAP(WRITE_ADDRESS + SIZEOF(EVENT)) = READ_ADDRESS
VAR READ_ADDRESS: INT

# TO PURGE THE QUEUE, ASSIGN WRITE_ADDRESS -> PURGE_READ_ADDRESS.
# WHEN THE JAMDAC SEES THAT PURGE_READ_ADDRESS IS NONZERO, IT WILL:
# 1. IF A "WAIT" OR "SYNC" EVENT IS ACTIVE, IT WILL BE ENDED EARLY
# 2. ASSIGN PURGE_READ_ADDRESS -> READ_ADDRESS, DISCARDING ALL EVENTS
# 3. ASSIGN 0 -> PURGE_READ_ADDRESS
VAR PURGE_READ_ADDRESS: INT

INSET EVENTS: IO_AUDIO_EVENT[INSET 100]
END CLASS