Viterbi Encoded Sound Sample
Viterbi Encoded Sound Sample
Here's my first attempt of replaying a 4kHz viterbi encoded sample on the 3 channels of the AY sound chip.
The original sound file : The Oric program to play it: (press a key to start and press a key when you've got enough)
Tell me what you think ? do you think it is a good sound quality ?
The original sound file : The Oric program to play it: (press a key to start and press a key when you've got enough)
Tell me what you think ? do you think it is a good sound quality ?
Re: Viterbi Encoded Sound Sample
Oups .. I realize I forgot to adapt the encoder to the timing of the replayer.
I think I can enhance the fidelity a little bit.
In fact the encoder takes into account the number of cycle it take for the replayer to write the register into the AY.
I used an approximative value because I didn't know what would the replayer look like when I wrote the encoder.
Now that I have a replayer, I have to calculate the number of cycle between two writing in the AY, and then configure the encoder accordingly.
I think I can enhance the fidelity a little bit.
In fact the encoder takes into account the number of cycle it take for the replayer to write the register into the AY.
I used an approximative value because I didn't know what would the replayer look like when I wrote the encoder.
Now that I have a replayer, I have to calculate the number of cycle between two writing in the AY, and then configure the encoder accordingly.
Re: Viterbi Encoded Sound Sample
Interesting! ... but IMHO it can be lot better .
Just an idea: use the sample WAV from DBug's demo which speaks 'Welcome' (can be found in the OSDK), so we can compare both players. Additionally you can optimize the IRQ routine - you save the registers to ZP *and* save them again with PHA's - use only the first one.
Waiting for the improvements ...
Just an idea: use the sample WAV from DBug's demo which speaks 'Welcome' (can be found in the OSDK), so we can compare both players. Additionally you can optimize the IRQ routine - you save the registers to ZP *and* save them again with PHA's - use only the first one.
Waiting for the improvements ...
Re: Viterbi Encoded Sound Sample
That's a great idea but I don't have the original wav file.
I've only got the already encoded version
I need the wav file to encode it with the Viterbi stuff.
how the hell do you know that ?? You're exactly right !!
Re: Viterbi Encoded Sound Sample
I can't find the source WAV too. Attached in ZIP file are compiled welcome.tap and 'one-step' moon-landing phrase as tap and 4k 8bit WAV. Hope this helps somehow...
- Attachments
-
- samples.zip
- (18.66 KiB) Downloaded 214 times
Re: Viterbi Encoded Sound Sample
Dbug gave me the link of a youtube video of Barbarian 2 which is the game he had taken the "Welcome" from.
I downloaded the audio of the video, extracted the "welcome" and now my computer is encoding the sample (it takes something like 1 hour per second)
I should be able to produce a tap file within a few hour.
Thank you, I will encode it as well.
There's one thing where your help could be very valuable.
As I was inspecting the audio that comes from the Oricutron playing the sample, I noticed some time glitch in the replaying.
Look at the phenomena (top signal is the original signal, bottom is the oricutron audio recorded) at different zoom level:
I've got a keyboard interrupt at 25 HZ which is supposed to be interruptible while the replayer's interrupt at 4kHz is supposed to be uninterruptible
So I wonder where this phenomena comes from ..
Any clue ?
I'm gonna give the source code if you want to cast a glance at it .. if never you could help solve this issue ..
Re: Viterbi Encoded Sound Sample
IMO, 2 possible sources for the missing samples:
- Oricutron doesn't fill the audio buffer properly - unlikely;
- player code takes too many cycles and misses interrupt signal from time to time.
When you attach test sample I will check it for missing pulses also on real Oric.
EDIT: can you describe how you write to the 3 volume registers?
Re: Viterbi Encoded Sound Sample
Sharing the important parts of the code would help
Could be all kind of issues, and ultimately it would also be important to compare with a real Oric, just to eliminate possible issues with emulation/host machine.
Could be all kind of issues, and ultimately it would also be important to compare with a real Oric, just to eliminate possible issues with emulation/host machine.
Re: Viterbi Encoded Sound Sample
Well, it is very disappointing.
The produced waveform is not so that bad .. but there are some moment where the signal remains flat.
You might be right when you say that some interruption are missed .. but I don't see how I can avoid that
The wecome.tap : The source code (with encoder): The problem that ruins the sound quality:
The produced waveform is not so that bad .. but there are some moment where the signal remains flat.
You might be right when you say that some interruption are missed .. but I don't see how I can avoid that
The wecome.tap : The source code (with encoder): The problem that ruins the sound quality:
Re: Viterbi Encoded Sound Sample
Here's the code of the 4kHz interrupt which writes the AY register values:
It is in the tasks_s.s file in the archive provided in my previous post.
Code: Select all
#define LATCH_REG_NUMBER sta via_porta:lda #$EE:sta via_pcr:lda #$CC: sta via_pcr
#define LATCH_REG_VALUE sta via_porta:lda #$EC:sta via_pcr:lda #$CC: sta via_pcr
TASK_4KHZ:
.(
ldy _position_low
lda (_ptr_wrt1), y
tax
and #$F0
lsr
lsr
lsr
lsr
LATCH_REG_NUMBER
txa
and #$0F
LATCH_REG_VALUE
lda (_ptr_wrt2), y
tax
and #$F0
lsr
lsr
lsr
lsr
LATCH_REG_NUMBER
txa
and #$0F
LATCH_REG_VALUE
lda (_ptr_wrt3), y
tax
and #$F0
lsr
lsr
lsr
lsr
LATCH_REG_NUMBER
txa
and #$0F
LATCH_REG_VALUE
inc _position_low
bne skipNext256
inc _position_high
inc _ptr_wrt1+1
inc _ptr_wrt2+1
inc _ptr_wrt3+1
skipNext256
lda _position_low
cmp #<NB_SAMPLE
bne skipResume
lda _position_high
cmp #>NB_SAMPLE
bne skipResume
restartsample
lda #<_bwrt1
sta _ptr_wrt1
lda #>_bwrt1
sta _ptr_wrt1+1
lda #<_bwrt2
sta _ptr_wrt2
lda #>_bwrt2
sta _ptr_wrt2+1
lda #<_bwrt3
sta _ptr_wrt3
lda #>_bwrt3
sta _ptr_wrt3+1
lda #0
sta _position_low
sta _position_high
skipResume
task4kHz_done
.)
rts
Re: Viterbi Encoded Sound Sample
Some small remarks about the code.
- If you swap the register number and value nibbles in your byte, you can avoid one of the "and #15" because after the four lsr the top nibble would be set to zero (that means three less immediate and, so 6 cycles per IRQ, 480 cycles per frame, almost 2.5% of the total CPU time)
- Make sure your sample is page aligned, so _ptr_wrt1/2/3 are not doing page cross when adding y, to avoid one more cycle per access, which also means on restartsample you could avoid all the lda #<_bwrt1/2/3 because they should just use the same "lda #0" you had at the end
You can also probably simplify the handling of the pointer increments/reset:
- The previous value of _position_low is still in the y register, so the lda _position_low feels a bit unnecessary (instead of the "inc _position_low" (5 cycles) you could "iny / sty _position_low" (2+2 cycles), so remove the lda _position_low and replace the cmp by a cpy)
Now, regarding the Viterbi algorithm, have you implemented the computation of delay between the writing to each of the three registers?
- If you swap the register number and value nibbles in your byte, you can avoid one of the "and #15" because after the four lsr the top nibble would be set to zero (that means three less immediate and, so 6 cycles per IRQ, 480 cycles per frame, almost 2.5% of the total CPU time)
- Make sure your sample is page aligned, so _ptr_wrt1/2/3 are not doing page cross when adding y, to avoid one more cycle per access, which also means on restartsample you could avoid all the lda #<_bwrt1/2/3 because they should just use the same "lda #0" you had at the end
You can also probably simplify the handling of the pointer increments/reset:
- The previous value of _position_low is still in the y register, so the lda _position_low feels a bit unnecessary (instead of the "inc _position_low" (5 cycles) you could "iny / sty _position_low" (2+2 cycles), so remove the lda _position_low and replace the cmp by a cpy)
Now, regarding the Viterbi algorithm, have you implemented the computation of delay between the writing to each of the three registers?
Re: Viterbi Encoded Sound Sample
Thanks @Dbug, you shorten my list!
Here are some remarks from me:
- you reserve 2 bytes to store the address of old IRQ handler but use:
- it's VIA T1 specific - to set the period to 250 uS you have to write a value with 4 less i.e.:
- now the biggest issue - the time spend in the IRQ handler: TASK_4KHZ takes 220+ uS and if the TASK_25Hz is executed - it takes 968+ uS! Obviously this is the reason for the missing samples .
The easiest solution here is to remove the TASK_25Hz (i.e. the keyboard handler) from the IRQ subroutine and move it as polling routine in the main loop.
Once this is fixed then in your IRQ handler called every 250 uS the time is divided as follow:
So, again as @Dbug said: you need to take into account the above delays when pre-calculating register values.
IMHO, there is possible to use an optimization to simplify the code and reduce its size: you can use shorter period 250/3 = ~83 uS and in the handler to write to only one register .
I'm really sorry if my remarks sound too critical but I'm sure we can turn this whole thing in something good and useful - don't give up!
Here are some remarks from me:
- you reserve 2 bytes to store the address of old IRQ handler but use:
Code: Select all
; Save the old handler value
lda $245
sta jmp_old_handler+1 ; <- should be +0
lda $246
sta jmp_old_handler+2 ; <- should be +1
Code: Select all
;; Set the VIA parameters (250 = 4Khz, )
lda #<(VIA_TIMER_DELAY_4KHZ-4)
sta $306 ;; via_t1ll
lda #>(VIA_TIMER_DELAY_4KHZ-4)
sta $307 ;; via_t1lh
The easiest solution here is to remove the TASK_25Hz (i.e. the keyboard handler) from the IRQ subroutine and move it as polling routine in the main loop.
Once this is fixed then in your IRQ handler called every 250 uS the time is divided as follow:
Code: Select all
irq_handler_4khz:
....
jsr TASK_4KHZ
...
secval ; <- here the VOL_A is updated 71 cycles relative to irq_handler_4khz
....
....
thirval ; <- here the VOL_B is updated 124 cycles relative to irq_handler_4khz (or 53 cycles rel. to secval)
....
....
endval ; <- here the VOL_C is updated 177 cycles relative to irq_handler_4khz (or 53 cycles rel. to thirval)
....
rti ; <- 220+ cycles
IMHO, there is possible to use an optimization to simplify the code and reduce its size: you can use shorter period 250/3 = ~83 uS and in the handler to write to only one register .
I'm really sorry if my remarks sound too critical but I'm sure we can turn this whole thing in something good and useful - don't give up!
Re: Viterbi Encoded Sound Sample
What about replacing
by
Code: Select all
lda (_ptr_wrt1), y
tax
lsr ; 2 cycles
lsr ; 2 cycles
lsr ; 2 cycles
lsr ; 2 cycles
LATCH_REG_NUMBER
txa
and #$0F
LATCH_REG_VALUE
Code: Select all
lda (_ptr_wrt1), y
tax
lda TableWithTheNibblesPreshifted,x ; 4 cycles
LATCH_REG_NUMBER
txa
and #$0F
LATCH_REG_VALUE
Re: Viterbi Encoded Sound Sample
OK guys !!
I thank you for very much for all your valuables comments.
I took into account all your remarks (except the last one from DBUG that I've just seen (and which look cool)).
Here is the code repository:
https://github.com/jbperin/ayPlaySample
I must admit I failed to get the keyboard routine out from the IRQ handler to the main loop. But I added a flag USE_KEYBOARD_INTERRUPT to disable the call to the 25 hz task .. and I noticed no specific amelioration when I use it.
And I'm not so surprised about that because I designed the stuff so that the keyboard dedicated part of the IRQ handler is interruptible and then the 4kHz interrupt allways have priority.
This is why I put the bit $304 just after the jsr TASK_4KHZ and before the 25Hz stuffs in the irq_handler.
Moreover, and that's what I would like to bring your attention to, I have analysed the problem and I noticed that:
- the first is the welcome.tap from DBug's demo
- the second is the viterbi welcome.tap with no keyboard handler
- the last one is the viterbi with 25Hz interrupt enabled
Can anyone tell me if, when you play the following TAP file in your oricutron:
You hear something like that:
If not .. could you record for me what you hear ?
I thank you for very much for all your valuables comments.
I took into account all your remarks (except the last one from DBUG that I've just seen (and which look cool)).
Here is the code repository:
https://github.com/jbperin/ayPlaySample
I'm not so sure about that.iss wrote: ↑Sat Aug 07, 2021 12:29 pm - now the biggest issue - the time spend in the IRQ handler: TASK_4KHZ takes 220+ uS and if the TASK_25Hz is executed - it takes 968+ uS! Obviously this is the reason for the missing samples .
The easiest solution here is to remove the TASK_25Hz (i.e. the keyboard handler) from the IRQ subroutine and move it as polling routine in the main loop.
I must admit I failed to get the keyboard routine out from the IRQ handler to the main loop. But I added a flag USE_KEYBOARD_INTERRUPT to disable the call to the 25 hz task .. and I noticed no specific amelioration when I use it.
And I'm not so surprised about that because I designed the stuff so that the keyboard dedicated part of the IRQ handler is interruptible and then the 4kHz interrupt allways have priority.
This is why I put the bit $304 just after the jsr TASK_4KHZ and before the 25Hz stuffs in the irq_handler.
Code: Select all
irq_handler_4khz:
.(
;Preserve registers
sta irq_A: stx irq_X: sty irq_Y
jsr TASK_4KHZ ; TASK_4KHZ_4BITS ;
bit $304
#ifdef USE_KEYBOARD_INTERRUPT
dec itCounter: bne not100Hz
lda #160: sta itCounter ; 4000 / 25 Hz
TASK_25Hz
not100Hz
#endif // USE_KEYBOARD_INTERRUPT
;Restore Registers
lda irq_A: ldx irq_X: ldy irq_Y
rti
.)
- The problem of the flat signal occurs on my Welcome.tap as well as the one of Dbug. (so It might not be due to something specific in my code)
- The phenomena of signal remaining flat happens on a regular basis and with a repeated pattern
46 ms of signal,
6 ms of steady condition,
46 ms of signal
6 ms of steady condition,
92 ms of normal signal
... and then it loop ..
- the first is the welcome.tap from DBug's demo
- the second is the viterbi welcome.tap with no keyboard handler
- the last one is the viterbi with 25Hz interrupt enabled
Can anyone tell me if, when you play the following TAP file in your oricutron:
You hear something like that:
If not .. could you record for me what you hear ?
Re: Viterbi Encoded Sound Sample
If you save registers like that, your IRQ is not reentrant, they will overwrite the status.jbperin wrote: ↑Sat Aug 07, 2021 7:44 pm This is why I put the bit $304 just after the jsr TASK_4KHZ and before the 25Hz stuffs in the irq_handler.Code: Select all
;Preserve registers sta irq_A: stx irq_X: sty irq_Y jsr TASK_4KHZ ; TASK_4KHZ_4BITS ; bit $304
For reentrant IRQ you need to use different locations for the various calls, generally done using the stack.