Servus,
ich habe mich mal an einer eigenen Musikroutine versucht. Man mag sich vielleicht fragen, warum, denn es gibt doch schon so viel fertiges, aber ich moechte das nicht zur Diskussion werden lassen, es ging mir ganz einfach mal drum, das selbst zu machen, auch um dabei etwas zu lernen. Und wie es aussieht, gibt es durchaus einiges, was ich dabei noch lernen muss...
Kurz zum Prinzip: Die Musik besteht aus einer Liste von Frequenzen, welche einfach fuer die drei Stimmen Stueck fuer Stueck eingelesen und in die entsprechenden Register geschrieben werden. Sollte eine Frequenz $FFFF sein, so wird ueberhaupt nichts gemacht, somit kann der Ton noch etwas ausklingen. Sollte eine Frequenz geschrieben worden sein, wird die Wellenform samt Gate-Bit geschrieben. Im naechsten Frame (jeweils durch IRQ ausgeloest) wird das Gate-Bit wieder geloescht, sodass der Ton direkt ausklingt. Dann wird eine gewisse Anzahl an Frames ueberhaupt nichts gemacht, bis es wieder soweit ist, dass die naechsten Noten gespielt werden sollen, und das ganze beginnt von vorn. Also eigentlich eine ganz simple Sache.
Das hat erstmal gar nicht so schlecht funktioniert, aber ich habe festgestellt, dass die Musik nicht 100% rund zu laufen scheint, sprich, es gibt ab und zu Toene, die scheinbar einen Tick spaeter oder frueher kommen. Das ganze war zum Teil nur minimal bemerkbar, aber es war definitiv da. Also habe ich ein wenig mehr rumexperimentiert, z.B. stable IRQs verwendet usw, aber irgendwie hat auch das nicht geholfen. Ich habe dann noch die Stelle, wo die Gate-Bits gesetzt und geloescht werden teilweise etwas herumgeschoben und siehe da, ich konnte zumindest Unterschiede feststellen. Leider laesst mein aktueller Code aber nicht wirklich andere Stellen zu, daher konnte ich das auch nicht so lassen. Habe dann noch die Idee gehabt, die Stimme kurz vorm Setzen der Wellenform + Gate-Bit einfach komplett abzuschalten, und siehe da, das ist bisher das beste Ergebnis. Es klingt nun 100% stabil.
Jetzt habe ich nur das Problem, dass ich, sobald ich ein anderes Tempo einschalte (sprich einfach eine andere Anzahl an Warte-Frames verwende), wieder extreme Unsauberkeiten bekomme. Moeglicherweise ist das alles also nur Zufall, dass es gerade in meinem verwendeten Tempo funktioniert?
Ich denke es ist am besten wenn ich den Code hier poste, vielleicht hat ja jemand einen Tip fuer mich. Vielleicht mache ich auch grundsaetzlich etwas falsch mit dem ganzen Gate-Bit-Zeugs usw. Ich hoffe es kann mir jemand weiterhelfen
Hier der Code:
- ;-------------------------------
- !zone
- .music_addr !word $FFFF
- .pattern_addr !word $FFFF
- .tempo !byte $0
- .when_clear !byte $0
- .pattern_length !byte $0
- .waveform1 !byte $0
- .waveform2 !byte $0
- .waveform3 !byte $0
- ;-- number of music has to be in A
- init_music
- pha
- tax
- clc
- lda TEMPO, x
- sta .tempo
- sbc #1
- sta .when_clear
- lda PATTERN_LENGTH, x
- sta .pattern_length
- pla
- pha
- asl
- tax
- lda MUSIC_LIST, x
- sta .music_addr
- lda MUSIC_LIST +1, x
- sta .music_addr +1
- pla
- sta $FB
- adc $FB
- adc $FB
- tax
- lda WAVEFORMS, x
- sta .waveform1
- lda WAVEFORMS +1, x
- sta .waveform2
- lda WAVEFORMS +2, x
- sta .waveform3
- lda #$0
- sta .tempo_cnt
- sta .note_cnt
- sta .seq_cnt
- ;-- gate bit 0
- lda #$0
- sta $D404
- sta $D40B
- sta $D412
- ;-- full volume
- lda #$0F
- sta $D418
- ;-- attack and decay
- lda ADSR +1, x
- sta $D405
- lda ADSR +3, x
- sta $D40C
- lda ADSR +5, x
- sta $D413
- ;-- sustain and release
- lda ADSR +0, x
- sta $D406
- lda ADSR +2, x
- sta $D40D
- lda ADSR +4, x
- sta $D414
- rts
- .tempo_cnt !byte $00
- .note_cnt !byte $00
- .seq_cnt !byte $00
- play_music
- lda .tempo_cnt
- beq .play
- dec .tempo_cnt
- lda .tempo_cnt
- cmp .when_clear
- bne .no_clear
- ;-- clear gate bits
- lda .waveform1
- sta $D404
- lda .waveform2
- sta $D40B
- lda .waveform3
- sta $D412
- .no_clear
- rts
- .play
- lda .tempo
- sta .tempo_cnt
- lda .note_cnt
- cmp .pattern_length
- bne .play2
- inc .seq_cnt
- lda #$0
- sta .note_cnt
- .play2
- lda .music_addr
- sta $FB
- lda .music_addr +1
- sta $FC
- clc
- lda .seq_cnt
- adc .seq_cnt
- adc .seq_cnt
- asl
- tay
- lda ($FB), y
- sta $FD
- iny
- lda ($FB), y
- sta $FE
- cmp #$FF
- beq .track2
- cmp #$FE
- bne .no_restart
- lda #0
- sta .seq_cnt
- jmp .play2
- .no_restart
- lda .note_cnt
- asl
- tay
- iny
- lda ($FD), y
- cmp #$FF
- beq .track2
- sta $D401
- lda #%00001000
- sta $D404
- dey
- lda ($FD), y
- sta $D400
- lda .waveform1
- adc #1
- sta $D404
- ;-- track 2
- .track2
- clc
- lda .seq_cnt
- adc .seq_cnt
- adc .seq_cnt
- adc #1
- asl
- tay
- lda ($FB), y
- sta $FD
- iny
- lda ($FB), y
- sta $FE
- cmp #$FF
- beq .track3
- lda .note_cnt
- asl
- tay
- iny
- lda ($FD), y
- cmp #$FF
- beq .track3
- sta $D408
- lda #%00001000
- sta $D40B
- dey
- lda ($FD), y
- sta $D407
- lda .waveform2
- adc #1
- sta $D40B
- ;-- track 3
- .track3
- clc
- lda .seq_cnt
- adc .seq_cnt
- adc .seq_cnt
- adc #2
- asl
- tay
- lda ($FB), y
- sta $FD
- iny
- lda ($FB), y
- sta $FE
- cmp #$FF
- beq .end
- lda .note_cnt
- asl
- tay
- iny
- lda ($FD), y
- cmp #$FF
- beq .end
- sta $D40F
- lda #%00001000
- sta $D412
- dey
- lda ($FD), y
- sta $D40E
- lda .waveform3
- adc #1
- sta $D412
- .end
- inc .note_cnt
- rts
- PATTERN_BASS1
- !word $02be ;-- E-1
- !word $057b ;-- E-2
- !word $02be ;-- E-1
- !word $057b ;-- E-2
- !word $02be ;-- E-1
- !word $057b ;-- E-2
- !word $02be ;-- E-1
- !word $057b ;-- E-2
- !word $0342 ;-- G-1
- !word $0685 ;-- G-2
- !word $0342 ;-- G-1
- !word $0685 ;-- G-2
- !word $0271 ;-- D-1
- !word $04e2 ;-- D-2
- !word $0271 ;-- D-1
- !word $04e2 ;-- D-2
- PATTERN_DRUM1
- !word $ffff ;-- ---
- !word $ffff ;-- ---
- !word $2e76 ;-- F-5
- !word $ffff ;-- ---
- !word $ffff ;-- ---
- !word $ffff ;-- ---
- !word $2e76 ;-- F-5
- !word $ffff ;-- ---
- !word $ffff ;-- ---
- !word $ffff ;-- ---
- !word $2e76 ;-- F-5
- !word $ffff ;-- ---
- !word $ffff ;-- ---
- !word $ffff ;-- ---
- !word $2e76 ;-- F-5
- !word $ffff ;-- ---
- PATTERN_DRUM2
- !word $ffff ;-- ---
- !word $ffff ;-- ---
- !word $2e76 ;-- F-5
- !word $ffff ;-- ---
- !word $ffff ;-- ---
- !word $ffff ;-- ---
- !word $2e76 ;-- F-5
- !word $ffff ;-- ---
- !word $ffff ;-- ---
- !word $ffff ;-- ---
- !word $2e76 ;-- F-5
- !word $ffff ;-- ---
- !word $ffff ;-- ---
- !word $2e76 ;-- F-5
- !word $2e76 ;-- F-5
- !word $ffff ;-- ---
- PATTERN_MELO1A
- !word $106d ;-- B-3
- !word $0af7 ;-- E-3
- !word $ffff ;-- ---
- !word $0ea2 ;-- A-3
- !word $ffff ;-- ---
- !word $0d0a ;-- G-3
- !word $ffff ;-- ---
- !word $0c4e ;-- F#3
- !word $0d0a ;-- G-3
- !word $0ea2 ;-- A-3
- !word $106d ;-- B-3
- !word $0ea2 ;-- A-3
- !word $ffff ;-- ---
- !word $0ea2 ;-- A-3
- !word $0d0a ;-- G-3
- !word $0c4e ;-- F#3
- PATTERN_MELO1B
- !word $0af7 ;-- E-3
- !word $ffff ;-- ---
- !word $ffff ;-- ---
- !word $0837 ;-- B-2
- !word $ffff ;-- ---
- !word $0af7 ;-- E-3
- !word $09c4 ;-- D-3
- !word $0837 ;-- B-2
- !word $09c4 ;-- D-3
- !word $0af7 ;-- E-3
- !word $0c4e ;-- F#3
- !word $0af7 ;-- E-3
- !word $ffff ;-- ---
- !word $09c4 ;-- D-3
- !word $0af7 ;-- E-3
- !word $ffff ;-- ---
- PATTERN_MELO2
- !word $15ed ;-- E-4
- !word $ffff ;-- ---
- !word $ffff ;-- ---
- !word $20db ;-- B-4
- !word $ffff ;-- ---
- !word $ffff ;-- ---
- !word $ffff ;-- ---
- !word $15ed ;-- E-4
- !word $1d45 ;-- A-4
- !word $ffff ;-- ---
- !word $20db ;-- B-4
- !word $22cf ;-- C-5
- !word $ffff ;-- ---
- !word $1d45 ;-- A-4
- !word $ffff ;-- ---
- !word $20db ;-- B-4
- PATTERN_MELO3
- !word $15ed ;-- E-4
- !word $ffff ;-- ---
- !word $ffff ;-- ---
- !word $20db ;-- B-4
- !word $ffff ;-- ---
- !word $ffff ;-- ---
- !word $ffff ;-- ---
- !word $15ed ;-- E-4
- !word $1d45 ;-- A-4
- !word $ffff ;-- ---
- !word $20db ;-- B-4
- !word $2712 ;-- D-5
- !word $ffff ;-- ---
- !word $1d45 ;-- A-4
- !word $ffff ;-- ---
- !word $20db ;-- B-4
- PATTERN_BASS2
- !word $022d ;-- C-1
- !word $045a ;-- C-2
- !word $022d ;-- C-1
- !word $045a ;-- C-2
- !word $022d ;-- C-1
- !word $045a ;-- C-2
- !word $022d ;-- C-1
- !word $045a ;-- C-2
- !word $0271 ;-- D-1
- !word $04e2 ;-- D-2
- !word $0271 ;-- D-1
- !word $04e2 ;-- D-2
- !word $0271 ;-- D-1
- !word $04e2 ;-- D-2
- !word $0271 ;-- D-1
- !word $04e2 ;-- D-2
- PATTERN_BASS3
- !word $02be ;-- E-1
- !word $057b ;-- E-2
- !word $02be ;-- E-1
- !word $057b ;-- E-2
- !word $02be ;-- E-1
- !word $057b ;-- E-2
- !word $02be ;-- E-1
- !word $057b ;-- E-2
- !word $02be ;-- E-1
- !word $057b ;-- E-2
- !word $02be ;-- E-1
- !word $057b ;-- E-2
- !word $02be ;-- E-1
- !word $057b ;-- E-2
- !word $0342 ;-- G-1
- !word $0685 ;-- G-2
- SONG
- !word PATTERN_BASS1, $FFFF, $FFFF
- !word PATTERN_BASS1, $FFFF, $FFFF
- !word PATTERN_BASS1, PATTERN_DRUM1, $FFFF
- !word PATTERN_BASS1, PATTERN_DRUM2, $FFFF
- !word PATTERN_BASS1, PATTERN_DRUM1, PATTERN_MELO1A
- !word PATTERN_BASS1, PATTERN_DRUM2, PATTERN_MELO1B
- !word PATTERN_BASS1, PATTERN_DRUM1, PATTERN_MELO1A
- !word PATTERN_BASS1, PATTERN_DRUM2, PATTERN_MELO1B
- !word PATTERN_BASS1, $FFFF, $FFFF
- !word PATTERN_BASS1, PATTERN_DRUM2, $FFFF
- !word PATTERN_BASS1, PATTERN_DRUM1, PATTERN_MELO1A
- !word PATTERN_BASS1, PATTERN_DRUM2, PATTERN_MELO1B
- !word PATTERN_BASS1, PATTERN_DRUM1, PATTERN_MELO1A
- !word PATTERN_BASS1, PATTERN_DRUM2, PATTERN_MELO1B
- !word PATTERN_BASS1, $FFFF, $FFFF
- !word PATTERN_BASS1, PATTERN_DRUM2, $FFFF
- !word PATTERN_BASS1, PATTERN_DRUM1, PATTERN_MELO2
- !word PATTERN_BASS1, PATTERN_DRUM2, $FFFF
- !word PATTERN_BASS1, PATTERN_DRUM1, PATTERN_MELO3
- !word PATTERN_BASS1, PATTERN_DRUM2, $FFFF
- !word PATTERN_BASS1, PATTERN_DRUM1, PATTERN_MELO2
- !word PATTERN_BASS1, PATTERN_DRUM2, $FFFF
- !word PATTERN_BASS2, PATTERN_DRUM1, PATTERN_MELO3
- !word PATTERN_BASS3, PATTERN_DRUM1, $FFFF
- !word $FEFF
- ;-- the following values and value tuples are per song
- TEMPO
- !byte $0B
- PATTERN_LENGTH
- !byte $10
- WAVEFORMS
- !byte $20, $80, $20
- ADSR
- !word $00F8, $00F9, $00F8
- ;-- list of songs and their start addresses
- MUSIC_LIST
- !word SONG