Jump to content
IGNORED

ABCmusic experiments going on...


_cooper_

Recommended Posts

Hi !

 

I'm still going on doing stuff on my side with my Lynx, and i'm still playing around with ABCmusic for newcc65.

 

I discovered each voice has a max length of 255 chars, including instruments configuration, which is quite tight to have a proper tune written :(

 

I've found that Karri has put the sourcecode on bitbucket for abcmusic, available here (thanks Karri !) :

https://bitbucket.org/atarilynx/lynx/src/f68a49d18f50df286a371caf4c75d21c51a4658b/contrib/abcmusic/newcc65version/abcmusic.m65?at=master&fileviewer=file-view-default

 

I had a silly idea, but is it possible to bypass this 255 chars limit ? Pointing in a specific address in RAM, or adding a specific char detection in the pattern data which would jump to an other dc.b declaration ? (really ugly but perhaps easier to do ?)

 

Unfortunately i have no asm knowledge to do this but perhaps some lynxdev wizards out there could give a hand ?

 

I know the new compiler is out there but i know some of us still use the old version (for convenience reasons or lazyness :) )

 

Anyway any opinion is ofcourse welcome !

Link to comment
Share on other sites

Sourcecode has been slightly modified to try to bypass the limit, but no sound for the moment :(

 

Here is the code if somebody manage to catch a weird thing...

; ABC music definition file
	global _silence
	global _update_music
	global _abcmusic
	xref popax

; vars for ABC-music

	bsszp
abc_score_ptr0  ds 2
abc_score_ptr1  ds 2
abc_score_ptr2  ds 2
abc_score_ptr3  ds 2
; Pointer temporaires
abc_score_ptr0_tmp ds 2
abc_score_ptr1_tmp  ds 2
abc_score_ptr2_tmp  ds 2
abc_score_ptr3_tmp  ds 2
	text

abcsilence  dc.b 0

; Set all scores to silent at startup
_silence::
  lda #$00
  sta $fd50 ; all channels to left+right
  lda #<abcsilence
  ldy #>abcsilence
  ldx #0
  jsr _abc_set_score
  lda #<abcsilence
  ldy #>abcsilence
  ldx #1
  jsr _abc_set_score
  lda #<abcsilence
  ldy #>abcsilence
  ldx #2
  jsr _abc_set_score
  lda #<abcsilence
  ldy #>abcsilence
  ldx #3
  jmp _abc_set_score

abc_read_number::
  stz abc_tmp
  stz abc_tmp+1
.tentimes1
  jsr abc_read_char
  cmp #$2f
  bcc  .tentimes9
  cmp #$39
  bcs .tentimes9
  and #$0f
  pha
  lda abc_tmp
  clc
  rol
  sta abc_tmp
  clc
  rol
  clc
  rol
  bcc .tentimes2
  inc abc_tmp+1
.tentimes2
  clc
  adc abc_tmp
  bcc .tentimes3
  inc abc_tmp+1
.tentimes3
  sta abc_tmp
  pla
  clc
  adc abc_tmp
  bcc .tentimes4
  inc abc_tmp+1
.tentimes4
  sta abc_tmp
  bra .tentimes1
.tentimes9
  dey
  lda abc_tmp
  rts

_abcmusic::
  jsr popax   ; pop string
  sta abc_tmp
  stx abc_tmp+1
  jsr popax   ; pop channel
  tax
  lda abc_tmp
  ldy abc_tmp+1
; Activate score on channel X
; A - low address
; Y - high address
_abc_set_score::
  inx
  dex
  bne .abc_set_score2
    ldx sound_channel_busy
    bne .abc_set_score1
    ; On met le ptr dans le temporaire
      sta abc_score_ptr0_tmp
      sta abc_score_ptr0	; puis dans le slot de base
      sty abc_score_ptr0+1
      stz abc_music_ptr
      stz sound_channel_duration
.abc_set_score1
    rts
.abc_set_score2
  dex
  bne .abc_set_score4
    ldx sound_channel_busy+1
    bne .abc_set_score3
          sta abc_score_ptr1_tmp
      sta abc_score_ptr1
      sty abc_score_ptr1+1
      stz abc_music_ptr+1
      stz sound_channel_duration+1
.abc_set_score3
    rts
.abc_set_score4
  dex
  bne .abc_set_score6
    ldx sound_channel_busy+2
    bne .abc_set_score5
          sta abc_score_ptr2_tmp
      sta abc_score_ptr2
      sty abc_score_ptr2+1
      stz abc_music_ptr+2
      stz sound_channel_duration+2
.abc_set_score5
    rts
.abc_set_score6
  ldx sound_channel_busy+3
  bne .abc_set_score7
        sta abc_score_ptr3_tmp
    sta abc_score_ptr3
    sty abc_score_ptr3+1
    stz abc_music_ptr+3
    stz sound_channel_duration+3
.abc_set_score7
  rts
;--------------------------------------------------------------
; Once at each frame we can update the music
; You should call this routine frequently.
; Once in a frame is a good idea.
_update_music::
  ldx #0
update_channel_x:
  lda sound_channel_duration,x
  bne .update_music1
    ; note has ended, fetch next
    lda abc_music_ptr,x
    tay
    bra parse_abc
.update_music1
  ; note is playing
  cmp #255 ; Duration 255 is forever, good for engines
  beq .update_music2
    dea
    sta sound_channel_duration,x
.update_music2
update_channel_tail:
  lda sound_channel_maxlen,x
  beq .update_music3
    dea
    sta sound_channel_maxlen,x
    bne .update_music3
      sta sound_channel_max_volume,x
.update_music3
  lda sound_channel_max_volume,x
  bne .update_music5
    ; silence
    lda sound_channel_volume,x
    beq .update_music5
      ; decay time still going on
      sec
      sbc abc_instrument_decr,x
      bcs .update_music4
        ; silence
        lda #0
.update_music4
      sta sound_channel_volume,x
.update_music5
  lda sound_channel_volume,x
  cmp sound_channel_max_volume,x
  bcs .update_music8
    ; attack time
    clc
    adc abc_instrument_incr,x
    bcc .update_music6
      ; desired volume reached
      lda sound_channel_max_volume,x
.update_music6
    cmp sound_channel_max_volume,x
    bcc .update_music7
    beq .update_music7
      ; desired volume reached
      lda sound_channel_max_volume,x
.update_music7
    sta sound_channel_volume,x
.update_music8
  lda sound_channel_volume,x
  phx
  pha
  txa
  clc
  rol
  clc
  rol
  clc
  rol
  tax
  pla
  sta $fd20,x
  plx
  inx
  txa
  cmp #4
  bne update_channel_x
  rts
;--------------------------------------------------------------
; Parse score enough to get next note
; X - channel to use
; Y - abc music pointer
parse_abc::
  jsr abc_read_char
  cmp #$0 ; End of music
  bne .parse_abc1
    sta sound_channel_busy,x
    bra update_channel_tail
.parse_abc1
  cmp #$20 ;' ' ignore spaces
  bne .parse_abc2
    bra parse_abc
.parse_abc2
  cmp #$7c ;'|'
  bne .parse_abc6
    jsr abc_read_char
    cmp #$3a ;':'
    bne .parse_abc4
      tya
      sta abc_repeat_offs,x
      lda #0
      sta abc_repeat_cnt,x
    bra .parse_abc5
.parse_abc4
      dey
.parse_abc5
    jmp parse_abc
.parse_abc6
  cmp #$3a ;':'
  bne .parse_abc7
    phy
    lda abc_repeat_offs,x
    tay
    pla
    ;sta abc_repeat_offs,x
    jmp parse_abc
.parse_abc7
  cmp #$50 ;'P' priority - wait until sound has ended
  bne .parse_abc8u
    sta sound_channel_busy,x
    jmp parse_abc
.parse_abc8u
  cmp #'V' ; volume
  bne .parse_abc8
    jsr abc_read_number
    sta abc_note_volume,x
    jmp parse_abc
.parse_abc8
  cmp #'R' ; ramp up
  bne .parse_abc8a
    jsr abc_read_number
    sta abc_instrument_incr,x
    jmp parse_abc
.parse_abc8a
  cmp #'H' ; hold
  bne .parse_abc8b
    jsr abc_read_number
    sta abc_instrument_maxlen,x
    jmp parse_abc
.parse_abc8b
  cmp #'K' ; kill sound
  bne .parse_abc8c
    jsr abc_read_number
    sta abc_instrument_decr,x
    jmp parse_abc
.parse_abc8c
  cmp #'I' ; incremental flag
  bne .parse_abc9
    jsr abc_read_number
    phx
    txa
    clc
    rol
    clc
    rol
    clc
    rol
    tax
    lda abc_tmp
    cmp #0
    bne .parse_abc8d
      lda $fd25,x
      and #$df
    bra .parse_abc8e
.parse_abc8d
      lda $fd25,x
      ora #$20
.parse_abc8e
    ora #$18
    sta $fd25,x
    plx
    jmp parse_abc
.parse_abc9
  cmp #$54 ;'T' tempo
  bne .parse_abc9b
    jsr abc_read_number
    sta abc_note_length,x
    jmp parse_abc
.parse_abc9b
  cmp #$4f ;'O' octave
  bne .parse_abc9c
    jsr abc_read_number
    phx
    txa
    clc
    rol
    clc
    rol
    clc
    rol
    tax
    lda $fd25,x
    and #$f8
    ora #$18
    ora abc_tmp
    sta $fd25,x
    plx
    jmp parse_abc
.parse_abc9c
  cmp #'X'; XOR taps
  bne .parse_abc10
    jsr abc_read_number
    phx
    txa ; modify X to point to sound channel
    clc
    rol
    clc
    rol
    clc
    rol
    tax
    lda abc_tmp
    ; The two topmost bits are shifted one place right
    bpl .parse_abc9d
      ora #$40
    bra .parse_abc9e
.parse_abc9d
      and #$bf
.parse_abc9e
    dec abc_tmp+1
    beq .parse_abc9f
      and #$7f
    bra .parse_abc9g
.parse_abc9f 
      ora #$80
.parse_abc9g 
    sta $fd21,x
    ; Bit $40 is put in a different register
    lda abc_tmp
    and #$40
    bne .parse_abc9h
      lda $fd25,x
      and #$7f
    bra .parse_abc9i
.parse_abc9h
      lda $fd25,x
      ora #$80
.parse_abc9i
    ora #$18
    sta $fd25,x
    lda #0
    sta $fd23,x
    plx
    jmp parse_abc
.parse_abc10
  cmp #$7a ;'z'
  bne .parse_abc11
    lda #0
    bra set_music_ptr
.parse_abc11
  ; Find out the pitch of the note
  stz cur_note
  inc cur_note
  cmp #$3d ;'='
  bne .parse_abc12
    inc cur_note
    jsr abc_read_char
.parse_abc12
  cmp #$7e ;'~'
  bne .parse_abc13
    dec cur_note
    jsr abc_read_char
.parse_abc13
  sec
  sbc #$41 ;'A'
  cmp #8 ;'H'-'A'
  bcs .parse_abc14 ;_IFLO
    clc
    asl
    clc
    adc cur_note
    sta cur_note
  bra .parse_abc15
.parse_abc14
    sec
    sbc #$20 ;'a'-'A' + 15
    clc
    asl
    clc
    adc cur_note
    clc
    adc #15
    sta cur_note
.parse_abc15
  lda cur_note
  phy
  tay
  lda _delays,y
  phx
  pha
  txa
  clc
  rol
  clc
  rol
  clc
  rol
  tax
  pla
  sta $fd24,x
  plx
  ply
  ; Find out the volume of the note
  lda abc_note_volume,x
set_music_ptr:
  sta sound_channel_max_volume,x
  ; Find out the duration of the note
  jsr abc_read_char
  cmp #$34 ; "4"
  bne .parse_abc16
    lda abc_note_length,x
    clc
    rol
    clc
    rol
  bra .parse_abc19
.parse_abc16
    cmp #$33 ; "3"
    bne .parse_abc17
      lda abc_note_length,x
      clc
      rol
      clc
      adc abc_note_length,x
    bra .parse_abc19
.parse_abc17
      cmp #$32 ; "2"
      bne .parse_abc18
        lda abc_note_length,x
        clc
        rol
      bra .parse_abc19
.parse_abc18
        dey
        lda abc_note_length,x
.parse_abc19
  sta sound_channel_duration,x
  tya
  sta abc_music_ptr,x
  lda abc_instrument_maxlen,x
  sta sound_channel_maxlen,x
  jmp update_channel_x
;--------------------------------------------------------------
; This table is used to cover the delays needed for 2 octaves
_delays dc.b 161 ; Ab
        dc.b 152 ; A
        dc.b 143 ; A# Bb
        dc.b 135 ; B
        dc.b 128 ;
        dc.b 255 ; C
        dc.b 241 ; C# Db
        dc.b 227 ; D
        dc.b 214 ; D# Eb
        dc.b 202 ; E
        dc.b 191 ;
        dc.b 191 ; F
        dc.b 180 ; F# Gb
        dc.b 170 ; G
        dc.b 161 ; G#
_delays2
        dc.b 80  ; ab
        dc.b 76  ; a
        dc.b 72  ; a# bb
        dc.b 68  ; b
        dc.b 128 ;
        dc.b 128 ; c
        dc.b 120 ; c# db
        dc.b 114 ; d
        dc.b 107 ; d# eb
        dc.b 101 ; e
        dc.b 96  ;
        dc.b 96  ; f
        dc.b 90  ; f# gb
        dc.b 85  ; g
        dc.b 80  ; g#
;--------------------------------------------------------------
; Read a character from the score. Advance ptr if it is not 0
; X - channel
; Y - score offset
abc_read_char::
	txa
	ina
	dea
	bne .abc_read_char1
    ; lda (abc_score_ptr0),y
	lda (abc_score_ptr0_tmp)
  	inc abc_score_ptr0_tmp		; Augmente de 1
	bra .abc_read_char4
.abc_read_char1
    dea
    bne .abc_read_char2
	;lda (abc_score_ptr1),y
    lda (abc_score_ptr1_tmp)
  	inc abc_score_ptr1_tmp		; Augmente de 1
    bra .abc_read_char4
.abc_read_char2
	dea
	bne .abc_read_char3
    ;lda (abc_score_ptr2),y
	lda (abc_score_ptr2_tmp)
  	inc abc_score_ptr2_tmp		; Augmente de 1
	bra .abc_read_char4
.abc_read_char3
	; lda (abc_score_ptr3),y
	lda (abc_score_ptr3_tmp)
  	inc abc_score_ptr3_tmp		; Augmente de 1
.abc_read_char4
	beq .abc_read_char5
    iny
.abc_read_char5
  rts
;--------------------------------------------------------------
; Instrument setup. C-interface
_abcinstrument::
  ; Lynx-specific abc-command to set up the instrument
  jsr popax   ; channel
  sta instrumenttmp+1
  clc
  rol
  clc
  rol
  clc
  rol
  sta instrumenttmp
  jsr popax ; shift 012345 10 11
  ldx instrumenttmp
  sta $fd21,x
  jsr popax ; start value not needed
  ldx instrumenttmp+1
  sta abc_note_length,x
  ldx instrumenttmp
  ; sta $fd23,x
  jsr popax ; backup not needed
  ldx instrumenttmp+1
  sta abc_note_volume,x
  ldx instrumenttmp
  ; sta $fd24,x
  jsr popax ; flags b012 clock b5 integr b7 fb7
  ldx instrumenttmp
  sta $fd25,x
  jsr popax ; attack
  ldx instrumenttmp+1
  sta abc_instrument_incr,x
  jsr popax ; hold
  ldx instrumenttmp+1
  sta abc_instrument_maxlen,x
  jsr popax ; decay
  ldx instrumenttmp+1
  sta abc_instrument_decr,x
  rts

instrumenttmp ds 2
abc_music_ptr   dc.b 0,0,0,0
abc_repeat_offs dc.b 0,0,0,0
abc_repeat_cnt  dc.b 0,0,0,0
abc_note_length dc.b 6,6,6,6
abc_note_volume dc.b 64,64,64,64
abc_instrument_incr   dc.b 4,4,4,4
abc_instrument_maxlen dc.b 4,4,4,4
abc_instrument_decr   dc.b 4,4,4,4
sound_channel_busy    dc.b 0,0,0,0
sound_channel_max_volume dc.b 60,127,127,127
sound_channel_volume   dc.b 4,4,4,4
sound_channel_maxlen   dc.b 4,4,4,4
sound_channel_duration dc.b 0,0,0,0
cur_note    dc.b 0
abc_tmp ds 2
Link to comment
Share on other sites

  • 4 weeks later...
  • 4 weeks later...

The novel development kicked off some new features in the pure C variant of the ABC module. I plan to write some instructions of how to use it.

 

The cc65 variant was also fixed but as it it interrupt driven I did not want to run it in the same cart with Chipper. The Reiko's Robot Run was Chipper based. But the cc65 can handle long abc tunes. So there is no 256 byte limitations.

 

I am also adding a digitized sound api running at HBL interrupt rate. The HBL interrupts occur at 105 x frame rate. So ABC music could use frame rate for notes and scan line rate divided by two for digitized sound like speech. The quality is pretty good at 4kHz.

 

The tests to run fake arpeggio chords did not turn out well. So doing [CEG] won't work. I may write a python script to lynxify any abc tune.

 

I added small test setups to different abcmusic directories to get sound out by just typing "make".

Edited by karri
Link to comment
Share on other sites

 

So there is no 256 byte limitations.

 

Nice, if you'd want to do something bigger!

 

 

I am also adding a digitized sound api running at HBL interrupt rate. The HBL interrupts occur at 105 x frame rate. So ABC music could use frame rate for notes and scan line rate divided by two for digitized sound like speech. The quality is pretty good at 4kHz.

 

That's really exciting! I love that stuff in for example APB. Opens up new possibilities in Lynx games.

 

 

The tests to run fake arpeggio chords did not turn out well. So doing [CEG] won't work.

 

Ah, too bad! I'm still second guessing myself if those fake-chords used on many 8-bit game systems and computers are the actual sounds or if they really are arpeggios (although I was told they are on another forum). I mean some of the chipper sounds I used in Reiko sounds like they're 'vibrating' back and forth between at least two notes (and those are only one note in the tracker). https://youtu.be/Yx6iY0BGHac?t=35s

 

 

I added small test setups to different abcmusic directories to get sound out by just typing "make".

 

Cool!

Edited by Turbo Laser Lynx
Link to comment
Share on other sites

  • 9 months later...

@Karri, a couple of questions about the old Lynx-native sound-finder program you had made if I may? The sounds generated with it didn't seem to be out of tune from each other? At least I remember experimenting and using whatever sounds from it in abc-music and the sounds were working fine together. Would there be a sensible way to translate sounds from the abc-sound-finder to chipper? It would speed up finding decent sounds a lot. I guess the sound-tool limits the "soundscape of the Lynx" since the sounds were not out of tune? But that would be a totally ok trade off since finding and creating sounds with it was much easier than with chipper.

 

Your chipper sound collection and chipper example songs (with sounds) is a nice start though.

Edited by Turbo Laser Lynx
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...