Music engine with PWP waves

Basic and Machine Language

Moderator: Moderators

Post Reply
kulor
Vic 20 Newbie
Posts: 8
Joined: Sat Sep 29, 2012 11:57 pm

Music engine with PWP waves

Post by kulor »

Hello everyone! I'm trying to write a music engine for the VIC-20 and I have a few questions. I'm still pretty new to coding in assembly, though I've made something similar on the Atari 2600.
What I have so far is a program that runs through all the notes in a note table. I'm trying to get those notes to be the different PWP waves, but it's inconsistent and I'm not sure why. I'm using this document for reference.
My code so far decrements x continually, decrementing y when x hits 0, then when y hits 0 the next note is played. This has allowed for some primitive form of timing, but what's the standard way for timing things to synchronize to screen updates on the VIC-20?
Then, the PWP waves. I have it set up so it puts $7E into the oscillator for a pretty long while, then it disables interrupts and rapidly pushes $FE, $FE, $7E, then the note frequency. According to that document that's all I should need to do, right? There's also a bit of sample code up towards the top which basically does the same thing I'm doing. And yet it only seems to have that PWP wave sound sometimes, it's not consistent. There's a routine towards the bottom of that document, but I don't understand it and I can't get it to assemble.
Any ideas what I'm doing wrong here? Attached the .prg and source, which is pasted below. Any help is greatly appreciated!

Code: Select all

    processor 6502

    org $1001

BASICstub 
    dc.w nxt_line               ; Calculate pointer to next BASIC line
    dc.w 2012                   ; BASIC Line# (change this to any # you want)
    hex 9e                      ; BASIC token for SYS
    if ml_start                 ; If ml_start hasn't been defined, skip it for now
    dc.b [ml_start]d            ; ML start address (use any address you like here)
    endif
    hex 00                      ; End of BASIC line
nxt_line  
    hex 00 00                   ; The next BASIC line would start here

LOFREQ = $900A
MDFREQ = $900B
HIFREQ = $900C
NZFREQ = $900D
VOL = $900E
BORDER = $900F

RAMValues
currentNote     .byte 0
    
ml_start                        ;Start your ML code here.
    
    lda #255
    sta VOL
    lda #0
    sta BORDER
    ldx #1
    ldy #1
inf
    ;Timing stuff!
    ;   y--
    ;   if (y == 0) {
    dey
    cpy #0
    bne inf
    ;       x--
    ;       if (x == 10) {
    ;           osc = $7E
    dex
    cpx #10
    bne dontDisableFreq
    lda #$7E
    sta MDFREQ
dontDisableFreq
    ;       }
    ;       else if (x == 0) {
    cpx #0
    bne inf
    ;Oscillator stuff!
    ;           disable interrupts
    ;           osc = $FE
    ;           osc = $FE
    ;           osc = $7E
    ;           osc = NoteTable[currentNote]
    ;           enable interrupts
    ldy currentNote
    lda NoteTable,y
    ldx #$7E
    ldy #$FE
    sei
    sty MDFREQ  ;1
    sty MDFREQ  ;1
    stx MDFREQ  ;0
    sta MDFREQ
    cli
    ;           currentNote++
    ;           if (currentNote == 52) {
    ;               currentNote = 0
    ;           }
    ldy currentNote
    iny
    cpy #52
    bne dontResetNoteTable
    ldy #0
dontResetNoteTable
    sty currentNote
    ldx #200
    ;       }
    ;   }
    jmp inf
    
NoteTable
        ;   C       C#      D       D#      E       F       F#      G       G#      A       A#      B
    .byte           131,    138,    144,    150,    156,    162,    167,    172,    177,    181,    185         ;1
    .byte   189,    193,    196,    200,    203,    206,    208,    211,    214,    216,    218,    220         ;2
    .byte   222,    224,    226,    227,    229,    230,    232,    233,    234,    235,    237,    238         ;3
    .byte   239,            240,    241,    242,    243,            244,            245,    246                 ;4
    .byte   247,                    248,            249,                            250                         ;5
    .byte   251,                                    252                                                         ;6
    .byte   253                                                                                                 ;7
    .byte           254                                                                                         ;8
    
    .byte 0
    
z_EndOfData

    org $1DFF
z_EndOfWorkspace
Attachments
victest.zip
(1.28 KiB) Downloaded 58 times
armypavarmy
Vic 20 Hobbyist
Posts: 107
Joined: Wed Oct 02, 2013 1:54 am
Location: Italy

Re: Music engine with PWP waves

Post by armypavarmy »

Hello
I'm Armando
I tried your program victest.prg
does not work.
Maybe the problem is
the table of not-correct notes.
I am attaching the table that I use
for the vic and the plus-4 --- PAL.
Note-Plus4-Vic20-Vic20 Piano-.doc.zip
(4.09 KiB) Downloaded 65 times
kulor
Vic 20 Newbie
Posts: 8
Joined: Sat Sep 29, 2012 11:57 pm

Re: Music engine with PWP waves

Post by kulor »

I was messing around with this again, I tried it on my real VIC-20 (NTSC) and strangely was getting the same result.
I noticed that if you swap out the middle channel for the high channel, the PWP wave works consistently...and if you swap it out for the low channel, it doesn't work at all.
The way to get it to behave consistently on lower channels seems to be to perform a whole bunch of NOPs between each oscillator frequency update. I pasted in 6 NOPs between each one:

Code: Select all

	sei
	sty LOFREQ	;1
	nop
	nop
	nop
	nop
	nop
	nop
	stx LOFREQ	;0
	nop
	nop
	nop
	nop
	nop
	nop
	sty LOFREQ	;1
	nop
	nop
	nop
	nop
	nop
	nop
	sty LOFREQ	;1
	nop
	nop
	nop
	nop
	nop
	nop
	sta LOFREQ
	cli
...and it seems to work consistently on the low and middle channels (but not the high channel!) that way. I'm gonna have to trial-and-error to figure out exactly how many NOPs you need for it to work on which channels.
armypavarmy wrote:Hello
I'm Armando
I tried your program victest.prg
does not work.
Maybe the problem is
the table of not-correct notes.
I am attaching the table that I use
for the vic and the plus-4 --- PAL.
Hey Armando! It doesn't work? What are you trying to run it on, an emulator or a real PAL VIC-20? My program doesn't do a whole lot, it just changes the screen colors a bit and plays a scale.
The note table I'm using is my own concoction, I made it by measuring the low channel ($900A) at value $FB (or you could POKE 36874, 251) and matching it to ~1076.65 hertz. $FD seems to be an octave higher (~2153.3hz), and $FE an octave higher than that (~4306.6hz). Then, having the base frequency and knowing that a frequency divider is being used, I did something like this:

Code: Select all

for (var i = 254, i > 128, i--) {
	freq = 4306.6 / (255 - i)
}
...which let me pair up each register value with its approximate frequency. I then matched these frequencies to their closest fits on a note to frequency table I found. I did this with VICE running in PAL mode, so my frequency table should be accurate for PAL machines.
I did briefly look at your frequency table, and I don't agree that POKE 36874,132 produces a B. Comparing it to my Yamaha DX-7 it definitely seems to be closer to a C#.
armypavarmy
Vic 20 Hobbyist
Posts: 107
Joined: Wed Oct 02, 2013 1:54 am
Location: Italy

Re: Music engine with PWP waves

Post by armypavarmy »

Hello
the tup program runs only on Vic20 unexpanded
strange because music programs work
usually with all ram expansions.
the attached evidence
it turns out that the poke 36874,132 produces C #
Poke36874,130 produces C perfect
Poke 36874,131-132 produce C#
Test performed with Cliftone Tuner MT 40.
You can try to change the poke
using 37004,132 tone and 37006,1-15 volume
greetings Armando
Vic20 valore note -PAL-NTSC.doc.zip
(1.36 MiB) Downloaded 56 times
kulor
Vic 20 Newbie
Posts: 8
Joined: Sat Sep 29, 2012 11:57 pm

Re: Music engine with PWP waves

Post by kulor »

armypavarmy wrote:Hello
the tup program runs only on Vic20 unexpanded
strange because music programs work
usually with all ram expansions.
Oh yeah! There's some weirdness with RAM expansions that I don't know about, I'll have to look into that stuff. Right now I'm building it for unexpanded, then once it's working that way I'll get it running on expansions.
There's still some very basic stuff I'm trying to figure out! Like, for example, I still don't know the standard way of synchronizing things with screen updates. Seems like there's a timer that happens 60 times per second, would that be the thing to use? Would there be PAL compatibility issues if I went that route?
Post Reply