Created
September 3, 2017 00:34
-
-
Save MegaLoler/99a317abc3d6346ae97746ada5e6a38a to your computer and use it in GitHub Desktop.
A 4 channel softsynth for AVR and a tracker in C that communicates with it over serial
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.define NOTE_C 262 | |
.define NOTE_Cs 277 | |
.define NOTE_D 294 | |
.define NOTE_Ds 311 | |
.define NOTE_E 330 | |
.define NOTE_F 349 | |
.define NOTE_Fs 370 | |
.define NOTE_G 392 | |
.define NOTE_Gs 415 | |
.define NOTE_A 440 | |
.define NOTE_As 466 | |
.define NOTE_B 494 | |
.def LEFT_BUF = r2 | |
.def RIGHT_BUF = r3 | |
.def CHAN1_OSCL = r4 | |
.def CHAN1_OSCH = r5 | |
.def CHAN2_OSCL = r6 | |
.def CHAN2_OSCH = r7 | |
.def CHAN3_OSCL = r8 | |
.def CHAN3_OSCH = r9 | |
.def CHAN4_OSCL = r10 | |
.def CHAN4_OSCH = r11 | |
.def CHAN1_FRQL = r12 | |
.def CHAN1_FRQH = r13 | |
.def CHAN2_FRQL = r14 | |
.def CHAN2_FRQH = r15 | |
.def CHAN3_FRQL = r24 | |
.def CHAN3_FRQH = r25 | |
.def CHAN4_FRQL = r26 | |
.def CHAN4_FRQH = r27 | |
.def NOISEL = r0 | |
.def NOISEH = r1 | |
.NOLIST | |
.include "m48def.inc" | |
.LIST | |
.cseg | |
.org 0x00 | |
rjmp start | |
.org 0x09 | |
rjmp timer | |
.org 0x12 | |
rjmp recieve | |
start: | |
ldi r16, LOW(RAMEND) | |
out spl, r16 | |
ldi r16, HIGH(RAMEND) | |
out sph, r16 | |
ldi r16, 1 | |
sts TIMSK2, r16 | |
ldi r16, 0b001 | |
sts TCCR2B, r16 | |
ldi r16, 0b11111100 | |
out ddrd, r16 | |
ldi r16, 0xFF | |
out ddrc, r16 | |
ldi r16, 0xFF | |
mov LEFT_BUF, r16 | |
mov RIGHT_BUF, r16 | |
ldi r16, 0b0011 | |
sts enable, r16 | |
ldi r16, 0b00000000 | |
sts waveform, r16 | |
ldi r16, 0x80 | |
sts chan1_tdut, r16 | |
sts chan2_tdut, r16 | |
sts chan3_tdut, r16 | |
sts chan4_tdut, r16 | |
ldi r16, 0xFF | |
sts chan1_tvol, r16 | |
sts chan2_tvol, r16 | |
sts chan3_tvol, r16 | |
sts chan4_tvol, r16 | |
ldi r16, 0x01 | |
ldi r17, 0x00 | |
mov NOISEL, r16 | |
mov NOISEH, r17 | |
ldi r16, 0x00 | |
sts tick_timer, r16 | |
sts tick_timer + 1, r16 | |
ldi r16, 0xF0 | |
sts chan1_env + 1, r16 | |
sts chan2_env + 1, r16 | |
sts chan3_env + 1, r16 | |
sts chan4_env + 1, r16 | |
ldi r16, 0x44 | |
sts chan1_notes, r16 | |
ldi r16, 0x00 | |
sts chan2_notes, r16 | |
ldi r16, 0x00 | |
sts chan3_notes, r16 | |
ldi r16, 0x00 | |
sts chan4_notes, r16 | |
ldi r16, 0x00 | |
sts chan1_notes + 1, r16 | |
ldi r16, 0x00 | |
sts chan2_notes + 1, r16 | |
ldi r16, 0x00 | |
sts chan3_notes + 1, r16 | |
ldi r16, 0x00 | |
sts chan4_notes + 1, r16 | |
ldi r16, 0b0000 | |
sts note_on, r16 | |
;ldi r16, 0b00100000 | |
;ldi r17, 0b10000010 | |
;rcall command | |
;ldi r16, 0b00100010 | |
;ldi r17, 0b11111110 | |
;rcall command | |
;ldi r16, 0b01011100 | |
;ldi r17, 0b11111110 | |
;rcall command | |
;ldi r16, 0b01110110 | |
;ldi r17, 0b11111110 | |
;rcall command | |
;ldi r16, 0b01111001 | |
;ldi r17, 0b10000001 | |
;rcall command | |
ldi r16, LOW(103) | |
ldi r17, HIGH(103) | |
sts UBRR0L, r16 | |
sts UBRR0H, r17 | |
ldi r16, (1 << RXEN0) | (1 << RXCIE0) | |
sts UCSR0B, r16 | |
ldi r16, (1 << USBS0) | (3 << UCSZ00) | |
sts UCSR0C, r16 | |
sei | |
loop: | |
rjmp loop | |
recieve: | |
lds r16, UDR0 | |
cpi r16, 0xFF | |
breq handle_command | |
lds r17, command_buf | |
sts command_buf + 1, r17 | |
sts command_buf, r16 | |
reti | |
handle_command: | |
lds r16, command_buf | |
lds r17, command_buf + 1 | |
rcall command | |
reti | |
command: | |
sbrs r17, 7 | |
ret | |
mov r18, r16 | |
lsr r18 | |
andi r18, 0b00000011 ;channel | |
sbrs r16, 0 | |
rjmp note_command | |
effect_command: | |
mov r19, r16 | |
lsl r19 | |
andi r19, 0xF0 ;effect | |
mov r20, r17 | |
lsl r20 | |
sbrc r16, 7 | |
ori r20, 0b00000001 ;argument | |
cpi r19, 0x00 | |
breq apply_arp | |
cpi r19, 0x10 | |
breq apply_pitch_slide_up | |
cpi r19, 0x20 | |
breq apply_pitch_slide_down_a | |
cpi r19, 0x30 | |
breq apply_portamento_a | |
cpi r19, 0x40 | |
breq apply_vibrato_a | |
cpi r19, 0x50 | |
breq apply_waveform_a | |
cpi r19, 0x60 | |
breq apply_duty_cycle_a | |
cpi r19, 0x70 | |
breq apply_tremolo_a | |
cpi r19, 0x80 | |
breq apply_pwm_a | |
cpi r19, 0xA0 | |
breq apply_volume_slide_up_a | |
cpi r19, 0xB0 | |
breq apply_volume_slide_down_a | |
cpi r19, 0xC0 | |
breq apply_volume_a | |
cpi r19, 0xF0 | |
breq apply_fine_a | |
rjmp done | |
apply_arp: | |
cpi r18, 0b00 | |
breq apply_arp1 | |
cpi r18, 0b01 | |
breq apply_arp2 | |
cpi r18, 0b10 | |
breq apply_arp3 | |
cpi r18, 0b11 | |
breq apply_arp4 | |
rjmp done | |
apply_arp1: | |
sts chan1_notes + 1, r20 | |
rjmp done | |
apply_arp2: | |
sts chan2_notes + 1, r20 | |
rjmp done | |
apply_arp3: | |
sts chan3_notes + 1, r20 | |
rjmp done | |
apply_arp4: | |
sts chan4_notes + 1, r20 | |
rjmp done | |
apply_pitch_slide_down_a: | |
rjmp apply_pitch_slide_down | |
apply_portamento_a: | |
rjmp apply_portamento | |
apply_vibrato_a: | |
rjmp apply_vibrato | |
apply_waveform_a: | |
rjmp apply_waveform | |
apply_duty_cycle_a: | |
rjmp apply_duty_cycle | |
apply_tremolo_a: | |
rjmp apply_tremolo | |
apply_pwm_a: | |
rjmp apply_pwm | |
apply_volume_slide_up_a: | |
rjmp apply_volume_slide_up | |
apply_volume_slide_down_a: | |
rjmp apply_volume_slide_down | |
apply_volume_a: | |
rjmp apply_volume_eff | |
apply_fine_a: | |
rjmp apply_fine | |
apply_pitch_slide_up: | |
cpi r18, 0b00 | |
breq apply_pitch_slide_up1 | |
cpi r18, 0b01 | |
breq apply_pitch_slide_up2 | |
cpi r18, 0b10 | |
breq apply_pitch_slide_up3 | |
cpi r18, 0b11 | |
breq apply_pitch_slide_up4 | |
rjmp done | |
apply_pitch_slide_up1: | |
sts chan1_pit_slide, r20 | |
lds r16, pit_slide_dir | |
ori r16, 0b0001 | |
sts pit_slide_dir, r16 | |
rjmp done | |
apply_pitch_slide_up2: | |
sts chan2_pit_slide, r20 | |
lds r16, pit_slide_dir | |
ori r16, 0b0010 | |
sts pit_slide_dir, r16 | |
rjmp done | |
apply_pitch_slide_up3: | |
sts chan3_pit_slide, r20 | |
lds r16, pit_slide_dir | |
ori r16, 0b0100 | |
sts pit_slide_dir, r16 | |
rjmp done | |
apply_pitch_slide_up4: | |
sts chan4_pit_slide, r20 | |
lds r16, pit_slide_dir | |
ori r16, 0b1000 | |
sts pit_slide_dir, r16 | |
rjmp done | |
apply_pitch_slide_down: | |
cpi r18, 0b00 | |
breq apply_pitch_slide_down1 | |
cpi r18, 0b01 | |
breq apply_pitch_slide_down2 | |
cpi r18, 0b10 | |
breq apply_pitch_slide_down3 | |
cpi r18, 0b11 | |
breq apply_pitch_slide_down4 | |
rjmp done | |
apply_pitch_slide_down1: | |
sts chan1_pit_slide, r20 | |
lds r16, pit_slide_dir | |
andi r16, 0b1110 | |
sts pit_slide_dir, r16 | |
rjmp done | |
apply_pitch_slide_down2: | |
sts chan2_pit_slide, r20 | |
lds r16, pit_slide_dir | |
andi r16, 0b1101 | |
sts pit_slide_dir, r16 | |
rjmp done | |
apply_pitch_slide_down3: | |
sts chan3_pit_slide, r20 | |
lds r16, pit_slide_dir | |
andi r16, 0b1011 | |
sts pit_slide_dir, r16 | |
rjmp done | |
apply_pitch_slide_down4: | |
sts chan4_pit_slide, r20 | |
lds r16, pit_slide_dir | |
andi r16, 0b0111 | |
sts pit_slide_dir, r16 | |
rjmp done | |
apply_portamento: | |
cpi r18, 0b00 | |
breq apply_portamento1 | |
cpi r18, 0b01 | |
breq apply_portamento2 | |
cpi r18, 0b10 | |
breq apply_portamento3 | |
cpi r18, 0b11 | |
breq apply_portamento4 | |
rjmp done | |
apply_portamento1: | |
sts chan1_port, r20 | |
rjmp done | |
apply_portamento2: | |
sts chan2_port, r20 | |
rjmp done | |
apply_portamento3: | |
sts chan3_port, r20 | |
rjmp done | |
apply_portamento4: | |
sts chan4_port, r20 | |
rjmp done | |
apply_vibrato: | |
cpi r18, 0b00 | |
breq apply_vibrato1 | |
cpi r18, 0b01 | |
breq apply_vibrato2 | |
cpi r18, 0b10 | |
breq apply_vibrato3 | |
cpi r18, 0b11 | |
breq apply_vibrato4 | |
rjmp done | |
apply_vibrato1: | |
sts chan1_vib, r20 | |
rjmp done | |
apply_vibrato2: | |
sts chan2_vib, r20 | |
rjmp done | |
apply_vibrato3: | |
sts chan3_vib, r20 | |
rjmp done | |
apply_vibrato4: | |
sts chan4_vib, r20 | |
rjmp done | |
apply_waveform: | |
lds r16, waveform | |
cpi r18, 0b00 | |
breq apply_waveform1 | |
cpi r18, 0b01 | |
breq apply_waveform2 | |
cpi r18, 0b10 | |
breq apply_waveform3 | |
cpi r18, 0b11 | |
breq apply_waveform4 | |
rjmp done_waveform | |
apply_waveform1: | |
andi r16, 0b11111100 | |
or r16, r20 | |
rjmp done_waveform | |
apply_waveform2: | |
andi r16, 0b11110011 | |
lsl r20 | |
lsl r20 | |
or r16, r20 | |
rjmp done_waveform | |
apply_waveform3: | |
andi r16, 0b11001111 | |
lsl r20 | |
lsl r20 | |
lsl r20 | |
lsl r20 | |
or r16, r20 | |
rjmp done_waveform | |
apply_waveform4: | |
andi r16, 0b00111111 | |
lsl r20 | |
lsl r20 | |
lsl r20 | |
lsl r20 | |
lsl r20 | |
lsl r20 | |
or r16, r20 | |
done_waveform: | |
sts waveform, r16 | |
rjmp done | |
apply_duty_cycle: | |
cpi r18, 0b00 | |
breq apply_duty_cycle1 | |
cpi r18, 0b01 | |
breq apply_duty_cycle2 | |
cpi r18, 0b10 | |
breq apply_duty_cycle3 | |
cpi r18, 0b11 | |
breq apply_duty_cycle4 | |
rjmp done | |
apply_duty_cycle1: | |
sts chan1_tdut, r20 | |
rjmp done | |
apply_duty_cycle2: | |
sts chan2_tdut, r20 | |
rjmp done | |
apply_duty_cycle3: | |
sts chan3_tdut, r20 | |
rjmp done | |
apply_duty_cycle4: | |
sts chan4_tdut, r20 | |
rjmp done | |
apply_tremolo: | |
cpi r18, 0b00 | |
breq apply_tremolo1 | |
cpi r18, 0b01 | |
breq apply_tremolo2 | |
cpi r18, 0b10 | |
breq apply_tremolo3 | |
cpi r18, 0b11 | |
breq apply_tremolo4 | |
rjmp done | |
apply_tremolo1: | |
sts chan1_trm, r20 | |
rjmp done | |
apply_tremolo2: | |
sts chan2_trm, r20 | |
rjmp done | |
apply_tremolo3: | |
sts chan3_trm, r20 | |
rjmp done | |
apply_tremolo4: | |
sts chan4_trm, r20 | |
rjmp done | |
apply_pwm: | |
cpi r18, 0b00 | |
breq apply_pwm1 | |
cpi r18, 0b01 | |
breq apply_pwm2 | |
cpi r18, 0b10 | |
breq apply_pwm3 | |
cpi r18, 0b11 | |
breq apply_pwm4 | |
rjmp done | |
apply_pwm1: | |
sts chan1_pwm, r20 | |
rjmp done | |
apply_pwm2: | |
sts chan2_pwm, r20 | |
rjmp done | |
apply_pwm3: | |
sts chan3_pwm, r20 | |
rjmp done | |
apply_pwm4: | |
sts chan4_pwm, r20 | |
rjmp done | |
apply_volume_slide_up: | |
cpi r18, 0b00 | |
breq apply_volume_slide_up1 | |
cpi r18, 0b01 | |
breq apply_volume_slide_up2 | |
cpi r18, 0b10 | |
breq apply_volume_slide_up3 | |
cpi r18, 0b11 | |
breq apply_volume_slide_up4 | |
rjmp done | |
apply_volume_slide_up1: | |
sts chan1_vol_slide, r20 | |
lds r16, vol_slide_dir | |
ori r16, 0b0001 | |
sts vol_slide_dir, r16 | |
rjmp done | |
apply_volume_slide_up2: | |
sts chan2_vol_slide, r20 | |
lds r16, vol_slide_dir | |
ori r16, 0b0010 | |
sts vol_slide_dir, r16 | |
rjmp done | |
apply_volume_slide_up3: | |
sts chan3_vol_slide, r20 | |
lds r16, vol_slide_dir | |
ori r16, 0b0100 | |
sts vol_slide_dir, r16 | |
rjmp done | |
apply_volume_slide_up4: | |
sts chan4_vol_slide, r20 | |
lds r16, vol_slide_dir | |
ori r16, 0b1000 | |
sts vol_slide_dir, r16 | |
rjmp done | |
apply_volume_slide_down: | |
cpi r18, 0b00 | |
breq apply_volume_slide_down1 | |
cpi r18, 0b01 | |
breq apply_volume_slide_down2 | |
cpi r18, 0b10 | |
breq apply_volume_slide_down3 | |
cpi r18, 0b11 | |
breq apply_volume_slide_down4 | |
rjmp done | |
apply_volume_slide_down1: | |
sts chan1_vol_slide, r20 | |
lds r16, vol_slide_dir | |
andi r16, 0b1110 | |
sts vol_slide_dir, r16 | |
rjmp done | |
apply_volume_slide_down2: | |
sts chan2_vol_slide, r20 | |
lds r16, vol_slide_dir | |
andi r16, 0b1101 | |
sts vol_slide_dir, r16 | |
rjmp done | |
apply_volume_slide_down3: | |
sts chan3_vol_slide, r20 | |
lds r16, vol_slide_dir | |
andi r16, 0b1011 | |
sts vol_slide_dir, r16 | |
rjmp done | |
apply_volume_slide_down4: | |
sts chan4_vol_slide, r20 | |
lds r16, vol_slide_dir | |
andi r16, 0b0111 | |
sts vol_slide_dir, r16 | |
rjmp done | |
apply_volume_eff: | |
cpi r18, 0b00 | |
breq apply_volume1_eff | |
cpi r18, 0b01 | |
breq apply_volume2_eff | |
cpi r18, 0b10 | |
breq apply_volume3_eff | |
cpi r18, 0b11 | |
breq apply_volume4_eff | |
rjmp done | |
apply_volume1_eff: | |
sts chan1_tvol, r20 | |
rjmp done | |
apply_volume2_eff: | |
sts chan1_tvol, r20 | |
rjmp done | |
apply_volume3_eff: | |
sts chan1_tvol, r20 | |
rjmp done | |
apply_volume4_eff: | |
sts chan1_tvol, r20 | |
rjmp done | |
apply_fine: | |
cpi r18, 0b00 | |
breq apply_fine1 | |
cpi r18, 0b01 | |
breq apply_fine2 | |
cpi r18, 0b10 | |
breq apply_fine3 | |
cpi r18, 0b11 | |
breq apply_fine4 | |
rjmp done | |
apply_fine1: | |
sts chan1_fine, r20 | |
rjmp done | |
apply_fine2: | |
sts chan2_fine, r20 | |
rjmp done | |
apply_fine3: | |
sts chan3_fine, r20 | |
rjmp done | |
apply_fine4: | |
sts chan4_fine, r20 | |
rjmp done | |
note_command: | |
mov r19, r16 | |
lsl r19 | |
andi r19, 0xF0 ;note | |
mov r20, r17 | |
lsl r20 | |
sbrc r16, 7 | |
ori r20, 0b00000001 | |
lsl r17 | |
andi r17, 0b11111000 ;volume | |
andi r20, 0x0F | |
or r20, r19 ;note/octave | |
cpi r18, 0b00 | |
breq set_chan1 | |
cpi r18, 0b01 | |
breq set_chan2 | |
cpi r18, 0b10 | |
breq set_chan3a | |
cpi r18, 0b11 | |
breq set_chan4a | |
rjmp done | |
set_chan1: | |
cpi r19, 0x00 | |
breq skip_note1 | |
cpi r19, 0x10 | |
breq reset_note1 | |
cpi r19, 0x20 | |
breq enable_note1 | |
cpi r19, 0x30 | |
breq disable_note1 | |
lds r16, enable | |
ori r16, 0b0001 | |
sts enable, r16 | |
lds r16, note_on | |
ori r16, 0b0001 | |
sts note_on, r16 | |
sts chan1_notes, r20 | |
rjmp skip_note1 | |
reset_note1: | |
clr CHAN1_OSCL | |
clr CHAN1_OSCH | |
rjmp skip_note1 | |
enable_note1: | |
lds r16, enable | |
ori r16, 0b0001 | |
sts enable, r16 | |
rjmp skip_note1 | |
disable_note1: | |
lds r16, enable | |
andi r16, 0b1110 | |
sts enable, r16 | |
rjmp skip_note1 | |
skip_note1: | |
cpi r17, 0x00 | |
breq done_a | |
sts chan1_tvol, r17 | |
rjmp done | |
set_chan3a: | |
rjmp set_chan3 | |
set_chan4a: | |
rjmp set_chan4b | |
set_chan2: | |
cpi r19, 0x00 | |
breq skip_note2 | |
cpi r19, 0x10 | |
breq reset_note2 | |
cpi r19, 0x20 | |
breq enable_note2 | |
cpi r19, 0x30 | |
breq disable_note2 | |
lds r16, enable | |
ori r16, 0b0010 | |
sts enable, r16 | |
lds r16, note_on | |
ori r16, 0b0010 | |
sts note_on, r16 | |
sts chan2_notes, r20 | |
rjmp skip_note2 | |
reset_note2: | |
clr CHAN2_OSCL | |
clr CHAN2_OSCH | |
rjmp skip_note2 | |
enable_note2: | |
lds r16, enable | |
ori r16, 0b0010 | |
sts enable, r16 | |
rjmp skip_note2 | |
disable_note2: | |
lds r16, enable | |
andi r16, 0b1101 | |
sts enable, r16 | |
rjmp skip_note2 | |
skip_note2: | |
cpi r17, 0x00 | |
breq done_a | |
sts chan2_tvol, r17 | |
rjmp done | |
set_chan4b: | |
rjmp set_chan4 | |
done_a: | |
rjmp done | |
set_chan3: | |
cpi r19, 0x00 | |
breq skip_note3 | |
cpi r19, 0x10 | |
breq reset_note3 | |
cpi r19, 0x20 | |
breq enable_note3 | |
cpi r19, 0x30 | |
breq disable_note3 | |
lds r16, enable | |
ori r16, 0b0100 | |
sts enable, r16 | |
lds r16, note_on | |
ori r16, 0b0100 | |
sts note_on, r16 | |
sts chan3_notes, r20 | |
rjmp skip_note3 | |
reset_note3: | |
clr CHAN3_OSCL | |
clr CHAN3_OSCH | |
rjmp skip_note3 | |
enable_note3: | |
lds r16, enable | |
ori r16, 0b0100 | |
sts enable, r16 | |
rjmp skip_note3 | |
disable_note3: | |
lds r16, enable | |
andi r16, 0b1011 | |
sts enable, r16 | |
rjmp skip_note3 | |
skip_note3: | |
cpi r17, 0x00 | |
breq done | |
sts chan3_tvol, r17 | |
rjmp done | |
set_chan4: | |
cpi r19, 0x00 | |
breq skip_note4 | |
cpi r19, 0x10 | |
breq reset_note4 | |
cpi r19, 0x20 | |
breq enable_note4 | |
cpi r19, 0x30 | |
breq disable_note4 | |
lds r16, enable | |
ori r16, 0b1000 | |
sts enable, r16 | |
lds r16, note_on | |
ori r16, 0b1000 | |
sts note_on, r16 | |
sts chan4_notes, r20 | |
rjmp skip_note4 | |
reset_note4: | |
clr CHAN3_OSCL | |
clr CHAN3_OSCH | |
rjmp skip_note4 | |
enable_note4: | |
lds r16, enable | |
ori r16, 0b1000 | |
sts enable, r16 | |
rjmp skip_note4 | |
disable_note4: | |
lds r16, enable | |
andi r16, 0b0111 | |
sts enable, r16 | |
rjmp skip_note4 | |
skip_note4: | |
cpi r17, 0x00 | |
breq done | |
sts chan4_tvol, r17 | |
rjmp done | |
done: | |
ret | |
timer: | |
push r16 | |
push r17 | |
push r18 | |
push r19 | |
push r20 | |
push r21 | |
push r22 | |
push r23 | |
mov r16, LEFT_BUF | |
andi r16, 0b11111100 | |
mov r17, RIGHT_BUF | |
lsr r17 | |
lsr r17 | |
out portd, r16 | |
out portc, r17 | |
clr LEFT_BUF | |
clr RIGHT_BUF | |
add CHAN1_OSCL, CHAN1_FRQL | |
adc CHAN1_OSCH, CHAN1_FRQH | |
add CHAN2_OSCL, CHAN2_FRQL | |
adc CHAN2_OSCH, CHAN2_FRQH | |
add CHAN3_OSCL, CHAN3_FRQL | |
adc CHAN3_OSCH, CHAN3_FRQH | |
add CHAN4_OSCL, CHAN4_FRQL | |
adc CHAN4_OSCH, CHAN4_FRQH | |
lds r16, waveform | |
lds r22, enable | |
mov r18, r16 | |
andi r18, 0b00000011 | |
mov r19, CHAN1_OSCH | |
lds r20, chan1_vol | |
lds r21, chan1_dut | |
rcall generate | |
sbrc r22, 0 | |
add LEFT_BUF, r17 | |
lsr r16 | |
lsr r16 | |
mov r18, r16 | |
andi r18, 0b00000011 | |
mov r19, CHAN2_OSCH | |
lds r20, chan2_vol | |
lds r21, chan2_dut | |
rcall generate | |
sbrc r22, 1 | |
add LEFT_BUF, r17 | |
lsr r16 | |
lsr r16 | |
mov r18, r16 | |
andi r18, 0b00000011 | |
mov r19, CHAN3_OSCH | |
lds r20, chan3_vol | |
lds r21, chan3_dut | |
rcall generate | |
sbrc r22, 2 | |
add RIGHT_BUF, r17 | |
lsr r16 | |
lsr r16 | |
mov r18, r16 | |
andi r18, 0b00000011 | |
mov r19, CHAN4_OSCH | |
lds r20, chan4_vol | |
lds r21, chan4_dut | |
rcall generate | |
sbrc r22, 3 | |
add RIGHT_BUF, r17 | |
lds r16, tick_timer | |
cpi r16, 0x00 | |
brne skip22 | |
lds r20, vol_slide_dir | |
lds r16, chan1_tvol | |
lds r17, chan1_vol_slide | |
sbrc r20, 0 | |
rjmp up1b | |
sbc r16, r17 | |
brcc down1b | |
clr r16 | |
up1b: | |
add r16, r17 | |
brcc down1b | |
ser r16 | |
down1b: | |
sts chan1_tvol, r16 | |
sts chan1_ptrm, r16 | |
lds r16, chan2_tvol | |
lds r17, chan2_vol_slide | |
sbrc r20, 1 | |
rjmp up2b | |
sbc r16, r17 | |
brcc down2b | |
clr r16 | |
up2b: | |
add r16, r17 | |
brcc down2b | |
ser r16 | |
down2b: | |
sts chan2_tvol, r16 | |
sts chan2_ptrm, r16 | |
rjmp skip23 | |
skip22: | |
rjmp skip2 | |
skip23: | |
lds r16, chan3_tvol | |
lds r17, chan3_vol_slide | |
sbrc r20, 2 | |
rjmp up3b | |
sbc r16, r17 | |
brcc down3b | |
clr r16 | |
up3b: | |
add r16, r17 | |
brcc down3b | |
ser r16 | |
down3b: | |
sts chan3_tvol, r16 | |
sts chan3_ptrm, r16 | |
lds r16, chan4_tvol | |
lds r17, chan4_vol_slide | |
sbrc r20, 3 | |
rjmp up4b | |
sbc r16, r17 | |
brcc down4b | |
clr r16 | |
up4b: | |
add r16, r17 | |
brcc down4b | |
ser r16 | |
down4b: | |
sts chan4_tvol, r16 | |
sts chan4_ptrm, r16 | |
rjmp skip3 | |
skip2: | |
rjmp skip | |
skip3: | |
lds r16, note_on | |
lds r17, chan1_notes + 1 | |
cpi r17, 0x00 | |
breq skip11 | |
ori r16, 0b0001 | |
skip11: | |
sbrs r16, 0 | |
rjmp skip7 | |
andi r16, 0b1110 | |
sts note_on, r16 | |
lds r16, chan1_notes | |
lds r17, chan1_notes + 1 | |
rcall handle_note | |
sts chan1_tpit, r16 | |
sts chan1_tpit + 1, r17 | |
skip7: | |
lds r16, note_on | |
lds r17, chan2_notes + 1 | |
cpi r17, 0x00 | |
breq skip12 | |
ori r16, 0b0010 | |
skip12: | |
sbrs r16, 1 | |
rjmp skip8 | |
andi r16, 0b1101 | |
sts note_on, r16 | |
lds r16, chan2_notes | |
lds r17, chan2_notes + 1 | |
rcall handle_note | |
sts chan2_tpit, r16 | |
sts chan2_tpit + 1, r17 | |
skip8: | |
lds r16, note_on | |
lds r17, chan3_notes + 1 | |
cpi r17, 0x00 | |
breq skip13 | |
ori r16, 0b0100 | |
skip13: | |
sbrs r16, 2 | |
rjmp skip9 | |
andi r16, 0b1011 | |
sts note_on, r16 | |
lds r16, chan3_notes | |
lds r17, chan3_notes + 1 | |
rcall handle_note | |
sts chan3_tpit, r16 | |
sts chan3_tpit + 1, r17 | |
skip9: | |
lds r16, note_on | |
lds r17, chan4_notes + 1 | |
cpi r17, 0x00 | |
breq skip14 | |
ori r16, 0b1000 | |
skip14: | |
sbrs r16, 3 | |
rjmp skip10 | |
andi r16, 0b0111 | |
sts note_on, r16 | |
lds r16, chan4_notes | |
lds r17, chan4_notes + 1 | |
rcall handle_note | |
sts chan4_tpit, r16 | |
sts chan4_tpit + 1, r17 | |
skip10: | |
lds CHAN1_FRQL, chan1_pvib | |
lds CHAN1_FRQH, chan1_pvib + 1 | |
lds CHAN2_FRQL, chan2_pvib | |
lds CHAN2_FRQH, chan2_pvib + 1 | |
lds CHAN3_FRQL, chan3_pvib | |
lds CHAN3_FRQH, chan3_pvib + 1 | |
lds CHAN4_FRQL, chan4_pvib | |
lds CHAN4_FRQH, chan4_pvib + 1 | |
lds r21, slide_timer | |
inc r21 | |
cpi r21, 0x4 | |
brne skip15 | |
clr r21 | |
skip15: | |
sts slide_timer, r21 | |
cpi r21, 0x00 | |
brne skip16 | |
ser r21 | |
rjmp skip17 | |
skip16: | |
clr r21 | |
skip17: | |
lds r20, pit_slide_dir | |
lds r16, chan1_tpit | |
lds r17, chan1_tpit + 1 | |
sbrs r21, 0 | |
rjmp skip18 | |
lds r18, chan1_pit_slide | |
ldi r19, 0x00 | |
sbrc r20, 0 | |
rjmp up1 | |
cpi r17, 0x00 | |
brne down1a | |
cpi r16, 0x00 | |
breq down1 | |
down1a: | |
sbc r16, r18 | |
brcc down1 | |
dec r17 | |
rjmp down1 | |
up1: | |
add r16, r18 | |
adc r17, r19 | |
down1: | |
sts chan1_tpit, r16 | |
sts chan1_tpit + 1, r17 | |
skip18: | |
sbrs r21, 0 | |
rjmp port1 | |
lds r18, chan1_port | |
cpi r18, 0x00 | |
breq skip_port1 | |
mov r23, CHAN1_FRQL | |
cpi r23, 0x00 | |
brne ne1 | |
mov r23, CHAN1_FRQH | |
cpi r23, 0x00 | |
breq skip_port1 | |
ne1: | |
cp CHAN1_FRQH, r17 | |
brlo higher1 | |
cp r17, CHAN1_FRQH | |
brlo lower1 | |
cp CHAN1_FRQL, r16 | |
brlo higher1 | |
cp r16, CHAN1_FRQL | |
brlo lower1 | |
rjmp skip_port1 | |
higher1: | |
ldi r19, 0x00 | |
add CHAN1_FRQL, r18 | |
adc CHAN1_FRQH, r19 | |
cp r17, CHAN1_FRQH | |
brlo skip_port1 | |
cp CHAN1_FRQH, r17 | |
brlo port1 | |
cp r16, CHAN1_FRQL | |
brlo skip_port1 | |
rjmp port1 | |
lower1: | |
clc | |
sbc CHAN1_FRQL, r18 | |
brcc lower1a | |
dec CHAN1_FRQH | |
lower1a: | |
cp CHAN1_FRQH, r17 | |
brlo skip_port1 | |
cp r17, CHAN1_FRQH | |
brlo port1 | |
cp CHAN1_FRQL, r16 | |
brlo skip_port1 | |
rjmp port1 | |
skip_port1: | |
mov CHAN1_FRQL, r16 | |
mov CHAN1_FRQH, r17 | |
port1: | |
lds r16, chan2_tpit | |
lds r17, chan2_tpit + 1 | |
sbrs r21, 0 | |
rjmp skip19 | |
lds r18, chan2_pit_slide | |
ldi r19, 0x00 | |
sbrc r20, 1 | |
rjmp up2 | |
cpi r17, 0x00 | |
brne down2a | |
cpi r16, 0x00 | |
breq down2 | |
down2a: | |
sbc r16, r18 | |
brcc down2 | |
dec r17 | |
rjmp down2 | |
up2: | |
add r16, r18 | |
adc r17, r19 | |
down2: | |
sts chan2_tpit, r16 | |
sts chan2_tpit + 1, r17 | |
skip19: | |
sbrs r21, 0 | |
rjmp port2 | |
lds r18, chan2_port | |
cpi r18, 0x00 | |
breq skip_port2 | |
mov r23, CHAN2_FRQL | |
cpi r23, 0x00 | |
brne ne2 | |
mov r23, CHAN2_FRQH | |
cpi r23, 0x00 | |
breq skip_port2 | |
ne2: | |
cp CHAN2_FRQH, r17 | |
brlo higher2 | |
cp r17, CHAN2_FRQH | |
brlo lower2 | |
cp CHAN2_FRQL, r16 | |
brlo higher2 | |
cp r16, CHAN2_FRQL | |
brlo lower2 | |
rjmp skip_port2 | |
higher2: | |
ldi r19, 0x00 | |
add CHAN2_FRQL, r18 | |
adc CHAN2_FRQH, r19 | |
cp r17, CHAN2_FRQH | |
brlo skip_port2 | |
cp CHAN2_FRQH, r17 | |
brlo port2 | |
cp r16, CHAN2_FRQL | |
brlo skip_port2 | |
rjmp port2 | |
lower2: | |
clc | |
sbc CHAN2_FRQL, r18 | |
brcc lower2a | |
dec CHAN2_FRQH | |
lower2a: | |
cp CHAN2_FRQH, r17 | |
brlo skip_port2 | |
cp r17, CHAN2_FRQH | |
brlo port2 | |
cp CHAN2_FRQL, r16 | |
brlo skip_port2 | |
rjmp port2 | |
skip_port2: | |
mov CHAN2_FRQL, r16 | |
mov CHAN2_FRQH, r17 | |
port2: | |
lds r16, chan3_tpit | |
lds r17, chan3_tpit + 1 | |
sbrs r21, 0 | |
rjmp skip20 | |
lds r18, chan3_pit_slide | |
ldi r19, 0x00 | |
sbrc r20, 2 | |
rjmp up3 | |
cpi r17, 0x00 | |
brne down3a | |
cpi r16, 0x00 | |
breq down3 | |
down3a: | |
sbc r16, r18 | |
brcc down3 | |
dec r17 | |
rjmp down3 | |
up3: | |
add r16, r18 | |
adc r17, r19 | |
down3: | |
sts chan3_tpit, r16 | |
sts chan3_tpit + 1, r17 | |
skip20: | |
sbrs r21, 0 | |
rjmp port3 | |
lds r18, chan3_port | |
cpi r18, 0x00 | |
breq skip_port3 | |
mov r23, CHAN3_FRQL | |
cpi r23, 0x00 | |
brne ne3 | |
mov r23, CHAN3_FRQH | |
cpi r23, 0x00 | |
breq skip_port3 | |
ne3: | |
cp CHAN3_FRQH, r17 | |
brlo higher3 | |
cp r17, CHAN3_FRQH | |
brlo lower3 | |
cp CHAN3_FRQL, r16 | |
brlo higher3 | |
cp r16, CHAN3_FRQL | |
brlo lower3 | |
rjmp skip_port3 | |
higher3: | |
ldi r19, 0x00 | |
add CHAN3_FRQL, r18 | |
adc CHAN3_FRQH, r19 | |
cp r17, CHAN3_FRQH | |
brlo skip_port3 | |
cp CHAN3_FRQH, r17 | |
brlo port3 | |
cp r16, CHAN3_FRQL | |
brlo skip_port3 | |
rjmp port3 | |
lower3: | |
clc | |
sbc CHAN3_FRQL, r18 | |
brcc lower3a | |
dec CHAN3_FRQH | |
lower3a: | |
cp CHAN3_FRQH, r17 | |
brlo skip_port3 | |
cp r17, CHAN3_FRQH | |
brlo port3 | |
cp CHAN3_FRQL, r16 | |
brlo skip_port3 | |
rjmp port3 | |
skip_port3: | |
mov CHAN3_FRQL, r16 | |
mov CHAN3_FRQH, r17 | |
port3: | |
lds r16, chan4_tpit | |
lds r17, chan4_tpit + 1 | |
sbrs r21, 0 | |
rjmp skip21 | |
lds r18, chan4_pit_slide | |
ldi r19, 0x00 | |
sbrc r20, 3 | |
rjmp up4 | |
cpi r17, 0x00 | |
brne down4a | |
cpi r16, 0x00 | |
breq down4 | |
down4a: | |
sbc r16, r18 | |
brcc down4 | |
dec r17 | |
rjmp down4 | |
up4: | |
add r16, r18 | |
adc r17, r19 | |
down4: | |
sts chan4_tpit, r16 | |
sts chan4_tpit + 1, r17 | |
skip21: | |
sbrs r21, 0 | |
rjmp port4 | |
lds r18, chan4_port | |
cpi r18, 0x00 | |
breq skip_port4 | |
mov r23, CHAN4_FRQL | |
cpi r23, 0x00 | |
brne ne4 | |
mov r23, CHAN4_FRQH | |
cpi r23, 0x00 | |
breq skip_port4 | |
ne4: | |
cp CHAN4_FRQH, r17 | |
brlo higher4 | |
cp r17, CHAN4_FRQH | |
brlo lower4 | |
cp CHAN4_FRQL, r16 | |
brlo higher4 | |
cp r16, CHAN4_FRQL | |
brlo lower4 | |
rjmp skip_port4 | |
higher4: | |
ldi r19, 0x00 | |
add CHAN4_FRQL, r18 | |
adc CHAN4_FRQH, r19 | |
cp r17, CHAN4_FRQH | |
brlo skip_port4 | |
cp CHAN4_FRQH, r17 | |
brlo port4 | |
cp r16, CHAN4_FRQL | |
brlo skip_port4 | |
rjmp port4 | |
lower4: | |
clc | |
sbc CHAN4_FRQL, r18 | |
brcc lower4a | |
dec CHAN4_FRQH | |
lower4a: | |
cp CHAN4_FRQH, r17 | |
brlo skip_port4 | |
cp r17, CHAN4_FRQH | |
brlo port4 | |
cp CHAN4_FRQL, r16 | |
brlo skip_port4 | |
rjmp port4 | |
skip_port4: | |
mov CHAN4_FRQL, r16 | |
mov CHAN4_FRQH, r17 | |
port4: | |
sts chan1_pvib, CHAN1_FRQL | |
sts chan1_pvib + 1, CHAN1_FRQH | |
sts chan2_pvib, CHAN2_FRQL | |
sts chan2_pvib + 1, CHAN2_FRQH | |
sts chan3_pvib, CHAN3_FRQL | |
sts chan3_pvib + 1, CHAN3_FRQH | |
sts chan4_pvib, CHAN4_FRQL | |
sts chan4_pvib + 1, CHAN4_FRQH | |
lds r21, vibrato_timer | |
inc r21 | |
cpi r21, 0x8 | |
brne skip27 | |
clr r21 | |
skip27: | |
sts vibrato_timer, r21 | |
push r0 | |
push r1 | |
lds r16, chan1_tvib | |
lds r17, chan1_vib | |
mov r19, r17 | |
andi r17, 0xF0 | |
lsr r17 | |
andi r19, 0x0F | |
cpi r21, 0x00 | |
brne skip26 | |
add r16, r17 | |
sts chan1_tvib, r16 | |
skip26: | |
sbrc r16, 7 | |
com r16 | |
lsr r16 | |
lsr r16 | |
lsr r16 | |
mul r16, r19 | |
mov r16, r0 | |
lsr r16 | |
lsr r16 | |
lsr r16 | |
ldi r19, 0x00 | |
lds r18, chan1_fine | |
add r16, r18 | |
add CHAN1_FRQL, r16 | |
adc CHAN1_FRQH, r19 | |
lds r16, chan2_tvib | |
lds r17, chan2_vib | |
mov r19, r17 | |
andi r17, 0xF0 | |
lsr r17 | |
andi r19, 0x0F | |
cpi r21, 0x00 | |
brne skip30 | |
add r16, r17 | |
sts chan2_tvib, r16 | |
skip30: | |
sbrc r16, 7 | |
com r16 | |
lsr r16 | |
lsr r16 | |
lsr r16 | |
mul r16, r19 | |
mov r16, r0 | |
lsr r16 | |
lsr r16 | |
lsr r16 | |
ldi r19, 0x00 | |
lds r18, chan2_fine | |
add r16, r18 | |
add CHAN2_FRQL, r16 | |
adc CHAN2_FRQH, r19 | |
lds r16, chan3_tvib | |
lds r17, chan3_vib | |
mov r19, r17 | |
andi r17, 0xF0 | |
lsr r17 | |
andi r19, 0x0F | |
cpi r21, 0x00 | |
brne skip28 | |
add r16, r17 | |
sts chan3_tvib, r16 | |
skip28: | |
sbrc r16, 7 | |
com r16 | |
lsr r16 | |
lsr r16 | |
lsr r16 | |
mul r16, r19 | |
mov r16, r0 | |
lsr r16 | |
lsr r16 | |
lsr r16 | |
ldi r19, 0x00 | |
lds r18, chan3_fine | |
add r16, r18 | |
add CHAN3_FRQL, r16 | |
adc CHAN3_FRQH, r19 | |
lds r16, chan4_tvib | |
lds r17, chan4_vib | |
mov r19, r17 | |
andi r17, 0xF0 | |
lsr r17 | |
andi r19, 0x0F | |
cpi r21, 0x00 | |
brne skip29 | |
add r16, r17 | |
sts chan4_tvib, r16 | |
skip29: | |
sbrc r16, 7 | |
com r16 | |
lsr r16 | |
lsr r16 | |
lsr r16 | |
mul r16, r19 | |
mov r16, r0 | |
lsr r16 | |
lsr r16 | |
lsr r16 | |
ldi r19, 0x00 | |
lds r18, chan4_fine | |
add r16, r18 | |
add CHAN4_FRQL, r16 | |
adc CHAN4_FRQH, r19 | |
lds r16, chan1_ttrm | |
lds r17, chan1_trm | |
mov r19, r17 | |
andi r17, 0xF0 | |
lsr r17 | |
andi r19, 0x0F | |
lsl r19 | |
lsl r19 | |
lsl r19 | |
lsl r19 | |
cpi r21, 0x00 | |
brne skip31 | |
add r16, r17 | |
sts chan1_ttrm, r16 | |
skip31: | |
sbrc r16, 7 | |
com r16 | |
lsl r16 | |
mul r16, r19 | |
mov r16, r1 | |
lds r18, chan1_ptrm | |
clc | |
sbc r18, r16 | |
brcc skip32 | |
clr r18 | |
skip32: | |
sts chan1_vol, r18 | |
lds r16, chan2_ttrm | |
lds r17, chan2_trm | |
mov r19, r17 | |
andi r17, 0xF0 | |
lsr r17 | |
andi r19, 0x0F | |
lsl r19 | |
lsl r19 | |
lsl r19 | |
lsl r19 | |
cpi r21, 0x00 | |
brne skip33 | |
add r16, r17 | |
sts chan2_ttrm, r16 | |
skip33: | |
sbrc r16, 7 | |
com r16 | |
lsl r16 | |
mul r16, r19 | |
mov r16, r1 | |
lds r18, chan2_ptrm | |
clc | |
sbc r18, r16 | |
brcc skip34 | |
clr r18 | |
skip34: | |
sts chan2_vol, r18 | |
lds r16, chan3_ttrm | |
lds r17, chan3_trm | |
mov r19, r17 | |
andi r17, 0xF0 | |
lsr r17 | |
andi r19, 0x0F | |
lsl r19 | |
lsl r19 | |
lsl r19 | |
lsl r19 | |
cpi r21, 0x00 | |
brne skip38 | |
add r16, r17 | |
sts chan3_ttrm, r16 | |
skip38: | |
sbrc r16, 7 | |
com r16 | |
lsl r16 | |
mul r16, r19 | |
mov r16, r1 | |
lds r18, chan3_ptrm | |
clc | |
sbc r18, r16 | |
brcc skip35 | |
clr r18 | |
skip35: | |
sts chan3_vol, r18 | |
lds r16, chan4_ttrm | |
lds r17, chan4_trm | |
mov r19, r17 | |
andi r17, 0xF0 | |
lsr r17 | |
andi r19, 0x0F | |
lsl r19 | |
lsl r19 | |
lsl r19 | |
lsl r19 | |
cpi r21, 0x00 | |
brne skip36 | |
add r16, r17 | |
sts chan4_ttrm, r16 | |
skip36: | |
sbrc r16, 7 | |
com r16 | |
lsl r16 | |
mul r16, r19 | |
mov r16, r1 | |
lds r18, chan4_ptrm | |
clc | |
sbc r18, r16 | |
brcc skip37 | |
clr r18 | |
skip37: | |
sts chan4_vol, r18 | |
lds r16, chan1_tpwm | |
lds r17, chan1_pwm | |
mov r19, r17 | |
andi r17, 0xF0 | |
lsr r17 | |
lsr r17 | |
lsr r17 | |
lsr r17 | |
andi r19, 0x0F | |
lsl r19 | |
lsl r19 | |
lsl r19 | |
lsl r19 | |
cpi r21, 0x00 | |
brne skip39 | |
add r16, r17 | |
sts chan1_tpwm, r16 | |
skip39: | |
sbrc r16, 7 | |
com r16 | |
mul r16, r19 | |
mov r16, r1 | |
lds r18, chan1_tdut | |
add r18, r16 | |
sts chan1_dut, r18 | |
lds r16, chan2_tpwm | |
lds r17, chan2_pwm | |
mov r19, r17 | |
andi r17, 0xF0 | |
lsr r17 | |
lsr r17 | |
lsr r17 | |
lsr r17 | |
andi r19, 0x0F | |
lsl r19 | |
lsl r19 | |
lsl r19 | |
lsl r19 | |
cpi r21, 0x00 | |
brne skip40 | |
add r16, r17 | |
sts chan2_tpwm, r16 | |
skip40: | |
sbrc r16, 7 | |
com r16 | |
mul r16, r19 | |
mov r16, r1 | |
lds r18, chan2_tdut | |
add r18, r16 | |
sts chan2_dut, r18 | |
lds r16, chan3_tpwm | |
lds r17, chan3_pwm | |
mov r19, r17 | |
andi r17, 0xF0 | |
lsr r17 | |
lsr r17 | |
lsr r17 | |
lsr r17 | |
andi r19, 0x0F | |
lsl r19 | |
lsl r19 | |
lsl r19 | |
lsl r19 | |
cpi r21, 0x00 | |
brne skip41 | |
add r16, r17 | |
sts chan3_tpwm, r16 | |
skip41: | |
sbrc r16, 7 | |
com r16 | |
mul r16, r19 | |
mov r16, r1 | |
lds r18, chan3_tdut | |
add r18, r16 | |
sts chan3_dut, r18 | |
lds r16, chan4_tpwm | |
lds r17, chan4_pwm | |
mov r19, r17 | |
andi r17, 0xF0 | |
lsr r17 | |
lsr r17 | |
lsr r17 | |
lsr r17 | |
andi r19, 0x0F | |
lsl r19 | |
lsl r19 | |
lsl r19 | |
lsl r19 | |
cpi r21, 0x00 | |
brne skip42 | |
add r16, r17 | |
sts chan4_tpwm, r16 | |
skip42: | |
sbrc r16, 7 | |
com r16 | |
mul r16, r19 | |
mov r16, r1 | |
lds r18, chan4_tdut | |
add r18, r16 | |
sts chan4_dut, r18 | |
pop r1 | |
pop r0 | |
skip: | |
lds r16, tick_timer | |
inc r16 | |
sts tick_timer, r16 | |
pop r23 | |
pop r22 | |
pop r21 | |
pop r20 | |
pop r19 | |
pop r18 | |
pop r17 | |
pop r16 | |
reti | |
handle_note: | |
lds r18, arp_timer | |
inc r18 | |
mov r19, r18 | |
lsr r19 | |
lsr r19 | |
lsr r19 | |
lsr r19 | |
lsr r19 | |
andi r19, 0b11 | |
cpi r19, 0b11 | |
brne skip5 | |
ldi r18, 0x0 | |
skip5: | |
sts arp_timer, r18 | |
sbrc r19, 0 | |
rjmp arp1 | |
sbrc r19, 1 | |
rjmp arp2 | |
rjmp skip6 | |
arp1: | |
andi r17, 0xF0 | |
add r16, r17 | |
brcc skip6 | |
ldi r18, 0x41 | |
add r16, r18 | |
arp2: | |
lsl r17 | |
lsl r17 | |
lsl r17 | |
lsl r17 | |
add r16, r17 | |
brcc skip6 | |
ldi r18, 0x41 | |
add r16, r18 | |
skip6: | |
rjmp note_freq | |
note_freq: | |
mov r19, r16 | |
lsr r16 | |
lsr r16 | |
lsr r16 | |
lsr r16 | |
cpi r16, 0x04 | |
breq setc | |
cpi r16, 0x05 | |
breq setcs | |
cpi r16, 0x06 | |
breq setd | |
cpi r16, 0x07 | |
breq setds | |
cpi r16, 0x08 | |
breq sete | |
cpi r16, 0x09 | |
breq setf | |
cpi r16, 0x0A | |
breq setfs | |
cpi r16, 0x0B | |
breq setg | |
cpi r16, 0x0C | |
breq setgs | |
cpi r16, 0x0D | |
breq seta | |
cpi r16, 0x0E | |
breq setas | |
cpi r16, 0x0F | |
breq setb | |
ret | |
setc: | |
ldi r16, LOW(NOTE_C) | |
ldi r17, HIGH(NOTE_C) | |
rjmp skip4 | |
setcs: | |
ldi r16, LOW(NOTE_Cs) | |
ldi r17, HIGH(NOTE_Cs) | |
rjmp skip4 | |
setd: | |
ldi r16, LOW(NOTE_D) | |
ldi r17, HIGH(NOTE_D) | |
rjmp skip4 | |
setds: | |
ldi r16, LOW(NOTE_Ds) | |
ldi r17, HIGH(NOTE_Ds) | |
rjmp skip4 | |
sete: | |
ldi r16, LOW(NOTE_E) | |
ldi r17, HIGH(NOTE_E) | |
rjmp skip4 | |
setf: | |
ldi r16, LOW(NOTE_F) | |
ldi r17, HIGH(NOTE_F) | |
rjmp skip4 | |
setfs: | |
ldi r16, LOW(NOTE_Fs) | |
ldi r17, HIGH(NOTE_Fs) | |
rjmp skip4 | |
setg: | |
ldi r16, LOW(NOTE_G) | |
ldi r17, HIGH(NOTE_G) | |
rjmp skip4 | |
setgs: | |
ldi r16, LOW(NOTE_Gs) | |
ldi r17, HIGH(NOTE_Gs) | |
rjmp skip4 | |
seta: | |
ldi r16, LOW(NOTE_A) | |
ldi r17, HIGH(NOTE_A) | |
rjmp skip4 | |
setas: | |
ldi r16, LOW(NOTE_As) | |
ldi r17, HIGH(NOTE_As) | |
rjmp skip4 | |
setb: | |
ldi r16, LOW(NOTE_B) | |
ldi r17, HIGH(NOTE_B) | |
rjmp skip4 | |
skip4: | |
andi r19, 0x0F | |
cpi r19, 0x01 | |
breq seto1 | |
cpi r19, 0x02 | |
breq seto2 | |
cpi r19, 0x03 | |
breq seto3 | |
cpi r19, 0x04 | |
breq seto4 | |
cpi r19, 0x05 | |
breq seto5 | |
cpi r19, 0x06 | |
breq seto6 | |
cpi r19, 0x07 | |
breq seto7 | |
cpi r19, 0x08 | |
breq seto8 | |
ret | |
seto1: | |
lsr r17 | |
ror r16 | |
lsr r17 | |
ror r16 | |
lsr r17 | |
ror r16 | |
ret | |
seto2: | |
lsr r17 | |
ror r16 | |
lsr r17 | |
ror r16 | |
ret | |
seto3: | |
lsr r17 | |
ror r16 | |
ret | |
seto4: | |
ret | |
seto5: | |
lsl r16 | |
rol r17 | |
ret | |
seto6: | |
lsl r16 | |
rol r17 | |
lsl r16 | |
rol r17 | |
ret | |
seto7: | |
lsl r16 | |
rol r17 | |
lsl r16 | |
rol r17 | |
lsl r16 | |
rol r17 | |
ret | |
seto8: | |
lsl r16 | |
rol r17 | |
lsl r16 | |
rol r17 | |
lsl r16 | |
rol r17 | |
lsl r16 | |
rol r17 | |
ret | |
generate: | |
clr r17 | |
cpi r18, 0b00 | |
breq gen_pulse | |
cpi r18, 0b01 | |
breq gen_triangle | |
cpi r18, 0b10 | |
breq gen_saw | |
cpi r18, 0b11 | |
breq gen_noise | |
ret | |
gen_pulse: | |
cp r19, r21 | |
brlo return | |
mov r17, r20 | |
lsr r17 | |
lsr r17 | |
return: | |
ret | |
gen_triangle: | |
mov r17, r19 | |
sbrc r19, 7 | |
com r17 | |
rjmp apply_volume | |
ret | |
gen_saw: | |
mov r17, r19 | |
lsr r17 | |
lsr r17 | |
rjmp apply_volume | |
ret | |
gen_noise: | |
clr r21 | |
clr r19 | |
sbrc NOISEH, 6 | |
ser r21 | |
sbrc NOISEL, 3 | |
ser r19 | |
eor r19, r21 | |
clr r21 | |
lsl NOISEH | |
lsl NOISEL | |
adc NOISEH, r21 | |
sbrc r19, 0 | |
inc NOISEL | |
mov r17, NOISEL | |
lsr r17 | |
rjmp apply_volume | |
ret | |
apply_volume: | |
push r0 | |
push r1 | |
mul r17, r20 | |
mov r17, r1 | |
pop r1 | |
pop r0 | |
ret | |
.dseg | |
command_buf: .byte 2 | |
chan1_vol: .byte 1 | |
chan2_vol: .byte 1 | |
chan3_vol: .byte 1 | |
chan4_vol: .byte 1 | |
chan1_dut: .byte 1 | |
chan2_dut: .byte 1 | |
chan3_dut: .byte 1 | |
chan4_dut: .byte 1 | |
waveform: .byte 1 | |
enable: .byte 1 | |
tick_timer: .byte 1 | |
arp_timer: .byte 1 | |
slide_timer: .byte 1 | |
vibrato_timer: .byte 1 | |
note_on: .byte 1 | |
; 0 - 3: note | |
; 4 - 7: octave | |
; 8 - 11: arp 1 | |
; 12 - 15: arp 2 | |
chan1_notes: .byte 2 | |
chan2_notes: .byte 2 | |
chan3_notes: .byte 2 | |
chan4_notes: .byte 2 | |
chan1_tpit: .byte 2 | |
chan2_tpit: .byte 2 | |
chan3_tpit: .byte 2 | |
chan4_tpit: .byte 2 | |
chan1_tvol: .byte 1 | |
chan2_tvol: .byte 1 | |
chan3_tvol: .byte 1 | |
chan4_tvol: .byte 1 | |
chan1_tdut: .byte 1 | |
chan2_tdut: .byte 1 | |
chan3_tdut: .byte 1 | |
chan4_tdut: .byte 1 | |
; 0 - down | |
; 1 - up | |
vol_slide_dir: .byte 1 | |
pit_slide_dir: .byte 1 | |
chan1_vol_slide: .byte 1 | |
chan2_vol_slide: .byte 1 | |
chan3_vol_slide: .byte 1 | |
chan4_vol_slide: .byte 1 | |
chan1_pit_slide: .byte 1 | |
chan2_pit_slide: .byte 1 | |
chan3_pit_slide: .byte 1 | |
chan4_pit_slide: .byte 1 | |
chan1_port: .byte 1 | |
chan2_port: .byte 1 | |
chan3_port: .byte 1 | |
chan4_port: .byte 1 | |
; 0 - 3: rate | |
; 4 - 7: depth | |
chan1_vib: .byte 1 | |
chan2_vib: .byte 1 | |
chan3_vib: .byte 1 | |
chan4_vib: .byte 1 | |
chan1_trm: .byte 1 | |
chan2_trm: .byte 1 | |
chan3_trm: .byte 1 | |
chan4_trm: .byte 1 | |
chan1_pwm: .byte 1 | |
chan2_pwm: .byte 1 | |
chan3_pwm: .byte 1 | |
chan4_pwm: .byte 1 | |
chan1_pvib: .byte 2 | |
chan2_pvib: .byte 2 | |
chan3_pvib: .byte 2 | |
chan4_pvib: .byte 2 | |
chan1_ptrm: .byte 2 | |
chan2_ptrm: .byte 2 | |
chan3_ptrm: .byte 2 | |
chan4_ptrm: .byte 2 | |
chan1_tvib: .byte 1 | |
chan2_tvib: .byte 1 | |
chan3_tvib: .byte 1 | |
chan4_tvib: .byte 1 | |
chan1_ttrm: .byte 1 | |
chan2_ttrm: .byte 1 | |
chan3_ttrm: .byte 1 | |
chan4_ttrm: .byte 1 | |
chan1_tpwm: .byte 1 | |
chan2_tpwm: .byte 1 | |
chan3_tpwm: .byte 1 | |
chan4_tpwm: .byte 1 | |
; 0 - 3: attack | |
; 4 - 7: decay | |
; 8 - 11: sustain | |
; 12 - 15: release | |
chan1_env: .byte 2 | |
chan2_env: .byte 2 | |
chan3_env: .byte 2 | |
chan4_env: .byte 2 | |
chan1_fine: .byte 1 | |
chan2_fine: .byte 1 | |
chan3_fine: .byte 1 | |
chan4_fine: .byte 1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Feature complete! | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <time.h> | |
#include <ncurses.h> | |
#define NOTE_NULL 0x0 | |
#define NOTE_RESET 0x1 | |
#define NOTE_ON 0x2 | |
#define NOTE_OFF 0x3 | |
#define NOTE_C 0x4 | |
#define NOTE_Cs 0x5 | |
#define NOTE_Db 0x5 | |
#define NOTE_D 0x6 | |
#define NOTE_Ds 0x7 | |
#define NOTE_Eb 0x7 | |
#define NOTE_E 0x8 | |
#define NOTE_F 0x9 | |
#define NOTE_Fs 0xA | |
#define NOTE_Gb 0xA | |
#define NOTE_G 0xB | |
#define NOTE_Gs 0xC | |
#define NOTE_Ab 0xC | |
#define NOTE_A 0xD | |
#define NOTE_As 0xE | |
#define NOTE_Bb 0xE | |
#define NOTE_B 0xF | |
#define EFF_ARPEGGIO 0x0 | |
#define EFF_PITCH_SLIDE_UP 0x1 | |
#define EFF_PITCH_SLIDE_DOWN 0x2 | |
#define EFF_PORTAMENTO 0x3 | |
#define EFF_VIBRATO 0x4 | |
#define EFF_WAVEFORM 0x5 | |
#define EFF_DUTY_CYCLE 0x6 | |
#define EFF_TREMOLO 0x7 | |
#define EFF_PWM 0x8 | |
#define EFF_PITCH 0x9 | |
#define EFF_VOLUME_SLIDE_UP 0xA | |
#define EFF_VOLUME_SLIDE_DOWN 0xB | |
#define EFF_VOLUME 0xC | |
#define EFF_ENVELOPE_ATTACK_DECAY 0xD | |
#define EFF_ENVELOPE_SUSTAIN_RELEASE 0xE | |
#define EFF_FINE_TUNE 0xF | |
FILE *out; | |
char serialPort[255]; | |
typedef struct | |
{ | |
unsigned char enable; | |
unsigned char effect; | |
unsigned char argument; | |
} Effect; | |
typedef struct | |
{ | |
unsigned char note; | |
unsigned char octave; | |
unsigned char volume; | |
unsigned char applyInstrument; | |
unsigned char instrument; | |
} NoteCommand; | |
typedef struct | |
{ | |
NoteCommand noteCommand; | |
Effect effect; | |
} Entry; | |
typedef struct | |
{ | |
Entry entries[4]; | |
} Frame; | |
typedef struct | |
{ | |
Effect effects[8]; | |
} Instrument; | |
typedef struct | |
{ | |
Frame frames[32]; | |
} Order; | |
typedef struct | |
{ | |
unsigned char fps; | |
unsigned char orderCount; | |
unsigned char repeat; | |
unsigned char instrumentCount; | |
Instrument *instruments; | |
Order *orders; | |
} Song; | |
Song song; | |
void printTabs(int tabs) | |
{ | |
int i; | |
for(i = 0; i < tabs; i++) | |
{ | |
printf("\t"); | |
} | |
} | |
void printEffect(Effect *effect, int tabs) | |
{ | |
int s1, s2; | |
s1 = (effect->argument) >> 4; | |
s2 = (effect->argument) & 0x0F; | |
printTabs(tabs); | |
if(effect->enable) | |
{ | |
switch(effect->effect) | |
{ | |
case 0x0: | |
if(s1 || s2) | |
{ | |
printf("Arpeggio: Semitones: %i, %i\n", s1, s2); | |
} | |
else | |
{ | |
printf("Arpeggio Off\n"); | |
} | |
break; | |
case 0x1: | |
printf("Pitch Slide Up: Rate: %i\n", effect->argument); | |
break; | |
case 0x2: | |
printf("Pitch Slide Down: Rate: %i\n", effect->argument); | |
break; | |
case 0x3: | |
if(effect->argument) | |
{ | |
printf("Portamento: Rate: %i\n", effect->argument); | |
} | |
else | |
{ | |
printf("Portamento Off"); | |
} | |
break; | |
case 0x4: | |
printf("Vibrato: Rate: %i, Depth: %i\n", s1, s2); | |
break; | |
case 0x5: | |
printf("Waveform: "); | |
switch(effect->argument) | |
{ | |
case 0: | |
printf("Pulse\n"); | |
break; | |
case 1: | |
printf("Triangle\n"); | |
break; | |
case 2: | |
printf("Sawtooth\n"); | |
break; | |
case 3: | |
printf("Noise\n"); | |
break; | |
default: | |
printf("Unknown\n"); | |
} | |
break; | |
case 0x6: | |
printf("Duty Cycle: %i\%\n", effect->argument / 256 * 100); | |
break; | |
case 0x7: | |
printf("Tremolo: Rate: %i, Depth: %i\n", s1, s2); | |
break; | |
case 0x8: | |
printf("Pulse Width Modulation: Rate: %i, Depth: %i\n", s1, s2); | |
break; | |
case 0x9: | |
printf("Pitch: %i\n", effect->argument); | |
break; | |
case 0xA: | |
printf("Volume Slide Up: Rate: %i\n", effect->argument); | |
break; | |
case 0xB: | |
printf("Volume Slide Down: Rate: %i\n", effect->argument); | |
break; | |
case 0xC: | |
printf("Volume: %i\n", effect->argument); | |
break; | |
case 0xD: | |
printf("Envelope: Attack: %i, Decay: %i\n", s1, s2); | |
break; | |
case 0xE: | |
printf("Envelope: Sustain: %i\%, Release: %i\n", s1 / 16 * 100, s2); | |
break; | |
case 0xF: | |
printf("Fine Tune: %i\n", effect->argument); | |
break; | |
default: | |
printf("Unknown Effect\n"); | |
} | |
} | |
else | |
{ | |
printf("No Effect\n"); | |
} | |
} | |
void printInstrumentInfo(Instrument *instrument, int tabs) | |
{ | |
int i; | |
for(i = 0; i < sizeof(instrument->effects) / sizeof(Effect); i++) | |
{ | |
printTabs(tabs); | |
printf("Effect #%i:\n", i + 1); | |
printEffect(&(instrument->effects[i]), tabs + 1); | |
} | |
} | |
void printNote(unsigned char note, unsigned char octave, int tabs) | |
{ | |
printTabs(tabs); | |
switch(note) | |
{ | |
case 0x0: | |
printf("No Note\n"); | |
break; | |
case 0x1: | |
printf("Reset Oscillator Timer\n"); | |
break; | |
case 0x2: | |
printf("Enable Oscillator\n"); | |
break; | |
case 0x3: | |
printf("Disable Oscillator\n"); | |
break; | |
case 0x4: | |
printf("Play Note C%i\n", octave); | |
break; | |
case 0x5: | |
printf("Play Note C#%i\n", octave); | |
break; | |
case 0x6: | |
printf("Play Note D%i\n", octave); | |
break; | |
case 0x7: | |
printf("Play Note D#%i\n", octave); | |
break; | |
case 0x8: | |
printf("Play Note E%i\n", octave); | |
break; | |
case 0x9: | |
printf("Play Note F%i\n", octave); | |
break; | |
case 0xA: | |
printf("Play Note F#%i\n", octave); | |
break; | |
case 0xB: | |
printf("Play Note G%i\n", octave); | |
break; | |
case 0xC: | |
printf("Play Note G#%i\n", octave); | |
break; | |
case 0xD: | |
printf("Play Note A%i\n", octave); | |
break; | |
case 0xE: | |
printf("Play Note A#%i\n", octave); | |
break; | |
case 0xF: | |
printf("Play Note B%i\n", octave); | |
break; | |
default: | |
printf("Unknown Command\n"); | |
} | |
} | |
void printVolume(unsigned char volume, int tabs) | |
{ | |
printTabs(tabs); | |
if(volume) | |
{ | |
printf("Volume: %i\%\n", volume / 32 * 100); | |
} | |
else | |
{ | |
printf("Ignore Volume\n"); | |
} | |
} | |
void printInstrumentID(unsigned char applyInstrument, unsigned char instrument, int tabs) | |
{ | |
printTabs(tabs); | |
if(applyInstrument) | |
{ | |
printf("Apply Instrument #%i\n", instrument + 1); | |
} | |
else | |
{ | |
printf("Ignore Instrument\n"); | |
} | |
} | |
void printNoteCommand(NoteCommand *noteCommand, int tabs) | |
{ | |
printNote(noteCommand->note, noteCommand->octave, tabs); | |
printVolume(noteCommand->volume, tabs); | |
printInstrumentID(noteCommand->applyInstrument, noteCommand->instrument, tabs); | |
} | |
void printEntry(Entry *entry, int tabs) | |
{ | |
printNoteCommand(&(entry->noteCommand), tabs); | |
printEffect(&(entry->effect), tabs); | |
} | |
void printFrame(Frame *frame, int tabs) | |
{ | |
int i; | |
for(i = 0; i < sizeof(frame->entries) / sizeof(Entry); i++) | |
{ | |
printTabs(tabs); | |
printf("Channel #%i:\n", i + 1); | |
printEntry(&(frame->entries[i]), tabs + 1); | |
} | |
} | |
void printOrderInfo(Order *order, int tabs) | |
{ | |
int i; | |
for(i = 0; i < sizeof(order->frames) / sizeof(Frame); i++) | |
{ | |
printTabs(tabs); | |
printf("Frame #%i:\n", i + 1); | |
printFrame(&(order->frames[i]), tabs + 1); | |
} | |
} | |
void printSongInfo(Song *song) | |
{ | |
printf("Speed: %i FPS\n", song->fps); | |
printf("Length: %i Orders\n", song->orderCount); | |
printf("Repeat: Order #%i\n", song->repeat + 1); | |
printf("Instrument Count: %i\n", song->instrumentCount); | |
printf("Instruments:\n"); | |
int i; | |
for(i = 0; i < song->instrumentCount; i++) | |
{ | |
printf("\tInstrument #%i:\n", i + 1); | |
printInstrumentInfo(&(song->instruments[0]), 2); | |
} | |
printf("Orders:\n"); | |
for(i = 0; i < song->orderCount; i++) | |
{ | |
printf("\tOrder #%i:\n", i + 1); | |
printOrderInfo(&(song->orders[0]), 2); | |
} | |
} | |
void playNote(unsigned char note, unsigned char octave, unsigned char volume, unsigned char osc) | |
{ | |
note &= 0x0F; | |
octave &= 0b00000111; | |
volume &= 0b00011110; // weird bug causing the last bit to make the octave go really high | |
osc &= 0b00000011; | |
char highByte = (octave >> 1) | (volume << 2) | (1 << 7); | |
char lowByte = (osc << 1) | (note << 3) | (octave << 7); | |
fputc(highByte, out); | |
fputc(lowByte, out); | |
fputc(0xFF, out); | |
fclose(out); | |
out = fopen(serialPort, "w"); | |
} | |
void playEffect(unsigned char effect, unsigned char argument, unsigned char osc) | |
{ | |
effect &= 0x0F; | |
osc &= 0b00000011; | |
char highByte = (argument >> 1) | (1 << 7); | |
char lowByte = 1 | (osc << 1) | (effect << 3) | (argument << 7); | |
fputc(highByte, out); | |
fputc(lowByte, out); | |
fputc(0xFF, out); | |
fclose(out); | |
out = fopen(serialPort, "w"); | |
} | |
void sendEffectCommand(Effect *effect, unsigned char osc) | |
{ | |
if(effect->enable) | |
{ | |
playEffect(effect->effect, effect->argument, osc); | |
} | |
} | |
void sendNoteCommand(NoteCommand *noteCommand, unsigned char osc) | |
{ | |
if(noteCommand->note || noteCommand->octave || noteCommand->volume) | |
{ | |
if(noteCommand->applyInstrument) | |
{ | |
int i; | |
for(i = 0; i < 8; i++) | |
{ | |
Effect effect = song.instruments[noteCommand->instrument].effects[i]; | |
sendEffectCommand(&effect, osc); | |
} | |
} | |
playNote(noteCommand->note, noteCommand->octave, noteCommand->volume, osc); | |
} | |
} | |
void playEntry(Entry *entry, unsigned char osc) | |
{ | |
sendEffectCommand(&entry->effect, osc); | |
sendNoteCommand(&entry->noteCommand, osc); | |
} | |
void playFrame(Frame *frame) | |
{ | |
playEntry(&frame->entries[0], 0); | |
playEntry(&frame->entries[1], 1); | |
playEntry(&frame->entries[2], 2); | |
playEntry(&frame->entries[3], 3); | |
} | |
NoteCommand newNoteCommand(unsigned char note, unsigned char octave, unsigned char volume, unsigned char applyInstrument, unsigned char instrument) | |
{ | |
NoteCommand command; | |
command.note = note; | |
command.octave = octave; | |
command.volume = volume; | |
command.applyInstrument = applyInstrument; | |
command.instrument = instrument; | |
return command; | |
} | |
NoteCommand newSimpleNoteCommand(unsigned char note, unsigned char octave, unsigned char volume) | |
{ | |
return newNoteCommand(note, octave, volume, 0, 0); | |
} | |
NoteCommand newSimplestNoteCommand(unsigned char note, unsigned char octave) | |
{ | |
return newSimpleNoteCommand(note, octave, 0); | |
} | |
NoteCommand newNullNoteCommand() | |
{ | |
return newSimplestNoteCommand(NOTE_NULL, 0); | |
} | |
NoteCommand newResetNoteCommand() | |
{ | |
return newSimplestNoteCommand(NOTE_RESET, 0); | |
} | |
NoteCommand newNoteOnCommand() | |
{ | |
return newSimplestNoteCommand(NOTE_ON, 0); | |
} | |
NoteCommand newNoteOffCommand() | |
{ | |
return newSimplestNoteCommand(NOTE_OFF, 0); | |
} | |
Effect newEffect(unsigned char effect, unsigned char argument) | |
{ | |
Effect new_effect; | |
new_effect.enable = 1; | |
new_effect.effect = effect; | |
new_effect.argument = argument; | |
return new_effect; | |
} | |
Effect newNullEffect() | |
{ | |
Effect effect; | |
effect.enable = 0; | |
effect.effect = 0; | |
effect.argument = 0; | |
return effect; | |
} | |
Entry newEntry(NoteCommand command, Effect effect) | |
{ | |
Entry entry; | |
entry.noteCommand = command; | |
entry.effect = effect; | |
return entry; | |
} | |
Entry newSimpleEntry(NoteCommand command) | |
{ | |
return newEntry(command, newNullEffect()); | |
} | |
Entry newNullEntry() | |
{ | |
return newEntry(newNullNoteCommand(), newNullEffect()); | |
} | |
Frame newFrame(Entry entry1, Entry entry2, Entry entry3, Entry entry4) | |
{ | |
Frame frame; | |
frame.entries[0] = entry1; | |
frame.entries[1] = entry2; | |
frame.entries[2] = entry3; | |
frame.entries[3] = entry4; | |
return frame; | |
} | |
Frame newUnisonFrame(Entry entry) | |
{ | |
return newFrame(entry, entry, entry, entry); | |
} | |
Frame newQuietFrame() | |
{ | |
return newUnisonFrame(newSimpleEntry(newNoteOffCommand())); | |
} | |
Order *newEmptyOrder() | |
{ | |
Order *order; | |
int i; | |
for(i = 0; i < sizeof(order->frames) / sizeof(Frame); i++) | |
{ | |
order->frames[i] = newQuietFrame(); | |
} | |
return order; | |
} | |
WINDOW *orderWindow; | |
WINDOW *instrumentWindow; | |
WINDOW *effectWindow; | |
WINDOW *trackerWindow; | |
int w1, w2, h1, h2; | |
#define WIN_ORDER 0 | |
#define WIN_INSTR 1 | |
#define WIN_EFFECT 2 | |
#define WIN_TRACKER 3 | |
int curWindow = WIN_TRACKER; | |
#define MODE_EDIT 0 | |
#define MODE_PLAY 1 | |
#define MODE_JAM 2 | |
int curMode = MODE_EDIT; | |
#define MAX_ORDERS 64 | |
#define MAX_INSTRUMENTS 16 | |
int curOrder = 0; | |
int curInstrument = 0; | |
int curEffect = 0; | |
int orderScroll = 0; | |
int instrumentScroll = 0; | |
int curOsc = 0; | |
int curFrame = 0; | |
int curCol = 0; | |
int trackerScroll = 0; | |
int curOctave = 4; | |
void placeCursor() | |
{ | |
move(LINES - 1, COLS - 1); | |
} | |
void printTitle(WINDOW *window, char *title) | |
{ | |
int h, w; | |
getmaxyx(window, h, w); | |
wattron(window, A_BOLD); | |
mvwprintw(window, 0,( w - strlen(title)) / 2, "%s", title); | |
} | |
void drawOrderWindow() | |
{ | |
wclear(orderWindow); | |
wattrset(orderWindow, A_NORMAL); | |
if(curWindow == WIN_ORDER && curMode == MODE_EDIT) wattrset(orderWindow, A_REVERSE); | |
box(orderWindow, 0, 0); | |
char t[20]; | |
sprintf(t, "Orders (%i)", song.orderCount); | |
printTitle(orderWindow, t); | |
wattrset(orderWindow, A_NORMAL); | |
int i; | |
int a; | |
for(i = orderScroll; i < song.orderCount && i < h1 - 2 + orderScroll; i++) | |
{ | |
wattrset(orderWindow, curOrder == i ? A_REVERSE : A_NORMAL); | |
for(a = 0; a < w1 - 2; a++) | |
{ | |
mvwprintw(orderWindow, i + 1 - orderScroll, a + 1, " "); | |
} | |
mvwprintw(orderWindow, i + 1 - orderScroll, 1, "%c 0x%x: ", song.repeat == i ? '*' : ' ', i); | |
} | |
wrefresh(orderWindow); | |
placeCursor(); | |
} | |
void drawInstrumentWindow() | |
{ | |
wclear(instrumentWindow); | |
wattrset(instrumentWindow, A_NORMAL); | |
if(curWindow == WIN_INSTR && curMode == MODE_EDIT) wattrset(instrumentWindow, A_REVERSE); | |
box(instrumentWindow, 0, 0); | |
char t[20]; | |
sprintf(t, "Instruments (%i)", song.instrumentCount); | |
printTitle(instrumentWindow, t); | |
wattrset(instrumentWindow, A_NORMAL); | |
int i; | |
int a; | |
for(i = instrumentScroll; i < song.instrumentCount && i < h1 - 2 + instrumentScroll; i++) | |
{ | |
wattrset(instrumentWindow, curInstrument == i ? A_REVERSE : A_NORMAL); | |
for(a = 0; a < w1 - 2; a++) | |
{ | |
mvwprintw(instrumentWindow, i + 1 - instrumentScroll, a + 1, " "); | |
} | |
mvwprintw(instrumentWindow, i + 1 - instrumentScroll, 1, "0x%x: ", i); | |
} | |
wrefresh(instrumentWindow); | |
placeCursor(); | |
} | |
void drawEffectWindow() | |
{ | |
wclear(effectWindow); | |
wattrset(effectWindow, A_NORMAL); | |
if(curWindow == WIN_EFFECT && curMode == MODE_EDIT) wattrset(effectWindow, A_REVERSE); | |
box(effectWindow, 0, 0); | |
printTitle(effectWindow, "Effects"); | |
wattrset(effectWindow, A_NORMAL); | |
Instrument *instrument = &song.instruments[curInstrument]; | |
int i; | |
int a; | |
for(i = 0; i < sizeof(instrument->effects) / sizeof(Effect); i++) | |
{ | |
Effect effect = instrument->effects[i]; | |
wattrset(effectWindow, curEffect == i ? A_REVERSE : A_NORMAL); | |
for(a = 0; a < w1 - 2; a++) | |
{ | |
mvwprintw(effectWindow, i + 1, a + 1, " "); | |
} | |
if(!effect.enable) | |
{ | |
mvwprintw(effectWindow, i + 1, 1, "0x%x: DISABLED", i); | |
} | |
else | |
{ | |
char eff[20]; | |
switch(effect.effect) | |
{ | |
case 0x0: | |
strcpy(eff, "ARPEGGIO: "); | |
break; | |
case 0x1: | |
strcpy(eff, "PORT UP: "); | |
break; | |
case 0x2: | |
strcpy(eff, "PORT DOWN: "); | |
break; | |
case 0x3: | |
strcpy(eff, "PORTAMENTO:"); | |
break; | |
case 0x4: | |
strcpy(eff, "VIBRATO: "); | |
break; | |
case 0x5: | |
strcpy(eff, "WAVEFORM: "); | |
break; | |
case 0x6: | |
strcpy(eff, "DUTY CYCLE:"); | |
break; | |
case 0x7: | |
strcpy(eff, "TREMOLO: "); | |
break; | |
case 0x8: | |
strcpy(eff, "PWM: "); | |
break; | |
case 0x9: | |
strcpy(eff, "PITCH: "); | |
break; | |
case 0xA: | |
strcpy(eff, "VOL UP: "); | |
break; | |
case 0xB: | |
strcpy(eff, "VOL DOWN: "); | |
break; | |
case 0xC: | |
strcpy(eff, "SET VOL: "); | |
break; | |
case 0xD: | |
strcpy(eff, "ATCK/DECAY:"); | |
break; | |
case 0xE: | |
strcpy(eff, "SUS/RELEAS:"); | |
break; | |
case 0xF: | |
strcpy(eff, "FINE TUNE: "); | |
break; | |
} | |
mvwprintw(effectWindow, i + 1, 1, "0x%x: (0x%x) %s 0x%x%x", i, effect.effect, eff, (effect.argument & 0xF0) >> 4, effect.argument & 0xF); | |
} | |
} | |
wrefresh(effectWindow); | |
placeCursor(); | |
} | |
void drawTrackerWindow() | |
{ | |
wclear(trackerWindow); | |
wattrset(trackerWindow, A_NORMAL); | |
if(curWindow == WIN_TRACKER && curMode == MODE_EDIT) wattrset(trackerWindow, A_REVERSE); | |
wattron(trackerWindow, A_BOLD); | |
box(trackerWindow, 0, 0); | |
wattroff(trackerWindow, A_BOLD); | |
printTitle(trackerWindow, "Tracker"); | |
wattrset(trackerWindow, A_NORMAL); | |
int i; | |
for(i = -2 + trackerScroll; i <= 32 && i < h2 - 4 + trackerScroll; i++) | |
{ | |
wattrset(trackerWindow, A_BOLD); | |
if(i - trackerScroll >= 0 && i - trackerScroll < 32) | |
{ | |
if(curFrame == i) wattron(trackerWindow, A_REVERSE); | |
mvwprintw(trackerWindow, i + 3 - trackerScroll, 1, "0x%x%x ", (i & 0xF0) >> 4, i & 0xF); | |
} | |
else if(i - trackerScroll == -2) | |
{ | |
mvwprintw(trackerWindow, i + 3 - trackerScroll, 1, "(0x%x)", curOrder); | |
} | |
else if(i - trackerScroll == -1 || i == 32) | |
{ | |
wattrset(trackerWindow, A_NORMAL); | |
wmove(trackerWindow, i + 3 - trackerScroll, 1); | |
int a; | |
for(a = 0; a < 5; a++) | |
{ | |
waddch(trackerWindow, ACS_HLINE); | |
} | |
} | |
wattrset(trackerWindow, A_NORMAL); | |
waddch(trackerWindow, ACS_VLINE); | |
int a; | |
for(a = 0; a < 4; a++) | |
{ | |
if(i - trackerScroll == -2) | |
{ | |
wattrset(trackerWindow, A_BOLD); | |
if(curOsc == a) wattron(trackerWindow, A_REVERSE); | |
mvwprintw(trackerWindow, i + 3 - trackerScroll, a * 10 + 7, "Osc #%i ", a + 1); | |
wattrset(trackerWindow, A_NORMAL); | |
} | |
else if(i - trackerScroll == -1 || i == 32) | |
{ | |
wmove(trackerWindow, i + 3 - trackerScroll, a * 10 + 7); | |
int a; | |
for(a = 0; a < 9; a++) | |
{ | |
waddch(trackerWindow, ACS_HLINE); | |
} | |
} | |
else | |
{ | |
Entry entry = song.orders[curOrder].frames[i].entries[a]; | |
wattrset(trackerWindow, curFrame == i && curOsc == a && curCol == 0 ? A_REVERSE : A_NORMAL); | |
switch(entry.noteCommand.note) | |
{ | |
case 0x0: | |
mvwprintw(trackerWindow, i + 3 - trackerScroll, a * 10 + 7, "---"); | |
break; | |
case 0x1: | |
mvwprintw(trackerWindow, i + 3 - trackerScroll, a * 10 + 7, "RES"); | |
break; | |
case 0x2: | |
mvwprintw(trackerWindow, i + 3 - trackerScroll, a * 10 + 7, "+++"); | |
break; | |
case 0x3: | |
mvwprintw(trackerWindow, i + 3 - trackerScroll, a * 10 + 7, "xxx"); | |
break; | |
case 0x4: | |
mvwprintw(trackerWindow, i + 3 - trackerScroll, a * 10 + 7, "C-%x", entry.noteCommand.octave); | |
break; | |
case 0x5: | |
mvwprintw(trackerWindow, i + 3 - trackerScroll, a * 10 + 7, "C#%x", entry.noteCommand.octave); | |
break; | |
case 0x6: | |
mvwprintw(trackerWindow, i + 3 - trackerScroll, a * 10 + 7, "D-%x", entry.noteCommand.octave); | |
break; | |
case 0x7: | |
mvwprintw(trackerWindow, i + 3 - trackerScroll, a * 10 + 7, "D#%x", entry.noteCommand.octave); | |
break; | |
case 0x8: | |
mvwprintw(trackerWindow, i + 3 - trackerScroll, a * 10 + 7, "E-%x", entry.noteCommand.octave); | |
break; | |
case 0x9: | |
mvwprintw(trackerWindow, i + 3 - trackerScroll, a * 10 + 7, "F-%x", entry.noteCommand.octave); | |
break; | |
case 0xA: | |
mvwprintw(trackerWindow, i + 3 - trackerScroll, a * 10 + 7, "F#%x", entry.noteCommand.octave); | |
break; | |
case 0xB: | |
mvwprintw(trackerWindow, i + 3 - trackerScroll, a * 10 + 7, "G-%x", entry.noteCommand.octave); | |
break; | |
case 0xC: | |
mvwprintw(trackerWindow, i + 3 - trackerScroll, a * 10 + 7, "G#%x", entry.noteCommand.octave); | |
break; | |
case 0xD: | |
mvwprintw(trackerWindow, i + 3 - trackerScroll, a * 10 + 7, "A-%x", entry.noteCommand.octave); | |
break; | |
case 0xE: | |
mvwprintw(trackerWindow, i + 3 - trackerScroll, a * 10 + 7, "A#%x", entry.noteCommand.octave); | |
break; | |
case 0xF: | |
mvwprintw(trackerWindow, i + 3 - trackerScroll, a * 10 + 7, "B-%x", entry.noteCommand.octave); | |
break; | |
} | |
wattrset(trackerWindow, curFrame == i && curOsc == a && curCol == 1 ? A_REVERSE : A_NORMAL); | |
if(entry.noteCommand.applyInstrument) | |
{ | |
wprintw(trackerWindow, "%x", entry.noteCommand.instrument); | |
} | |
else | |
{ | |
wprintw(trackerWindow, "-", entry.noteCommand.instrument); | |
} | |
wattrset(trackerWindow, curFrame == i && curOsc == a && curCol == 2 ? A_REVERSE : A_NORMAL); | |
if(entry.noteCommand.volume) | |
{ | |
wprintw(trackerWindow, "%x%x", entry.noteCommand.volume >> 4, entry.noteCommand.volume & 0xF); | |
} | |
else | |
{ | |
wprintw(trackerWindow, "--"); | |
} | |
if(entry.effect.enable) | |
{ | |
wattrset(trackerWindow, curFrame == i && curOsc == a && curCol == 3 ? A_REVERSE : A_NORMAL); | |
wprintw(trackerWindow, "%x", entry.effect.effect & 0xF); | |
wattrset(trackerWindow, curFrame == i && curOsc == a && curCol == 4 ? A_REVERSE : A_NORMAL); | |
wprintw(trackerWindow, "%x%x", entry.effect.argument >> 4, entry.effect.argument & 0xF); | |
} | |
else | |
{ | |
wattrset(trackerWindow, curFrame == i && curOsc == a && curCol == 3 ? A_REVERSE : A_NORMAL); | |
wprintw(trackerWindow, "-"); | |
wattrset(trackerWindow, curFrame == i && curOsc == a && curCol == 4 ? A_REVERSE : A_NORMAL); | |
wprintw(trackerWindow, "--"); | |
} | |
} | |
wattrset(trackerWindow, A_NORMAL); | |
waddch(trackerWindow, ACS_VLINE); | |
} | |
} | |
wrefresh(trackerWindow); | |
placeCursor(); | |
} | |
void drawWindows() | |
{ | |
drawOrderWindow(); | |
drawInstrumentWindow(); | |
drawEffectWindow(); | |
drawTrackerWindow(); | |
placeCursor(); | |
refresh(); | |
} | |
void spam(int c, int y) | |
{ | |
move(y, 0); | |
int i; | |
for(i = 0; i < COLS; i++) | |
{ | |
printw("%c", c); | |
} | |
} | |
void drawStatus() | |
{ | |
char modeString[32]; | |
switch(curMode) | |
{ | |
case MODE_EDIT: | |
strcpy(modeString, "Edit"); | |
break; | |
case MODE_PLAY: | |
strcpy(modeString, "Play"); | |
break; | |
case MODE_JAM: | |
strcpy(modeString, "Jam"); | |
break; | |
} | |
attrset(A_NORMAL); | |
spam(' ', LINES - 1); | |
mvprintw(LINES - 1, 0, "MODE: %s | OCTAVE: %i | SPEED: %i FPS | REPEAT: 0x%x | ORDERS: %i | INSTRUMENTS: %i", modeString, curOctave, song.fps, song.repeat, song.orderCount, song.instrumentCount); | |
placeCursor(); | |
refresh(); | |
} | |
void initWindows() | |
{ | |
w1 = COLS / 3; | |
h1 = 10; | |
w2 = w1 * 3; | |
h2 = LINES - h1 - 1; | |
orderWindow = newwin(h1, w1, 0, 0); | |
instrumentWindow = newwin(h1, w1, 0, w1); | |
effectWindow = newwin(h1, w1, 0, w1 * 2); | |
trackerWindow = newwin(h2, w2, h1, 0); | |
clear(); | |
refresh(); | |
drawWindows(); | |
drawStatus(); | |
placeCursor(); | |
refresh(); | |
} | |
void scrollTracker() | |
{ | |
while(curFrame > h2 / 2 + trackerScroll) trackerScroll++; | |
while(curFrame < trackerScroll) trackerScroll--; | |
} | |
void down() | |
{ | |
curFrame = (curFrame + 1) % 32; | |
scrollTracker(); | |
} | |
void up() | |
{ | |
curFrame--; | |
if(curFrame < 0) curFrame = 31; | |
scrollTracker(); | |
} | |
Order clipboard; | |
void editInput(int c) | |
{ | |
Entry *entry = &song.orders[curOrder].frames[curFrame].entries[curOsc]; | |
switch(c) | |
{ | |
case '\t': | |
curWindow = (curWindow + 1) % 4; | |
drawWindows(); | |
break; | |
default: | |
switch(curWindow) | |
{ | |
case WIN_ORDER: | |
switch(c) | |
{ | |
case KEY_DOWN: | |
curOrder = (curOrder + 1) % song.orderCount; | |
while(curOrder >= orderScroll + h1 - 2) | |
{ | |
orderScroll++; | |
} | |
while(curOrder < orderScroll) | |
{ | |
orderScroll--; | |
} | |
drawOrderWindow(); | |
drawTrackerWindow(); | |
break; | |
case KEY_UP: | |
curOrder = (curOrder - 1); | |
while(curOrder < 0) curOrder += song.orderCount; | |
while(curOrder >= orderScroll + h1 - 2) | |
{ | |
orderScroll++; | |
} | |
while(curOrder < orderScroll) | |
{ | |
orderScroll--; | |
} | |
drawOrderWindow(); | |
drawTrackerWindow(); | |
break; | |
case 'r': | |
song.repeat = curOrder; | |
drawOrderWindow(); | |
break; | |
case 'c': | |
clipboard = song.orders[curOrder]; | |
break; | |
case 'v': | |
song.orders[curOrder] = clipboard; | |
drawTrackerWindow(); | |
case '=': | |
song.orderCount++; | |
if(song.orderCount > MAX_ORDERS) song.orderCount = MAX_ORDERS; | |
drawOrderWindow(); | |
drawStatus(); | |
break; | |
case '-': | |
song.orderCount--; | |
if(song.orderCount <= 0) song.orderCount = 1; | |
if(curOrder >= song.orderCount) curOrder = song.orderCount - 1; | |
while(curOrder >= orderScroll + h1 - 2) | |
{ | |
orderScroll++; | |
} | |
while(curOrder < orderScroll) | |
{ | |
orderScroll--; | |
} | |
if(song.repeat >= song.orderCount) song.repeat--; | |
drawOrderWindow(); | |
drawStatus(); | |
break; | |
} | |
break; | |
case WIN_INSTR: | |
switch(c) | |
{ | |
case KEY_DOWN: | |
curInstrument = (curInstrument + 1) % song.instrumentCount; | |
while(curInstrument >= instrumentScroll + h1 - 2) | |
{ | |
instrumentScroll++; | |
} | |
while(curInstrument < instrumentScroll) | |
{ | |
instrumentScroll--; | |
} | |
drawInstrumentWindow(); | |
drawEffectWindow(); | |
break; | |
case KEY_UP: | |
curInstrument = (curInstrument - 1); | |
while(curInstrument < 0) curInstrument += song.instrumentCount; | |
while(curInstrument >= instrumentScroll + h1 - 2) | |
{ | |
instrumentScroll++; | |
} | |
while(curInstrument < instrumentScroll) | |
{ | |
instrumentScroll--; | |
} | |
drawInstrumentWindow(); | |
drawEffectWindow(); | |
break; | |
case '=': | |
song.instrumentCount++; | |
if(song.instrumentCount > MAX_INSTRUMENTS) song.instrumentCount = MAX_INSTRUMENTS; | |
drawInstrumentWindow(); | |
drawStatus(); | |
break; | |
case '-': | |
song.instrumentCount--; | |
if(song.instrumentCount <= 0) song.instrumentCount = 1; | |
if(curInstrument >= song.instrumentCount) curInstrument = song.instrumentCount - 1; | |
while(curInstrument >= instrumentScroll + h1 - 2) | |
{ | |
orderScroll++; | |
} | |
while(curInstrument < instrumentScroll) | |
{ | |
instrumentScroll--; | |
} | |
drawInstrumentWindow(); | |
drawStatus(); | |
break; | |
} | |
break; | |
case WIN_EFFECT: | |
switch(c) | |
{ | |
case KEY_DOWN: | |
curEffect = (curEffect + 1) % 8; | |
drawEffectWindow(); | |
break; | |
case KEY_UP: | |
curEffect = (curEffect - 1); | |
while(curEffect < 0) curEffect += 8; | |
drawEffectWindow(); | |
break; | |
case KEY_RIGHT: | |
if(song.instruments[curInstrument].effects[curEffect].enable) | |
{ | |
song.instruments[curInstrument].effects[curEffect].effect++; | |
if(song.instruments[curInstrument].effects[curEffect].effect > 0xF) song.instruments[curInstrument].effects[curEffect].effect = 0xF; | |
} | |
else | |
{ | |
song.instruments[curInstrument].effects[curEffect].enable = 1; | |
} | |
drawEffectWindow(); | |
break; | |
case KEY_LEFT: | |
if(song.instruments[curInstrument].effects[curEffect].enable) | |
{ | |
song.instruments[curInstrument].effects[curEffect].effect--; | |
if(song.instruments[curInstrument].effects[curEffect].effect > 0xF) | |
{ | |
song.instruments[curInstrument].effects[curEffect].effect = 0; | |
song.instruments[curInstrument].effects[curEffect].enable = 0; | |
} | |
drawEffectWindow(); | |
} | |
break; | |
case '=': | |
if(song.instruments[curInstrument].effects[curEffect].enable) | |
{ | |
song.instruments[curInstrument].effects[curEffect].argument++; | |
drawEffectWindow(); | |
} | |
break; | |
case '-': | |
if(song.instruments[curInstrument].effects[curEffect].enable) | |
{ | |
song.instruments[curInstrument].effects[curEffect].argument--; | |
drawEffectWindow(); | |
} | |
break; | |
case ']': | |
if(song.instruments[curInstrument].effects[curEffect].enable) | |
{ | |
song.instruments[curInstrument].effects[curEffect].argument += 0x10; | |
drawEffectWindow(); | |
} | |
break; | |
case '[': | |
if(song.instruments[curInstrument].effects[curEffect].enable) | |
{ | |
song.instruments[curInstrument].effects[curEffect].argument -= 0x10; | |
drawEffectWindow(); | |
} | |
break; | |
} | |
break; | |
case WIN_TRACKER: | |
switch(c) | |
{ | |
case KEY_F(1): | |
curOsc = 0; | |
drawTrackerWindow(); | |
break; | |
case KEY_F(2): | |
curOsc = 1; | |
drawTrackerWindow(); | |
break; | |
case KEY_F(3): | |
curOsc = 2; | |
drawTrackerWindow(); | |
break; | |
case KEY_F(4): | |
curOsc = 3; | |
drawTrackerWindow(); | |
break; | |
case KEY_RIGHT: | |
curCol++; | |
if(curCol > 4) | |
{ | |
curCol = 0; | |
curOsc = (curOsc + 1) % 4; | |
} | |
drawTrackerWindow(); | |
break; | |
case KEY_LEFT: | |
curCol--; | |
if(curCol < 0) | |
{ | |
curCol = 4; | |
curOsc--; | |
if(curOsc < 0) curOsc = 3; | |
} | |
drawTrackerWindow(); | |
break; | |
case KEY_DOWN: | |
down(); | |
drawTrackerWindow(); | |
break; | |
case KEY_UP: | |
up(); | |
drawTrackerWindow(); | |
break; | |
case 'p': | |
playEntry(entry, curOsc); | |
break; | |
case KEY_BACKSPACE: | |
up(); | |
default: | |
switch(curCol) | |
{ | |
case 0: | |
switch(c) | |
{ | |
case KEY_BACKSPACE: | |
entry->noteCommand.note = NOTE_NULL; | |
break; | |
case '`': | |
if(entry->noteCommand.note == NOTE_OFF) | |
{ | |
entry->noteCommand.note = NOTE_ON; | |
} | |
else | |
{ | |
entry->noteCommand.note = NOTE_OFF; | |
} | |
down(); | |
break; | |
case '0': | |
entry->noteCommand.octave = 0; | |
break; | |
case '1': | |
entry->noteCommand.octave = 1; | |
break; | |
case '2': | |
entry->noteCommand.octave = 2; | |
break; | |
case '3': | |
entry->noteCommand.octave = 3; | |
break; | |
case '4': | |
entry->noteCommand.octave = 4; | |
break; | |
case '5': | |
entry->noteCommand.octave = 5; | |
break; | |
case '6': | |
entry->noteCommand.octave = 6; | |
break; | |
case '7': | |
entry->noteCommand.octave = 7; | |
break; | |
case 'a': | |
entry->noteCommand.octave = curOctave; | |
entry->noteCommand.note = NOTE_C; | |
down(); | |
break; | |
case 'w': | |
entry->noteCommand.octave = curOctave; | |
entry->noteCommand.note = NOTE_Cs; | |
down(); | |
break; | |
case 's': | |
entry->noteCommand.octave = curOctave; | |
entry->noteCommand.note = NOTE_D; | |
down(); | |
break; | |
case 'e': | |
entry->noteCommand.octave = curOctave; | |
entry->noteCommand.note = NOTE_Ds; | |
down(); | |
break; | |
case 'd': | |
entry->noteCommand.octave = curOctave; | |
entry->noteCommand.note = NOTE_E; | |
down(); | |
break; | |
case 'f': | |
entry->noteCommand.octave = curOctave; | |
entry->noteCommand.note = NOTE_F; | |
down(); | |
break; | |
case 't': | |
entry->noteCommand.octave = curOctave; | |
entry->noteCommand.note = NOTE_Fs; | |
down(); | |
break; | |
case 'g': | |
entry->noteCommand.octave = curOctave; | |
entry->noteCommand.note = NOTE_G; | |
down(); | |
break; | |
case 'y': | |
entry->noteCommand.octave = curOctave; | |
entry->noteCommand.note = NOTE_Gs; | |
down(); | |
break; | |
case 'h': | |
entry->noteCommand.octave = curOctave; | |
entry->noteCommand.note = NOTE_A; | |
down(); | |
break; | |
case 'u': | |
entry->noteCommand.octave = curOctave; | |
entry->noteCommand.note = NOTE_As; | |
down(); | |
break; | |
case 'j': | |
entry->noteCommand.octave = curOctave; | |
entry->noteCommand.note = NOTE_B; | |
down(); | |
break; | |
case 'k': | |
entry->noteCommand.octave = curOctave + 1; | |
entry->noteCommand.note = NOTE_C; | |
down(); | |
break; | |
case 'r': | |
entry->noteCommand.note = NOTE_RESET; | |
break; | |
case '=': | |
if(entry->noteCommand.note == NOTE_B) | |
{ | |
entry->noteCommand.note = NOTE_C; | |
entry->noteCommand.octave = (entry->noteCommand.octave + 1) % 8; | |
} | |
else if(entry->noteCommand.note > 3) | |
{ | |
entry->noteCommand.note++; | |
} | |
break; | |
case '-': | |
if(entry->noteCommand.note == 4) | |
{ | |
entry->noteCommand.note = 15; | |
if(entry->noteCommand.octave == 0) | |
{ | |
entry->noteCommand.octave = 7; | |
} | |
else | |
{ | |
entry->noteCommand.octave--; | |
} | |
} | |
else if(entry->noteCommand.note > 4) | |
{ | |
entry->noteCommand.note--; | |
} | |
break; | |
case ']': | |
entry->noteCommand.octave = (entry->noteCommand.octave + 1) % 8; | |
break; | |
case '[': | |
if(entry->noteCommand.octave == 0) | |
{ | |
entry->noteCommand.octave = 7; | |
} | |
else | |
{ | |
entry->noteCommand.octave--; | |
} | |
break; | |
} | |
break; | |
case 1: | |
switch(c) | |
{ | |
case KEY_BACKSPACE: | |
entry->noteCommand.applyInstrument = 0; | |
break; | |
case '0': | |
entry->noteCommand.instrument = 0; | |
entry->noteCommand.applyInstrument = 1; | |
down(); | |
break; | |
case '1': | |
entry->noteCommand.instrument = 1; | |
entry->noteCommand.applyInstrument = 1; | |
down(); | |
break; | |
case '2': | |
entry->noteCommand.instrument = 2; | |
entry->noteCommand.applyInstrument = 1; | |
down(); | |
break; | |
case '3': | |
entry->noteCommand.instrument = 3; | |
entry->noteCommand.applyInstrument = 1; | |
down(); | |
break; | |
case '4': | |
entry->noteCommand.instrument = 4; | |
entry->noteCommand.applyInstrument = 1; | |
down(); | |
break; | |
case '5': | |
entry->noteCommand.instrument = 5; | |
entry->noteCommand.applyInstrument = 1; | |
down(); | |
break; | |
case '6': | |
entry->noteCommand.instrument = 6; | |
entry->noteCommand.applyInstrument = 1; | |
down(); | |
break; | |
case '7': | |
entry->noteCommand.instrument = 7; | |
entry->noteCommand.applyInstrument = 1; | |
down(); | |
break; | |
case '=': | |
entry->noteCommand.instrument = (entry->noteCommand.instrument + 1) % 8; | |
break; | |
case '-': | |
if(entry->noteCommand.instrument == 0) | |
{ | |
entry->noteCommand.instrument = 7; | |
} | |
else | |
{ | |
entry->noteCommand.instrument--; | |
} | |
break; | |
} | |
break; | |
case 2: | |
switch(c) | |
{ | |
case KEY_BACKSPACE: | |
entry->noteCommand.volume = 0; | |
break; | |
case '0': | |
entry->noteCommand.volume = 0; | |
down(); | |
break; | |
case '`': | |
entry->noteCommand.volume = 31; | |
down(); | |
break; | |
case '=': | |
entry->noteCommand.volume = (entry->noteCommand.volume + 1) % 32; | |
break; | |
case '-': | |
if(entry->noteCommand.volume == 0) | |
{ | |
entry->noteCommand.volume = 31; | |
} | |
else | |
{ | |
entry->noteCommand.volume--; | |
} | |
break; | |
case ']': | |
entry->noteCommand.volume = (entry->noteCommand.volume + 0x10) % 32; | |
break; | |
case '[': | |
if(entry->noteCommand.volume <= 0x10) | |
{ | |
entry->noteCommand.volume = 31; | |
} | |
else | |
{ | |
entry->noteCommand.volume -= 0x10; | |
} | |
break; | |
} | |
break; | |
case 3: | |
switch(c) | |
{ | |
case KEY_BACKSPACE: | |
entry->effect.enable = 0; | |
break; | |
case '0': | |
entry->effect.effect = 0; | |
entry->effect.enable = 1; | |
down(); | |
break; | |
case '1': | |
entry->effect.effect = 1; | |
entry->effect.enable = 1; | |
down(); | |
break; | |
case '2': | |
entry->effect.effect = 2; | |
entry->effect.enable = 1; | |
down(); | |
break; | |
case '3': | |
entry->effect.effect = 3; | |
entry->effect.enable = 1; | |
down(); | |
break; | |
case '4': | |
entry->effect.effect = 4; | |
entry->effect.enable = 1; | |
down(); | |
break; | |
case '5': | |
entry->effect.effect = 5; | |
entry->effect.enable = 1; | |
down(); | |
break; | |
case '6': | |
entry->effect.effect = 6; | |
entry->effect.enable = 1; | |
down(); | |
break; | |
case '7': | |
entry->effect.effect = 7; | |
entry->effect.enable = 1; | |
down(); | |
break; | |
case '8': | |
entry->effect.effect = 8; | |
entry->effect.enable = 1; | |
down(); | |
break; | |
case '9': | |
entry->effect.effect = 9; | |
entry->effect.enable = 1; | |
down(); | |
break; | |
case 'a': | |
entry->effect.effect = 0xA; | |
entry->effect.enable = 1; | |
down(); | |
break; | |
case 'b': | |
entry->effect.effect = 0xB; | |
entry->effect.enable = 1; | |
down(); | |
break; | |
case 'c': | |
entry->effect.effect = 0xC; | |
entry->effect.enable = 1; | |
down(); | |
break; | |
case 'd': | |
entry->effect.effect = 0xD; | |
entry->effect.enable = 1; | |
down(); | |
break; | |
case 'e': | |
entry->effect.effect = 0xE; | |
entry->effect.enable = 1; | |
down(); | |
break; | |
case 'f': | |
entry->effect.effect = 0xF; | |
entry->effect.enable = 1; | |
down(); | |
break; | |
case '=': | |
entry->effect.effect = (entry->effect.effect + 1) % 0x10; | |
entry->effect.enable = 1; | |
break; | |
case '-': | |
if(entry->effect.effect == 0) | |
{ | |
entry->effect.effect = 0xF; | |
} | |
else | |
{ | |
entry->effect.effect--; | |
} | |
entry->effect.enable = 1; | |
break; | |
} | |
break; | |
case 4: | |
switch(c) | |
{ | |
case KEY_BACKSPACE: | |
entry->effect.enable = 0; | |
break; | |
case '0': | |
entry->effect.argument = 0; | |
entry->effect.enable = 1; | |
down(); | |
break; | |
case '=': | |
entry->effect.argument++; | |
entry->effect.enable = 1; | |
break; | |
case '-': | |
entry->effect.argument--; | |
entry->effect.enable = 1; | |
break; | |
case ']': | |
entry->effect.argument += 0x10; | |
entry->effect.enable = 1; | |
break; | |
case '[': | |
entry->effect.argument -= 0x10; | |
entry->effect.enable = 1; | |
break; | |
} | |
break; | |
} | |
drawTrackerWindow(); | |
} | |
break; | |
} | |
} | |
} | |
void playInput(int c) | |
{ | |
} | |
void jamInput(int c) | |
{ | |
} | |
void editMode() | |
{ | |
curMode = MODE_EDIT; | |
drawWindows(); | |
drawStatus(); | |
} | |
void broadcastEffect(Effect effect) | |
{ | |
sendEffectCommand(&effect, 0); | |
sendEffectCommand(&effect, 1); | |
sendEffectCommand(&effect, 2); | |
sendEffectCommand(&effect, 3); | |
} | |
void resetEffects() | |
{ | |
broadcastEffect(newEffect(0x0, 0x00)); | |
broadcastEffect(newEffect(0x1, 0x00)); | |
broadcastEffect(newEffect(0x2, 0x00)); | |
broadcastEffect(newEffect(0x3, 0x00)); | |
broadcastEffect(newEffect(0x4, 0x00)); | |
broadcastEffect(newEffect(0x5, 0x00)); | |
broadcastEffect(newEffect(0x6, 0x7F)); | |
broadcastEffect(newEffect(0x7, 0x00)); | |
broadcastEffect(newEffect(0x8, 0x00)); | |
broadcastEffect(newEffect(0x9, 0x00)); | |
broadcastEffect(newEffect(0xA, 0x00)); | |
broadcastEffect(newEffect(0xB, 0x00)); | |
broadcastEffect(newEffect(0xC, 0xFF)); | |
broadcastEffect(newEffect(0xD, 0x00)); | |
broadcastEffect(newEffect(0xE, 0xF0)); | |
broadcastEffect(newEffect(0xF, 0x00)); | |
} | |
Frame quietFrame; | |
void reset() | |
{ | |
playFrame(&quietFrame); | |
resetEffects(); | |
} | |
int playing; | |
void playOrder(Order *order, int fps) | |
{ | |
int i; | |
for(i = 0; i < sizeof(order->frames) / sizeof(Frame); i++) | |
{ | |
curFrame = i; | |
scrollTracker(); | |
drawTrackerWindow(); | |
playFrame(&order->frames[i]); | |
usleep(1000000 / fps); | |
char c = getch(); | |
if(c == '\n' || c == ' ' || c == KEY_F(8)) | |
{ | |
playing = 0; | |
reset(); | |
editMode(); | |
break; | |
} | |
} | |
} | |
void playMode() | |
{ | |
curMode = MODE_PLAY; | |
drawWindows(); | |
drawStatus(); | |
int i; | |
playing = 1; | |
for(i = 0; playing; i++) | |
{ | |
if(i == song.orderCount) i = song.repeat; | |
curOrder = i; | |
drawOrderWindow(); | |
Order order = song.orders[i]; | |
playOrder(&order, song.fps); | |
} | |
} | |
void jamMode() | |
{ | |
curMode = MODE_JAM; | |
drawWindows(); | |
drawStatus(); | |
} | |
void playCurrentFrame() | |
{ | |
Frame f = song.orders[curOrder].frames[curFrame]; | |
playFrame(&f); | |
} | |
void playCurrentOrder() | |
{ | |
Order o = song.orders[curOrder]; | |
playOrder(&o, song.fps); | |
} | |
void save() | |
{ | |
FILE *fp; | |
fp = fopen("chiptune.sav", "w"); | |
fputc(song.fps, fp); | |
fputc(song.repeat, fp); | |
fputc(song.instrumentCount, fp); | |
fputc(song.orderCount, fp); | |
int i; | |
for(i = 0; i < song.instrumentCount; i++) | |
{ | |
Instrument instrument = song.instruments[i]; | |
int a; | |
for(a = 0; a < 8; a++) | |
{ | |
Effect effect = instrument.effects[a]; | |
fputc(effect.enable, fp); | |
fputc(effect.effect, fp); | |
fputc(effect.argument, fp); | |
} | |
} | |
for(i = 0; i < song.orderCount; i++) | |
{ | |
Order order = song.orders[i]; | |
int a; | |
for(a = 0; a < 32; a++) | |
{ | |
Frame frame = order.frames[a]; | |
int b; | |
for(b = 0; b < 4; b++) | |
{ | |
Entry entry = frame.entries[b]; | |
fputc(entry.noteCommand.note, fp); | |
fputc(entry.noteCommand.octave, fp); | |
fputc(entry.noteCommand.volume, fp); | |
fputc(entry.noteCommand.applyInstrument, fp); | |
fputc(entry.noteCommand.instrument, fp); | |
fputc(entry.effect.enable, fp); | |
fputc(entry.effect.effect, fp); | |
fputc(entry.effect.argument, fp); | |
} | |
} | |
} | |
fclose(fp); | |
} | |
void load() | |
{ | |
FILE *fp; | |
fp = fopen("chiptune.sav", "r"); | |
song.fps = fgetc(fp); | |
song.repeat = fgetc(fp); | |
song.instrumentCount = fgetc(fp); | |
song.orderCount = fgetc(fp); | |
int i; | |
for(i = 0; i < song.instrumentCount; i++) | |
{ | |
int a; | |
for(a = 0; a < 8; a++) | |
{ | |
song.instruments[i].effects[a].enable = fgetc(fp); | |
song.instruments[i].effects[a].effect = fgetc(fp); | |
song.instruments[i].effects[a].argument = fgetc(fp); | |
} | |
} | |
for(i = 0; i < song.orderCount; i++) | |
{ | |
int a; | |
for(a = 0; a < 32; a++) | |
{ | |
int b; | |
for(b = 0; b < 4; b++) | |
{ | |
song.orders[i].frames[a].entries[b].noteCommand.note = fgetc(fp); | |
song.orders[i].frames[a].entries[b].noteCommand.octave = fgetc(fp); | |
song.orders[i].frames[a].entries[b].noteCommand.volume = fgetc(fp); | |
song.orders[i].frames[a].entries[b].noteCommand.applyInstrument = fgetc(fp); | |
song.orders[i].frames[a].entries[b].noteCommand.instrument = fgetc(fp); | |
song.orders[i].frames[a].entries[b].effect.enable = fgetc(fp); | |
song.orders[i].frames[a].entries[b].effect.effect = fgetc(fp); | |
song.orders[i].frames[a].entries[b].effect.argument = fgetc(fp); | |
} | |
} | |
} | |
fclose(fp); | |
curOrder = 0; | |
curInstrument = 0; | |
curEffect = 0; | |
curFrame = 0; | |
orderScroll = 0; | |
instrumentScroll = 0; | |
trackerScroll = 0; | |
drawWindows(); | |
drawStatus(); | |
} | |
void inputLoop() | |
{ | |
quietFrame = newQuietFrame(); | |
int e = 1; | |
while(e) | |
{ | |
int c = getch(); | |
switch(c) | |
{ | |
case KEY_F(5): | |
reset(); | |
break; | |
case KEY_F(6): | |
playNote(NOTE_C, 3, 0xFF, 0); | |
playNote(NOTE_E, 4, 0xFF, 1); | |
playNote(NOTE_G, 3, 0xFF, 2); | |
playNote(NOTE_Bb, 4, 0xFF, 3); | |
break; | |
case KEY_F(7): | |
playCurrentFrame(); | |
break; | |
case KEY_F(8): | |
playCurrentOrder(); | |
break; | |
case KEY_F(9): | |
save(); | |
case KEY_F(10): | |
load(); | |
break; | |
case 'q': | |
e = 0; | |
break; | |
case KEY_RESIZE: | |
initWindows(); | |
break; | |
case '.': | |
curOctave = (curOctave + 1) % 8; | |
drawStatus(); | |
break; | |
case ',': | |
if(curOctave == 0) | |
{ | |
curOctave = 7; | |
} | |
else | |
{ | |
curOctave--; | |
} | |
drawStatus(); | |
break; | |
case '\'': | |
song.fps = (song.fps + 1) % 25; | |
if(song.fps <= 0) song.fps = 1; | |
drawStatus(); | |
break; | |
case ';': | |
if(song.fps <= 1) | |
{ | |
song.fps = 24; | |
} | |
else | |
{ | |
song.fps--; | |
} | |
drawStatus(); | |
break; | |
case '\n': | |
if(curMode == MODE_PLAY) | |
{ | |
editMode(); | |
} | |
else | |
{ | |
playMode(); | |
} | |
break; | |
case ' ': | |
if(curMode == MODE_JAM) | |
{ | |
editMode(); | |
} | |
else | |
{ | |
jamMode(); | |
} | |
break; | |
case ERR: | |
break; | |
default: | |
switch(curMode) | |
{ | |
case MODE_EDIT: | |
editInput(c); | |
break; | |
case MODE_PLAY: | |
playInput(c); | |
break; | |
case MODE_JAM: | |
jamInput(c); | |
break; | |
} | |
} | |
} | |
} | |
void gui() | |
{ | |
initscr(); | |
clear(); | |
noecho(); | |
cbreak(); | |
keypad(stdscr, TRUE); | |
nodelay(stdscr, TRUE); | |
refresh(); | |
initWindows(); | |
inputLoop(); | |
endwin(); | |
} | |
void initSong() | |
{ | |
song.fps = 8; | |
song.repeat = 0; | |
song.orderCount = 1; | |
song.instrumentCount = 1; | |
Order orders[MAX_ORDERS]; | |
song.orders = orders; | |
Instrument instruments[MAX_INSTRUMENTS]; | |
song.instruments = instruments; | |
} | |
int main(int argc, char *argv[]) | |
{ | |
if(argc > 1) | |
{ | |
strcpy(serialPort, argv[1]); | |
} | |
else | |
{ | |
printf("Enter full path to serial device: "); | |
scanf("%s", serialPort); | |
} | |
if(out = fopen(serialPort, "w")) | |
{ | |
initSong(); | |
reset(); | |
gui(); | |
reset(); | |
fclose(out); | |
} | |
else | |
{ | |
printf("Unable to open file!\n"); | |
exit(1); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment