6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Nov 24, 2024 5:19 pm

All times are UTC




Post new topic Reply to topic  [ 5 posts ] 
Author Message
PostPosted: Wed Jun 03, 2020 6:34 pm 
Offline

Joined: Wed Jul 18, 2018 12:12 pm
Posts: 96
Back in April I had asked a question about methods of toggling a single bit as a flag. The suggestions were very helpful and some clever alternatives were proposed. This was for a C64 'DIGI' player I had starting working on in January. I was finally able to incorporate the suggestions this past weekend so only 6 months to finish the project. :) The thread is here: viewtopic.php?f=2&t=6093

Typically for a DIGI player each sample is a 4bit value with two samples packed in a byte. You play the low byte in the first ISR call, shift the high nibble down and play the high nibble the second ISR, etc.

I had though to a couple ideas to decrease the memory footprint of the digital sample. The one I tried months ago an a simple RLE. While the encoding is the hard part it was simple and quick on a modern PC. I wrote the decoder side for the C64 but alas it took too much processor time when trying to play an 8khz sample.

I got to thinking about trying an interpolation scheme this past weekend. This would halve the memory foot print but it makes the player side much more interesting. After several ideas which would not work it occurred to me that it can be done with what amounts to four 'separate ISR routines'. The trick will be how to select the correct one.

An outline of what each ISR does:
Code:
; init - load sample A, separate hi & lo nibbles
; we have three storage bytes in zero page hi, mid, low

; ISR #1 - play lo, calc mid point of hiA-loA save to lo, move hi to mid

; ISR #2, play lo, move mid to lo

; ISR #3, play lo, calc mid point of loB-hiA save to lo

; ISR #4, load sample B, separate hi & lo nibbles


This arrangement of tasks for each ISR evens out the number of cycles each one requires which should range between 40-60 cycles.

One way to 'select which ISR' is used is to use a counter to determine the branch target. This would require two or more comparisons to select between four possibilities unless someone had a trick for this.

Code:
;enter ISR
;play lo sample
; branch to correct block
;
;
; correct block code
; INC counter, AND counter with #$03 (2 bits only)
; RTI



Another idea is to change the ISR address each time. Since we always need to cycle through the ISRs in the order 0, 1, 2, 3 this should work. We will always be at the end of the sample data at ISR #3 so will can always decide to disable the NMI at that point. I kind of like this idea as it seems simple. If the entire ISR can fit in 256 bytes we would only need to change the low byte of the NIM vector as well.

Code:
;enter ISR #0
;play lo sample
; change NMI address to ISR #1
; RTI

;enter ISR #1
;play lo sample
; change NMI address to ISR #2
; RTI


I'm curious what ideas other have. There is always more than a few ways to accomplish something.

Thanks


Top
 Profile  
Reply with quote  
PostPosted: Wed Jun 03, 2020 10:49 pm 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
The most obvious method might be to overwrite the NMI vector at the top of RAM. If you can guarantee that all entry points are in the same page, that will end up being 6 cycles (LDA #imm : STA $FFFA).

For a slightly more general solution, consider that BIT sets both N and V based on bits 7 and 6, as well as Z to reflect the AND of the operand with A. This potentially gives you a way to branch eight ways by executing BIT once, then chaining three layers of branches together - or four ways with a total of three branch instructions, of which two are executed in any given path. For example:
Code:
  LDA #1
  BIT ctr
  BPL ISR_3
  BNE ISR_2
ISR_1:
  INC ctr

ISR_2:
  INC ctr

ISR_3:
  BNE ISR_4
  INC ctr

ISR_4:
  LDA #$FE
  STA ctr



Top
 Profile  
Reply with quote  
PostPosted: Sun Jun 07, 2020 1:25 pm 
Offline

Joined: Wed Jul 18, 2018 12:12 pm
Posts: 96
Thanks, That is a clever way to do it.

I have both versions working and both sound awful. The version that changes the NMI address take up more memory but is a bit faster. Your version is smaller, takes a little longer but is more clear as to what is happening I think.

I suspect it is an issue with how I'm calculating the midpoints, etc. I just implemented a 4K sample to 8K sample upscale program in C# and the results are very similar to the original 8K sampled file with numerous 'off by one' values. Playing the upscaled file in the normal player sounds OK though, with a slight reduction in quality which is to be expected.

I think I'll modify one of the interpolating players to save the output values into an unused section of memory. If I start with a small known test file I can compare the output I get from the C# code to the C64 code. I'm sure when I spot the problem it will be something silly.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jun 08, 2020 3:57 pm 
Offline

Joined: Wed Jul 18, 2018 12:12 pm
Posts: 96
Turns out I tried to invent a brand new addressing mode! I needed to 'peek' at the next byte coming up to calculate the mid-point between the hi-nibble of current byte and low nibble of next byte. Somehow I thought I could do a "LDA mySelfModPtr" from the 'peeking' code as well. Doh! I was working on a program to log the calculations when it occurred to me what I had done. Now to clean up the mess I made and make the code pretty again.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jun 10, 2020 1:49 pm 
Offline

Joined: Wed Jul 18, 2018 12:12 pm
Posts: 96
I'm not going mad!!

When working on the problem of cleaning exiting back to BASIC after the player stopped it seemed that none of the changes I was making were having an effect. I finally set $0400 to display an A character and when that did not show up I new VICE was running an old code version. I checked the configuration in CBM Prj Studio and then it started building correctly. What?

After spending an hour looking at it I was finally able to duplicate the problem at will. Turns out CBM Prg Studio will 'remember' the name of the previous project you worked on and use that instead of your current project. You can open up the user options dialog and it will fix this issue, so at least that is a work around for now. If there was a .prj from a previous build in the directory that would be run instead of the new code which had the wrong name!

Any who, bug filed and now I know I'm not mad. I can now see the changes I am making to the interpolating player so progress can be made. Also, it now does nto freak out when returning to BASIC after the player is finished.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 5 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: