November 2nd – Sound samples revisited

I haven’t done anything specifically related to Vectorblade for over a months now.

I am thinking about stuff to “fill” it up a little more besides pure gameplay. Little stuff that will make a complete “round” package.

You have seen an Intro Test, I have done the disk, I have done a new/seperate highscore editing (not shown yet) – and I have improved the tile base engine to be prepared to do collision detection (which might lead to an extra “game – gem” – or not).
I will probably use very little of what I have researched so far – because I don’t realy fancy it anymore …

The “sample gambling” described in this blog entry also originated in that search.


Sound Samples 1

In general – the Vectrex can play digitized sounds. The first game to support this was Spike:
“Eeek, Help, Spike!” – “Oh No, Molly!”

On the technical side this is possible since the DAC output can be (electronically) connected* to the amplifiying hardware.
If the sound samples are in the correct format, and the sample bytes are output frequently enough to that hardware (e.g. 8000Hz sample rate -> 8000 bytes per second to the output…) – than you can listen to sampled sound.

I have never taken measurement – but I think Spike might have a sample rate of something between 3000 – 4000Hz.

The sound format is: PCM unsigned, 8 bit.

The challenge with playing samples is the above “frequently enough”. If we take the example from above (8000Hz), a digitized sound byte must be played every 188 cylces.
(
6809 clockspeed 1.5Mhz
-> 1 secound = 1500000 cycles, 8000 sampels per second ->
1500000/8000 = 187.5 -> every 187.5 cycles a sample must be played
)

Playing a sample itself (reading the byte, preparing output etc), takes also some cycles, lets say the sample output takes about 60 cycles. In summary you than:

  • have only 2/3 of cycles for the rest of your program
  • the program must be interrupted each 188 cylces for about 60 cycles
  • due to technical limitations the sound output can NOT be done while theĀ  vector hardware is active in any way

These are pretty steep restrictions – this is one of the reasons, why you see very few programs, that make use of samples. And even less programs that incorporate digitized sound during gameplay.

Additionally

For undisclosed reasons accessing the audio hardware does not work properly on newer vectrex versions. The so called “No Buzz” Vectrex do not play digitized sound correctly – they do still play the sound, but it is even in full volume only barely audible.

Sound Samples 2

Especially above mentioned “additionally” was a thing that always bothered me. For quite some time I was thinking:
“sample playing must also be possible by using the PSG chip”.

Some weeks ago I started trying that out, I wrote a small program, that would output samples to the PSG chip.
In general:
– sound samples are (more or less) volume levels. My thought was – “if I output these volume levels to the PSG – I ought to be able to play samples using the volume registers”

My first tryouts were quite bad.

I could hear some “scratching noise”, that was in the rythm of the digitized sound that I wanted to play – but that was about it.

Several tryouts later I discovered the reason: I had to use a different sample format.
I don’t exactly know why, but playing digitized sound via the PSG you have to use the format:

PCM signed

During my search I also found a couple of interesting links:
Playing samples on the PSG
Playing samples on the PSG
Crystal clean PCM 8bit samples on the poor PSG

Which provided some information.

The volume levels of the PSG are encoded in only 4bit. Thus the sound format “complete” is: PCM signed 4 bit.
The volume level is based on a “logarithmic volume scale” so in reality the above mentioned 4 bits are more something like 2.5 – 3 bits. The number of volume levels available restrict the quality of samples.

The gist is by using the PSG as digitized sample output:

– negative: reduction of sample quality from 8bit to about 3bit
– negative: the playback routine needs more cycles (PSG-Registers are harder to access than the audio hardware)
– positive: the sample size is only half as big
– positive: playback is “constant” on all vectrex
– other: playback is a little bit softer than audio hardware using samples on “buzz” machines

Note 1:
On the above pages it is mentioned, that the quality can be enhanced by adding sound levels of more than one PSG channel.
I tried that – and failed. That might be prone to my programming skills – but I rather suspect, that due to the “complicated” way that PSG-registers are accessed in the vectrex hardware, that the timing with which the volume levels are put into the 3 PSG channels differs to much to produce clean samples (30-40 cycles needed for each individual channel).

Note 2:
On above pages it is suggested that the volume levels from the samples could be “translated” to corresponding PSG levels (linear versus logarithmic). I tried that also – which resulted in an audible pessimation rather than an optimization.

The next Vide version will feature a method to build samples and generate a player for above PSG “Samples”.

Following some of the used source code:

Write data in B to PSG register in A, here you see why it is more complicated to write to PSG registers.

WRITE_PSG_DIRECT macro
                    STA      <VIA_port_a                  ;store register select byte 
                    LDA      #$19                         ;sound BDIR on, BC1 on, mux off _ LATCH 
                    STA      <VIA_port_b 
                    LDA      #$01                         ;sound BDIR off, BC1 off, mux off - INACTIVE 
                    STA      <VIA_port_b 
                    LDA      <VIA_port_a                  ;read sound chip status (?) 
                    STB      <VIA_port_a                  ;store data byte 
                    LDB      #$11                         ;sound BDIR on, BC1 off, mux off - WRITE 
                    STB      <VIA_port_b 
                    LDB      #$01                         ;sound BDIR off, BC1 off, mux off - INACTIVE 
                    STB      <VIA_port_b 
                    endm

 

This macro must be called whenever we have “time”.
It waits for the next timestep, where a sample must be played, outputs the sample nibble and restarts the timer.
(this can be optimized)

NEXT_DIGIT_BYTE_FASTER_NO_I_4bitPSG  macro                ; name of macro 
; load current digit byte and increment counter
                    WAIT_FOR_NEXT_DIGIT                   ; otherwise we wait till the last played 
                                                          ; sample-byte is finnished 
                    CMPY     digit_end_pos                ; if it is zero, than we are finnished 
                    BNE      sound_not_done               ; with this sample, otherwise we continue further below 
; if we are done, should we restart?
sound_done: 
                    LDA      digit_looping                ; is this sample a looping one? 
                    STA      digit_is_playing             ; store it to is_playing 
                    BEQ      timer_restart_only           ; if none looping... we are done 
                                                          ; but we still must use the timer 
; ok, for restart, we only change current position
                    LDY      digit_start_pos              ; load the start position 
                                                          ; this is the end_position of the sample, 
                                                          ; since we go backwards 
                    BRA      timer_restart_only           ; and restart the timer, next byte 

                                                          ; is played next round... 
; here our normal 'digit_byte_playing_section'
sound_not_done: 
                    tst      digit_oddEven 
                    beq      doFirstNibble 
                    LDb      ,Y+                          ; load the next sample_byte to A 
                    andb     #%00001111 
                    clr      digit_oddEven 
                    bra      doDigitOutput 

doFirstNibble 
                    LDb      ,Y                           ; load the next sample_byte to A 
                    lsrb     
                    lsrb     
                    lsrb     
                    lsrb     
                    inc      digit_oddEven 
doDigitOutput 
; to reg 8 (Amplidtude)
                    lda      #8 
                    WRITE_PSG_DIRECT  
timer_restart_only: 
                    RESTART_TIMER                         ; restart timer... 
makro_rts: 
                    endm                                  ; end of macro 

I have put a small example together:

(18kB)

A sample is played and a frog displayed.
The sample has a sample rate of 8000Hz and is output via PSG using 4bit samples.
The time between samples (in cycles) is about the above mentioned 188 cycles.

The time needed for playing the samples (in cycles) is about 70 cycles – thus about 110 cycles are left to draw vectors.
The vectors displayed are drawn with a scale of 50.

I was not yet able to display raster text reliably.

Regards

Malban

 


* Technically:
To put a sample byte to the amplifying hardware:
– you have to use the VIA
– the DAC output has to switched to “audio hardware”
– this is done using the MUX connected to VIA
– to select MUX settings Via Port B is used
– bit 0 is the MUX enable bit (zero active)
– bit 1+2 selects the “destination”, bit 1=1 and bit 2=1 selects the audio hardware
– first you set 11 to bit 1 and 2, and prepare the MUX to send bytes to the audio hardware
– you set the DAC value using VIA port A
– you set VIA port A to the sampled byte
– than you set Via Port B bit 0 to 0 (zero) -> the audio hardware will receive DAC values
– > you just put one sample byte to the audio hardware
– (don’t forget to clean up the VIA Port B)

2 thoughts on “November 2nd – Sound samples revisited

  1. Graham Toal

    Interesting that the “vectrexy” emulator fails to play any audio with this binary! (I’ll play it on the hardware tomorrow – it was already quite late tonight when I saw this post)

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.