Page 1 of 2

Musical Note Duration Conversions

Posted: Tue Jan 03, 2017 12:00 pm
by Gorf
Hello! :D

I was wondering if someone could give me a good guide for musical not duration conversions as I am trying to use my VIC to create some music using POKEs and FOR...NEXT loops.

Thanks! :D

Re: Musical Note Duration Conversions

Posted: Tue Jan 03, 2017 12:25 pm
by Bobbi
I guess I would get out a stop watch and time some FOR loops in BASIC :)

Re: Musical Note Duration Conversions

Posted: Tue Jan 03, 2017 12:43 pm
by Boray
How about

FOR T=1 TO S/N : NEXT

Where S is playback speed and N is note length, for example 1,2,4 or 8.

Re: Musical Note Duration Conversions

Posted: Tue Jan 03, 2017 12:45 pm
by Bobbi
Or maybe use the VIC's own stopwatch for timing!

10 S=TI
20 FOR I=1TO1000:NEXTI
30 PRINT TI-S

Re: Musical Note Duration Conversions

Posted: Tue Jan 03, 2017 12:57 pm
by Mike
The main issue with simple FOR...NEXT timing loops, if used for different note durations, is that they don't compensate properly for the time taken the read in the note data, writes to the VIC sound registers and other overhead. Tunes played with this method quite often sound like they're losing the beat.

IMO, it's better to employ a "tracker" approach, using a single time base period. Then, longer notes are achieved by repeating the note value until the desired length is reached. Most simple tunes do not use more than 3 different note lengths, so that should cover most needs. IRQ based players in machine language almost always take the same approach, using the stable IRQ clock for their purpose.

As an example how a music player in BASIC looks like with that method, here's a simple "Happy Birthday" tune:

Code: Select all

1 V=36864:POKEV+14,5:DIMN(8):FORT=0TO8:READN(T):NEXT
2 A$=""+"AAAAA@AA@BBBBBBBB@AAAAAAAA@DDDDDDDD@CCCCCCCCCCCCCCCCC@"
3 A$=A$+"AAAAA@AA@BBBBBBBB@AAAAAAAA@EEEEEEEE@DDDDDDDDDDDDDDDDD@"
4 A$=A$+"AAAAA@AA@HHHHHHHH@FFFFFFFF@DDDDDDDD@CCCCCCCC@BBBBBBBB@"
5 A$=A$+"GGGGG@GG@FFFFFFFF@DDDDDDDD@EEEEEEEE@DDDDDDDDDDDDDDDDD@"
6 FORT=1TOLEN(A$):POKEV+12,N(ASC(MID$(A$,T,1))-64):FORS=1TO30:NEXT:NEXT
7 FORP=-1TO0:GETA$:P=A$="":NEXT
8 DATA 0,170,179,187,191,198,204,207,212
That one uses a rather short time base (see FORS=1TO30:NEXT), because it needs to insert small pauses to properly separate consecutive identical notes.

Re: Musical Note Duration Conversions

Posted: Tue Jan 03, 2017 1:59 pm
by Gorf
Bobbi wrote:Or maybe use the VIC's own stopwatch for timing!

10 S=TI
20 FOR I=1TO1000:NEXTI
30 PRINT TI-S
So, that gives me a value of 73, can you please tell me what I can deduce from that? :D
Boray wrote:How about

FOR T=1 TO S/N : NEXT

Where S is playback speed and N is note length, for example 1,2,4 or 8.
So, am I correct that 1, 2, 4, or 8 are essentially whole, half, quarter, and eighth notes? If so, how do you determine the playback speed? :D
Mike wrote:The main issue with simple FOR...NEXT timing loops, if used for different note durations, is that they don't compensate properly for the time taken the read in the note data, writes to the VIC sound registers and other overhead. Tunes played with this method quite often sound like they're losing the beat.

IMO, it's better to employ a "tracker" approach, using a single time base period. Then, longer notes are achieved by repeating the note value until the desired length is reached. Most simple tunes do not use more than 3 different note lengths, so that should cover most needs. IRQ based players in machine language almost always take the same approach, using the stable IRQ clock for their purpose.

As an example how a music player in BASIC looks like with that method, here's a simple "Happy Birthday" tune:

Code: Select all

1 V=36864:POKEV+14,5:DIMN(8):FORT=0TO8:READN(T):NEXT
2 A$=""+"AAAAA@AA@BBBBBBBB@AAAAAAAA@DDDDDDDD@CCCCCCCCCCCCCCCCC@"
3 A$=A$+"AAAAA@AA@BBBBBBBB@AAAAAAAA@EEEEEEEE@DDDDDDDDDDDDDDDDD@"
4 A$=A$+"AAAAA@AA@HHHHHHHH@FFFFFFFF@DDDDDDDD@CCCCCCCC@BBBBBBBB@"
5 A$=A$+"GGGGG@GG@FFFFFFFF@DDDDDDDD@EEEEEEEE@DDDDDDDDDDDDDDDDD@"
6 FORT=1TOLEN(A$):POKEV+12,N(ASC(MID$(A$,T,1))-64):FORS=1TO30:NEXT:NEXT
7 FORP=-1TO0:GETA$:P=A$="":NEXT
8 DATA 0,170,179,187,191,198,204,207,212
That one uses a rather short time base (see FORS=1TO30:NEXT), because it needs to insert small pauses to properly separate consecutive identical notes.
Ok, I understand what you are saying about FOR...NEXT loops and I have a rudimentary understanding of how trackers work and how they time notes. Can you tell me what lines to change to use different notes and also, can you take advantage of more than one voice using this approach? :D

Thank you all for your help! :mrgreen:

Re: Musical Note Duration Conversions

Posted: Tue Jan 03, 2017 2:09 pm
by Mike
Gorf wrote:Ok, I understand what you are saying about FOR...NEXT loops and I have a rudimentary understanding of how trackers work and how they time notes. Can you tell me what lines to change to use different notes and also, can you take advantage of more than one voice using this approach? :D
I deliberately left that as exercise for the reader. :P

But really, the note values are contained in the DATAs of line 8 and can be changed as you like. And more than one voice would be done by interleaving the note data in the string, retrieving the register values into two or more variables, and finally updating the VIC registers with the necessary POKEs within the shortest time possible for each time step, so all note changes happen nearly simultaneously - otherwise you *will* hear strange arpeggio-like blips on all note changes.

Anything more complex than that is better done in one of the music trackers available for the VIC-20, like Daniel Kahlin's VIC-TRACKER 2.0.

Re: Musical Note Duration Conversions

Posted: Tue Jan 03, 2017 2:15 pm
by Gorf
Mike wrote:
Gorf wrote:Ok, I understand what you are saying about FOR...NEXT loops and I have a rudimentary understanding of how trackers work and how they time notes. Can you tell me what lines to change to use different notes and also, can you take advantage of more than one voice using this approach? :D
I deliberately left that as exercise for the reader. :P

But really, the note values are contained in the DATAs of line 8 and can be changed as you like. And more than one voice would be done by interleaving the note data in the string, retrieving the register values into two or more variables, and finally updating the VIC registers with the necessary POKEs within the shortest time possible for each time step, so all note changes happen nearly simultaneously - otherwise you *will* hear strange arpeggio-like blips on all note changes.

Anything more complex than that is better done in one of the music trackers available for the VIC-20, like Daniel Kahlin's VIC-TRACKER 2.0.
Ok, thank you. I think that your subroutine will help me in the future. :D

Re: Musical Note Duration Conversions

Posted: Tue Jan 03, 2017 2:38 pm
by Mike
Just one small addition:
Mike wrote:[...] more than one voice would be done by interleaving the note data in the string, [...]
It is also possible to use an own string for each voice.

That avoids the interleaving, but you have to take a little more oversight that the voices keep in step. You'd then retrieve the register values for all the voices from the same position in two or more strings instead of from two or more consecutive positions in the same one string.

You'll still have to write the registers as fast as possible, like in: POKEV+10,A:POKEV+11,B:POKEV+12,C - with the values in A, B and C retrieved beforehand (say, with A=N(MID$(..)).:B=...:C=...).

Re: Musical Note Duration Conversions

Posted: Tue Jan 03, 2017 3:55 pm
by Boray
Gorf wrote: So, am I correct that 1, 2, 4, or 8 are essentially whole, half, quarter, and eighth notes? If so, how do you determine the playback speed? :D
Yes. Playback speed is faster the lower the number is and slower the higher the number is.

Re: Musical Note Duration Conversions

Posted: Tue Jan 03, 2017 4:04 pm
by Bobbi
To answer your question about the 'stopwatch' ... TI (and TI$) contain the time since the system started in 60ths of a second.

So your value of 73, corresponds to slightly more than one second (73/60).

Re: Musical Note Duration Conversions

Posted: Tue Jan 03, 2017 5:23 pm
by Gorf
Mike wrote:Just one small addition:
Mike wrote:[...] more than one voice would be done by interleaving the note data in the string, [...]
It is also possible to use an own string for each voice.

That avoids the interleaving, but you have to take a little more oversight that the voices keep in step. You'd then retrieve the register values for all the voices from the same position in two or more strings instead of from two or more consecutive positions in the same one string.

You'll still have to write the registers as fast as possible, like in: POKEV+10,A:POKEV+11,B:POKEV+12,C - with the values in A, B and C retrieved beforehand (say, with A=N(MID$(..)).:B=...:C=...).

Ok, thank you for the tip! :D

Re: Musical Note Duration Conversions

Posted: Tue Jan 03, 2017 6:37 pm
by Gorf
Boray wrote:
Gorf wrote: So, am I correct that 1, 2, 4, or 8 are essentially whole, half, quarter, and eighth notes? If so, how do you determine the playback speed? :D
Yes. Playback speed is faster the lower the number is and slower the higher the number is.
Ok, thank you for clarifying that. :D
Bobbi wrote:To answer your question about the 'stopwatch' ... TI (and TI$) contain the time since the system started in 60ths of a second.

So your value of 73, corresponds to slightly more than one second (73/60).
Which make sense because the 6502's speen on the NTSC VIC-20 is slightly more than 1 MHz, right? :D

Re: Musical Note Duration Conversions

Posted: Tue Jan 03, 2017 11:47 pm
by Bobbi
Which make sense because the 6502's speen on the NTSC VIC-20 is slightly more than 1 MHz, right?
It has more to do with however fast BASIC happens to be when executing a FOR loop.

Re: Musical Note Duration Conversions

Posted: Thu Jan 05, 2017 7:33 am
by Gorf
Bobbi wrote:
Which make sense because the 6502's speen on the NTSC VIC-20 is slightly more than 1 MHz, right?
It has more to do with however fast BASIC happens to be when executing a FOR loop.
Ok, thanks for the clarification. :D