diff --git a/SANDBOX.PO b/SANDBOX.PO index e81dcd9..25b2a17 100755 Binary files a/SANDBOX.PO and b/SANDBOX.PO differ diff --git a/src/samplesrc/a2pwm/._demo.po b/src/samplesrc/a2pwm/._demo.po new file mode 100755 index 0000000..c29b0e3 Binary files /dev/null and b/src/samplesrc/a2pwm/._demo.po differ diff --git a/src/samplesrc/a2pwm/._lfo.po b/src/samplesrc/a2pwm/._lfo.po new file mode 100755 index 0000000..d5a959f Binary files /dev/null and b/src/samplesrc/a2pwm/._lfo.po differ diff --git a/src/samplesrc/a2pwm/hilopwm.pla b/src/samplesrc/a2pwm/hilopwm.pla index 7d91150..c4e937c 100755 --- a/src/samplesrc/a2pwm/hilopwm.pla +++ b/src/samplesrc/a2pwm/hilopwm.pla @@ -1,8 +1,30 @@ const inbuff = $200 const freemem = $0002 +const iobuffer = 0x1800 +const NMACROS = 7 const FALSE = 0 const TRUE = !FALSE // +// Macro sequence structure +// +struc t_macro + byte absStart + byte durAtk + byte durDcy + byte durSus + byte durRel + word rateAtk + word rateDcy + word rateRel + byte idxOctave + byte perLFO + byte idxLFO + byte[256] sequence +end +word macros // Pointer to macros +byte record[t_macro] // Recording buffer +word recording = FALSE // Recording key/flag +// // System variables. // word heap @@ -15,6 +37,14 @@ byte scale[] = 166, 156, 148, 139, 132, 124, 117, 111, 104, 99, 93, 88, 83, 78 // byte keytone[] = 'A','S','E','D','R','F','G','Y','H','U','J','I','K','L' // +// Macro sequence keys +// +byte keymacro[] = 'Z', 'X', 'C', 'V', 'B', 'N', 'M' +// +// Macro record keys +// +byte keyrecord[] = $1A, $18, $03, $16, $02, $0E, $0D +// // Which octave are we in // byte octave = 1 @@ -37,10 +67,53 @@ word atkRate = $07FF word dcyRate = $0000 word relRate = $00FF // +// Patch filename +// +byte patch = "PATCH" +byte modPatch = FALSE +// // Import utility routines // include "util.pla" // +// Load/Save PATCH +// +def loadPatch + byte refnum + + refnum = open(@patch, iobuffer) + if refnum + read(refnum, macros, t_macro * NMACROS) // Macros + read(refnum, @octave, @patch - @octave) // Initial values + close(refnum) + fin +end +def savePatch + byte refnum + + destroy(@patch) + create(@patch, $C3, $06, $00) // full access, BIN file + refnum = open(@patch, iobuffer) + if refnum + write(refnum, macros, t_macro * NMACROS) // Macros + write(refnum, @octave, @patch - @octave) // Initial values + close(refnum) + modPatch = FALSE + fin +end +// +// Query routines +// +def query(str) + byte c + + inverse + clearview + putsxy(20 - ^str / 2, 2, str) + c = toupper(getc) + return c == 'Y' +end +// // Display LFO bar // def showLFO @@ -48,18 +121,21 @@ def showLFO LFObar = (LFO+7)/8 grcolor(WHITE) - rect(34, 39, 6, 39, FALSE) + rect(33, 39, 6, 39, FALSE) if LFObar < 32 grcolor(ORANGE) - rect(35, 38, 7, 38-LFObar, TRUE) + rect(34, 38, 7, 38-LFObar, TRUE) fin if LFObar grcolor(DRKBLU) - rect(35, 38, 39-LFObar, 38, TRUE) + rect(34, 38, 39-LFObar, 38, TRUE) fin - putsxy(36, 0, " ") - gotoxy(36, 0) - puti(LFO) + // + //Show actual value + // + putsxy(35, 0, " ") + gotoxy(35, 0) + return puti(LFO) end // // Display LFO waveform @@ -87,7 +163,7 @@ def showWaveform // // Restore envelope // - envelope(atkLen, dcyLen, susLen, relLen, atkRate, dcyRate, relRate) + return envelope(atkLen, dcyLen, susLen, relLen, atkRate, dcyRate, relRate) end // // Display duration @@ -111,6 +187,12 @@ def showDuration fin grcolor(AQUA) rect(left, right, 0, 5, TRUE) + // + // Show actual value + // + putsxy(5, 3, " ") + gotoxy(5, 3) + return puti(duration) end // // Display octave @@ -120,7 +202,35 @@ def showOctave putsxy(0, 1, "----------------------------------------") normal putsxy(octave*10, 1, "----------") + return inverse +end +def showMainPanel inverse + clearview + showDuration + showWaveform + showLFO + putsxy(5, 0, "OSCILLATION OVERTHRUSTER 1.0") + normal + putsxy(1, 0, "1-8") + gotoxy(34, 0); putc('<') + gotoxy(38, 0); putc('>') + gotoxy(3, 3); putc('-') + gotoxy(8, 3); putc('+') + inverse + showOctave + normal + putsxy(0, 2, "<-") + putsxy(38, 2, "->") + inverse + putsxy(11, 3, "A S D F G H J K L") + normal + gotoxy(14, 2); putc('E') + gotoxy(16, 2); putc('R') + gotoxy(20, 2); putc('Y') + gotoxy(22, 2); putc('U') + gotoxy(24, 2); putc('I') + return inverse end // // Recalc envelope parameters @@ -133,123 +243,315 @@ def recalcEnv relRate = $0FFF/relLen end // +// Rest +// +def restnote + byte d + + for d = duration downto 1 + call($FCA8, $6A, 0, 0, 0) + next +end +// +// playback a sequence +// +def playback(seq) + word macro + byte seq, key, i, showUpdate + + macro = macros + t_macro * seq + // + // Start off with initial conditions + // + showUpdate = 0 + if macro->absStart + if macro->idxOctave <> octave + octave = macro->idxOctave + showUpdate = showUpdate | 1 + fin + if macro->idxLFO <> LFOmap + LFOmap = macro->idxLFO + showUpdate = showUpdate | 2 + fin + if macro->perLFO <> LFO + LFO = macro->perLFO + showUpdate = showUpdate | 4 + fin + if macro->durAtk + macro->durDcy + macro->durSus + macro->durRel <> duration + envelope(macro->durAtk, macro->durDcy, macro->durSus, macro->durRel, macro=>rateAtk, macro=>rateDcy, macro=>rateRel) + duration = macro->durAtk + macro->durDcy + macro->durSus + macro->durRel + showUpdate = showUpdate | 8 + fin + fin + // + // Run throught the sequence + // + for seq = 1 to macro->sequence + key = macro->sequence[seq] + // + // Check for tone keys + // + for i = 0 to 13 + if keytone[i] == key + if LFO == 0 + hilopwm(scale[i]>>octave, LFO, 0) + else + hilopwm(scale[i]>>octave, LFO, LFOmap) + fin + break + fin + next + // + // Check for macro keys + // + if i > 13 + for i = 0 to 6 + if keymacro[i] == key + playback(i) + break + fin + next + if i > 6 + when key + is ' ' + restnote + break + is $15 // -> + octave++ + showUpdate = showUpdate | 1 + break + is $08 // <- + showUpdate = showUpdate | 1 + octave-- + break + is '1' + is '2' + is '3' + is '4' + is '5' + is '6' + is '7' + is '8' + LFOmap = key - '1' + showUpdate = showUpdate | 2 + break + is '<' + is ',' + LFO-- + showUpdate = showUpdate | 4 + break + is '>' + is '.' + LFO++ + showUpdate = showUpdate | 4 + break + is '+' + is $0B // UP + duration++ + recalcEnv + envelope(atkLen, dcyLen, susLen, relLen, atkRate, dcyRate, relRate) + showUpdate = showUpdate | 8 + break + is '-' + is $0A // DOWN + duration-- + recalcEnv + envelope(atkLen, dcyLen, susLen, relLen, atkRate, dcyRate, relRate) + showUpdate = showUpdate | 8 + break + wend + fin + fin + next + // + // Udate display + // + if showUpdate & 1; showOctave; fin + if showUpdate & 2; showWaveform; fin + if showUpdate & 4; showLFO; fin + if showUpdate & 8; showDuration; fin +end +// // Main loop // def main byte quit, key, i - envelope(atkLen, dcyLen, susLen, relLen, atkRate, dcyRate, relRate) quit = FALSE repeat if keypressed key = toupper(getc) - when key - is $1B // ESC - quit = TRUE - break - is $15 // -> - if octave < 3 - octave++ - showOctave + // + // Check for tone keys + // + for i = 0 to 13 + if keytone[i] == key + if LFO == 0 + hilopwm(scale[i]>>octave, LFO, 0) + else + hilopwm(scale[i]>>octave, LFO, LFOmap) fin break - is $08 // <- - if octave > 0 - octave-- - showOctave + fin + next + // + // Check for macro keys + // + if i > 13 + for i = 0 to 6 + if keymacro[i] == key + playback(i) + break fin - break - is '1' - is '2' - is '3' - is '4' - is '5' - is '6' - is '7' - is '8' - LFOmap = key - '1' - showWaveform - break - is '<' - is ',' - LFO-- - showLFO - break - is '>' - is '.' - LFO++ - showLFO - break - is '+' - is $0B // UP - if duration < 40 - duration++ - recalcEnv - envelope(atkLen, dcyLen, susLen, relLen, atkRate, dcyRate, relRate) - showDuration - fin - break - is '-' - is $0A // DOWN - if duration > 2 - duration-- - recalcEnv - envelope(atkLen, dcyLen, susLen, relLen, atkRate, dcyRate, relRate) - showDuration - fin - break - otherwise - for i = 0 to 13 - if keytone[i] == key - if LFO == 0 - hilopwm(scale[i]>>octave, LFO, 0) - else - hilopwm(scale[i]>>octave, LFO, LFOmap) + next + if i > 6 + if not recording + for i = 0 to 6 + if keyrecord[i] == key + recording = (key << 8) | i + // + // Save current state + // + record.absStart = TRUE + record.durAtk = atkLen + record.durDcy = dcyLen + record.durSus = susLen + record.durRel = relLen + record.rateAtk = atkRate + record.rateDcy = dcyRate + record.rateRel = relRate + record.idxOctave = octave + record.perLFO = LFO + record.idxLFO = LFOmap + record.sequence = 0 + flash + putsxy(29, 3, "RECORDING") + inverse + key = 0 + break fin - break - fin - next - wend + next + fin + if i > 6 + when key + is $1B // ESC + if recording // Cancel recording + recording = FALSE + putsxy(29, 3, " ") + else + quit = query("QUIT (Y/N)?") + if not quit + showMainPanel + fin + fin + break + is '?' + record.absStart = FALSE + is '/' + if recording // Copy recorded macro to key macro + memcpy(macros + t_macro * (recording & $FF), @record, t_macro) + recording = FALSE + modPatch = TRUE + putsxy(29, 3, " ") + fin + break + is $15 // -> + if octave < 3 + octave++ + showOctave + else + key = 0 + fin + break + is $08 // <- + if octave > 0 + octave-- + showOctave + else + key = 0 + fin + break + is '1' + is '2' + is '3' + is '4' + is '5' + is '6' + is '7' + is '8' + LFOmap = key - '1' + showWaveform + break + is '<' + is ',' + LFO-- + showLFO + break + is '>' + is '.' + LFO++ + showLFO + break + is '+' + is $0B // UP + if duration < 40 + duration++ + recalcEnv + envelope(atkLen, dcyLen, susLen, relLen, atkRate, dcyRate, relRate) + showDuration + else + key = 0 + fin + break + is '-' + is $0A // DOWN + if duration > 1 + duration-- + recalcEnv + envelope(atkLen, dcyLen, susLen, relLen, atkRate, dcyRate, relRate) + showDuration + else + key = 0 + fin + break + is 'P' + if modPatch + savePatch + fin + break + wend + fin + fin + fin + if recording and key + if record.sequence < 255 + record.sequence++ + record.sequence[record.sequence] = key + fin + fin fin - //LFO = pdl(0) until quit end // // Get heap start. // -heap = *freemem +macros = *freemem +heap = macros + t_macro * NMACROS +loadPatch +memset(macros, 0, t_macro * NMACROS) call($FDED, $8D, 0, 0, 0) call($FDED, $91, 0, 0, 0)// CTRL-Q = turn off 80 column call($FDED, $8D, 0, 0, 0) ^$C000 = 0 // Turn off 80STORE grmode -clearview -showDuration -showWaveform -showLFO -putsxy(8, 0, "OSCILLATION OVERTHRUSTER") -normal -putsxy(2, 0, "1..8") -gotoxy(34, 0); putc('<') -gotoxy(39, 0); putc('>') -gotoxy(6, 3); putc('-') -gotoxy(32, 3); putc('+') -inverse -showOctave -normal -putsxy(0, 2, "<-") -putsxy(38, 2, "->") -inverse -putsxy(11, 3, "A S D F G H J K L") -normal -gotoxy(14, 2); putc('E') -gotoxy(16, 2); putc('R') -gotoxy(20, 2); putc('Y') -gotoxy(22, 2); putc('U') -gotoxy(24, 2); putc('I') -inverse +showMainPanel main +if modPatch + if query("SAVE PATCH (Y/N)?") + savePatch + fin +fin normal textmode done diff --git a/src/samplesrc/a2pwm/lfo.po b/src/samplesrc/a2pwm/lfo.po index 8578bce..7246055 100755 Binary files a/src/samplesrc/a2pwm/lfo.po and b/src/samplesrc/a2pwm/lfo.po differ diff --git a/src/samplesrc/a2pwm/makefile b/src/samplesrc/a2pwm/makefile index df9b77b..d5080af 100755 --- a/src/samplesrc/a2pwm/makefile +++ b/src/samplesrc/a2pwm/makefile @@ -24,5 +24,5 @@ clean: -rm *.o *~ *.a *.bin $(HILOPWM): a2pwm.s util.pla hilopwm.pla pwmvm.s $(PLASM) - ./$(PLASM) -A < hilopwm.pla > hilopwm.a + $(PLASM) -A < hilopwm.pla > hilopwm.a acme -o $(HILOPWM) pwmvm.s diff --git a/src/samplesrc/a2pwm/util.pla b/src/samplesrc/a2pwm/util.pla index 4ad9d8a..e4db7f2 100644 --- a/src/samplesrc/a2pwm/util.pla +++ b/src/samplesrc/a2pwm/util.pla @@ -22,6 +22,10 @@ word txt1scrn[] = $0400,$0480,$0500,$0580,$0600,$0680,$0700,$0780 word = $0428,$04A8,$0528,$05A8,$0628,$06A8,$0728,$07A8 word = $0450,$04D0,$0550,$05D0,$0650,$06D0,$0750,$07D0 // +// ProDOS error +// +byte perr +// // CALL 6502 ROUTINE // CALL(ADDR, AREG, XREG, YREG, STATUS) // @@ -63,225 +67,248 @@ CALL6502 JSR $FFFF REGVALS !FILL 4 end // +// CALL PRODOS +// SYSCALL(CMD, PARAMS) +// +asm syscall + LDA ESTKL,X + LDY ESTKH,X + STA PARAMS + STY PARAMS+1 + INX + LDA ESTKL,X + STA CMD + JSR $BF00 +CMD: !BYTE 00 +PARAMS: !WORD 0000 + LDY #$00 + STA ESTKL,X + STY ESTKH,X + RTS +end +// // SET MEMORY TO VALUE // MEMSET(ADDR, VALUE, SIZE) // With optimizations from Peter Ferrie // asm memset - LDA ESTKL+2,X - STA DSTL - LDA ESTKH+2,X - STA DSTH - LDY ESTKL,X - BEQ + - INC ESTKH,X - LDY #$00 -+ LDA ESTKH,X - BEQ SETMEX + LDA ESTKL+2,X + STA DSTL + LDA ESTKH+2,X + STA DSTH + LDY ESTKL,X + BEQ + + INC ESTKH,X + LDY #$00 ++ LDA ESTKH,X + BEQ SETMEX SETMLPL CLC - LDA ESTKL+1,X + LDA ESTKL+1,X SETMLPH STA (DST),Y - DEC ESTKL,X - BEQ ++ -- INY - BEQ + --- BCS SETMLPL - SEC - LDA ESTKH+1,X - BCS SETMLPH -+ INC DSTH - BNE -- -++ DEC ESTKH,X - BNE - + DEC ESTKL,X + BEQ ++ +- INY + BEQ + +-- BCS SETMLPL + SEC + LDA ESTKH+1,X + BCS SETMLPH ++ INC DSTH + BNE -- +++ DEC ESTKH,X + BNE - SETMEX INX - INX - RTS + INX + RTS end // // COPY MEMORY // MEMCPY(DSTADDR, SRCADDR, SIZE) // asm memcpy - INX - INX - LDA ESTKL-2,X - ORA ESTKH-2,X - BEQ CPYMEX - LDA ESTKL-1,X - CMP ESTKL,X - LDA ESTKH-1,X - SBC ESTKH,X - BCC REVCPY + INX + INX + LDA ESTKL-2,X + ORA ESTKH-2,X + BEQ CPYMEX + LDA ESTKL-1,X + CMP ESTKL,X + LDA ESTKH-1,X + SBC ESTKH,X + BCC REVCPY ; ; FORWARD COPY ; - LDA ESTKL,X - STA DSTL - LDA ESTKH,X - STA DSTH - LDA ESTKL-1,X - STA SRCL - LDA ESTKH-1,X - STA SRCH - LDY ESTKL-2,X - BEQ FORCPYLP - INC ESTKH-2,X - LDY #$00 + LDA ESTKL,X + STA DSTL + LDA ESTKH,X + STA DSTH + LDA ESTKL-1,X + STA SRCL + LDA ESTKH-1,X + STA SRCH + LDY ESTKL-2,X + BEQ FORCPYLP + INC ESTKH-2,X + LDY #$00 FORCPYLP LDA (SRC),Y - STA (DST),Y - INY - BNE + - INC DSTH - INC SRCH -+ DEC ESTKL-2,X - BNE FORCPYLP - DEC ESTKH-2,X - BNE FORCPYLP - RTS + STA (DST),Y + INY + BNE + + INC DSTH + INC SRCH ++ DEC ESTKL-2,X + BNE FORCPYLP + DEC ESTKH-2,X + BNE FORCPYLP + RTS ; ; REVERSE COPY ; REVCPY ;CLC - LDA ESTKL-2,X - ADC ESTKL,X - STA DSTL - LDA ESTKH-2,X - ADC ESTKH,X - STA DSTH - CLC - LDA ESTKL-2,X - ADC ESTKL-1,X - STA SRCL - LDA ESTKH-2,X - ADC ESTKH-1,X - STA SRCH - DEC DSTH - DEC SRCH - LDY #$FF - LDA ESTKL-2,X - BEQ REVCPYLP - INC ESTKH-2,X + LDA ESTKL-2,X + ADC ESTKL,X + STA DSTL + LDA ESTKH-2,X + ADC ESTKH,X + STA DSTH + CLC + LDA ESTKL-2,X + ADC ESTKL-1,X + STA SRCL + LDA ESTKH-2,X + ADC ESTKH-1,X + STA SRCH + DEC DSTH + DEC SRCH + LDY #$FF + LDA ESTKL-2,X + BEQ REVCPYLP + INC ESTKH-2,X REVCPYLP LDA (SRC),Y - STA (DST),Y - DEY - CPY #$FF - BNE + - DEC DSTH - DEC SRCH -+ DEC ESTKL-2,X - BNE REVCPYLP - DEC ESTKH-2,X - BNE REVCPYLP + STA (DST),Y + DEY + CPY #$FF + BNE + + DEC DSTH + DEC SRCH ++ DEC ESTKL-2,X + BNE REVCPYLP + DEC ESTKH-2,X + BNE REVCPYLP CPYMEX RTS end // // Unsigned word comparisons. // asm uword_isge - LDA ESTKL+1,X - CMP ESTKL,X - LDA ESTKH+1,X - SBC ESTKH,X - LDA #$FF - ADC #$00 - EOR #$FF - STA ESTKL+1,X - STA ESTKH+1,X - INX - RTS + LDA ESTKL+1,X + CMP ESTKL,X + LDA ESTKH+1,X + SBC ESTKH,X + LDA #$FF + ADC #$00 + EOR #$FF + STA ESTKL+1,X + STA ESTKH+1,X + INX + RTS end asm uword_isle - LDA ESTKL,X - CMP ESTKL+1,X - LDA ESTKH,X - SBC ESTKH+1,X - LDA #$FF - ADC #$00 - EOR #$FF - STA ESTKL+1,X - STA ESTKH+1,X - INX - RTS + LDA ESTKL,X + CMP ESTKL+1,X + LDA ESTKH,X + SBC ESTKH+1,X + LDA #$FF + ADC #$00 + EOR #$FF + STA ESTKL+1,X + STA ESTKH+1,X + INX + RTS end asm uword_isgt - LDA ESTKL,X - CMP ESTKL+1,X - LDA ESTKH,X - SBC ESTKH+1,X - LDA #$FF - ADC #$00 - STA ESTKL+1,X - STA ESTKH+1,X - INX - RTS + LDA ESTKL,X + CMP ESTKL+1,X + LDA ESTKH,X + SBC ESTKH+1,X + LDA #$FF + ADC #$00 + STA ESTKL+1,X + STA ESTKH+1,X + INX + RTS end asm uword_islt - LDA ESTKL+1,X - CMP ESTKL,X - LDA ESTKH+1,X - SBC ESTKH,X - LDA #$FF - ADC #$00 - STA ESTKL+1,X - STA ESTKH+1,X - INX - RTS + LDA ESTKL+1,X + CMP ESTKL,X + LDA ESTKH+1,X + SBC ESTKH,X + LDA #$FF + ADC #$00 + STA ESTKL+1,X + STA ESTKH+1,X + INX + RTS end // // Addresses of internal routines. // asm _hilopwm - TXA - PHA - JSR HILOPWM - PLA - TAX - DEX - RTS + TXA + PHA + JSR HILOPWM + PLA + TAX + DEX + RTS end asm toupper - LDA ESTKL,X + LDA ESTKL,X TOUPR AND #$7F - CMP #'a' - BCC + - CMP #'z'+1 - BCS + - SBC #$1F -+ STA ESTKL,X - RTS + CMP #'a' + BCC + + CMP #'z'+1 + BCS + + SBC #$1F ++ STA ESTKL,X + RTS end // // CONSOLE I/O // asm putc - LDA ESTKL,X -; JSR TOUPR - ORA #$80 - JMP $FDF0 + LDA ESTKL,X +; JSR TOUPR + ORA #$80 + JMP $FDF0 end asm getc - DEX -- LDA $C000 - BPL - - BIT $C010 - AND #$7F - STA ESTKL,X - LDA #$00 - STA ESTKH,X - RTS + DEX +- LDA $C000 + BPL - + BIT $C010 + AND #$7F + STA ESTKL,X + LDA #$00 + STA ESTKH,X + RTS end def keypressed return ^$C000 >= 128 end def pdl(num) return call($FB1E, 0, num, 0, 0)->2 -end +end def bttn(num) return (^$C061+num) >= 128 end def putln return putc($0D) end +def beep + return putc($07) +end def puts(str) byte i @@ -320,6 +347,9 @@ end def inverse ^$32 = $3F end +def flash + ^$32 = $1F +end def gotoxy(x, y) ^$24 = x + ^$20 return call($FB5B, y + ^$22, 0, 0, 0) @@ -341,7 +371,7 @@ end def clearview byte i word c - inverse + c = ' ' | $80 & ^$32 c = c | (c << 8) for i = ^$22 to ^$23 @@ -385,6 +415,71 @@ def rect(left, right, top, bottom, fill) fin end // +// ProDOS routines +// +def open(path, buff) + byte params[6] + + params.0 = 3 + params:1 = path + params:3 = buff + params.5 = 0 + perr = syscall($C8, @params) + return params.5 +end +def close(refnum) + byte params[2] + + params.0 = 1 + params.1 = refnum + perr = syscall($CC, @params) + return perr +end +def read(refnum, buff, len) + byte params[8] + + params.0 = 4 + params.1 = refnum + params:2 = buff + params:4 = len + params:6 = 0 + perr = syscall($CA, @params) + return params:6 +end +def write(refnum, buff, len) + byte params[8] + + params.0 = 4 + params.1 = refnum + params:2 = buff + params:4 = len + params:6 = 0 + perr = syscall($CB, @params) + return params:6 +end +def create(path, access, type, aux) + byte params[12] + + params.0 = 7 + params:1 = path + params.3 = access + params.4 = type + params:5 = aux + params.7 = $1 + params:8 = 0 + params:10 = 0 + perr = syscall($C0, @params) + return perr +end +def destroy(path) + byte params[3] + + params.0 = 1 + params:1 = path + perr = syscall($C1, @params) + return perr +end +// // HFO/LFO PWM sound routines // def envelope(attack, decay, sustain, release, ainc, dinc, rinc)