Author
| PCM player using SCC
|
ARTRAG msx master Posts: 1592 | Posted: October 12 2007, 16:41   |
Quote:
|
If I understand this correctly the frequency of the sample is played is 32x bigger (one step rotation after playback of whole 32 byte sample)
|
Why you say that ?
Form wiki it seems that 32x is only the frequency of rotation, not the playing frequency that should stay 1x
Moreover I was thinking that the fact you cannot write the samples refers only to the fact you cannot know
where to write, not to the fact that samples are locked....
|
|
NYYRIKKI msx master Posts: 1503 | Posted: October 12 2007, 17:12   |
Quote:
|
Why you say that ?
Form wiki it seems that 32x is only the frequency of rotation, not the playing frequency that should stay 1x
|
I don't really know, but in this case the sound should be same with rotation and without... How ever it has some effect to the sound it self but not to pitch. Don't know the details. Maybe it would be good idea to sample the outputted sound to really know what happens.
Quote:
|
Moreover I was thinking that the fact you cannot write the samples refers only to the fact you cannot know
where to write, not to the fact that samples are locked....
|
I did some testing long time ago and IIRC the samples are really locked... How ever I suggest you to test this again... I didn't do proper testing and didn't make memos.
|
|
Metalion msx freak Posts: 215 | Posted: October 12 2007, 17:13   |
Quote:
| You need to write 4 bytes each 2 scanlines, so you have barely the time
to fetch the current bytes of the samples or to change the current samples
(maybe swapping memory pages)
|
You need to write those 4 bytes every 125µs (8kHz).
At 50Hz, it means you have to write those 4 bytes every 1/160th of a frame.
The interrupt routine ($38) takes approximately 6500 T-states on an MSX2, or 1/9th of a frame.
It means that you cannot do it on scanline IRQ, not unless you handle that IRQ out of the BIOS.
So you can only do it in the main code, and you have only 447 T-states to fetch the data before writing again (and we know that we will probably need all those T-states because the data will certainly be compressed). Once again, it means that you cannot use IRQs (remember the 6500 T-states used) to do something else or that you have to handle them outside of the BIOS ... and be really efficient about it.
|
|
NYYRIKKI msx master Posts: 1503 | Posted: October 12 2007, 18:30   |
This is a bit offtopic, but a nice idea I think.
I also once tried to get sample playing on backround on SCC. Unfortunately I just didn't have enough nerves to get the timing right. Here is anyway the idea explained if someone wants to try it.
Basics: SCC has 128 bytes of sample RAM. One channel is 32 bytes that is enough to produce 1920Hz sample on 60Hz (32 samples * 60). This is not enough to actually call it a "sample in backround".
Idea: If you play 4 channels at 1920Hz and start each of the samples at different time you can produce 7680Hz sample (4*1920Hz) that is actually already pretty close to 8kHz
I hope this "picture" gives better idea what I'm after:
chA 1111222233334444555...
chB 111122223333444455...
chC 11112222333344445...
chD 1111222233334444...
Example of sample conversion algorithm from SCC data to 4ch SCC data:
A1=<Sample byte 1>
B1=<Sample byte 2>-A1
C1=<Sample byte 3>-A1-B1
D1=<Sample byte 4>-A1-B1-C1
A2=<sample byte 5>-A1-B1-C1-D1
B2=<Sample byte 6>-A2-B1-C1-D1
C2=<Sample byte 7>-A2-B2-C1-D1
D2=<Sample byte 8>-A2-B2-C2-D1
A3=<Sample byte 9>-A2-B2-C2-D2
.
.
.
|
|
ARTRAG msx master Posts: 1592 | Posted: October 12 2007, 18:35   |
I realized that the initial idea is very bad as the dummy time is almost zero.
I have another proposal.
This is the new idea:
Provided that the rotation of the wave table does not affect the sound
(@NYYRIKKI I have no real HW ATM sorry I cannot test this) we can reserve
the lowest bit of the channel as flag (a huge waste I know).
All the samples have to be prepared having the last bit reset except for
those multiple of 32, where the bit is set.
the algorithm is this:
Prepare the channel as before
0) do you staff here in less than 125us (if at 8KHz)
1) test bit 0 in byte #1 of the channel used for replay
2) if it is reset goto 1
3) LDIR the next 32 samples in the wavetable
4) goto 0
in this way you have plenty of 447 T states for your staff
If you want 8bit accuracy and you have some unused channels, you
can use an unused channel in the way above as counter.
NYYRIKKI what you think of this ?
|
|
ARTRAG msx master Posts: 1592 | Posted: October 12 2007, 18:46   |
@NYYRIKKI
sorry but ur idea cannot work
the 4 channels play they samples at the same time
To get 4 times the sample frequency you need 4 different sub_sample offesets
In your way, the sole result you have is that the 4 channels sums among them
so in theory you can get better accuracy on the sample
i.e. 10bits instead of 8bit/sample, but not a higher frequency
|
|
NYYRIKKI msx master Posts: 1503 | Posted: October 12 2007, 19:08   |
Quote:
| To get 4 times the sample frequency you need 4 different sub_sample offesets
|
This is exactly what I was trying to explain... Is there a reason why 4 different sub_sample offsets can not be done?
|
|
NYYRIKKI msx master Posts: 1503 | Posted: October 12 2007, 19:17   |
Quote:
| NYYRIKKI what you think of this ?
|
I think this could work... but I'm still not sure how the rotation really works... Somehow I just have a feeling that it is not all documented correctly yet. BTW someone should add the rotation direction to Wiki.
|
|
ARTRAG msx master Posts: 1592 | Posted: October 12 2007, 19:49   |
Quote:
| Quote:
| To get 4 times the sample frequency you need 4 different sub_sample offesets
|
This is exactly what I was trying to explain... Is there a reason why 4 different sub_sample offsets can not be done?
|
Sorry, but each channel has to go at 8Khz
now i see your idea a bit better and I like it
The problem is to know how update the samples.
Actually I'm not sure if I've got this point from your idea:
let me recollect:
you can output 32*60Hz = 1920 bytes/sec
and this on 4 channels, i.e. corresponding to 7680 bytes/sec
If you stay with one channel you should set
the Fsample = 1920 Hz
This would allow you to get "perfect" synchronization (apart the actual problem you can get jitters and sample losses due to interrupt latency)
Now my problem in understanding
IMHO if you use your trick in order to get higher frequency you MUST have an higher Fsample and you MUST replicate
samples 4 times in order to add them.
I do not see other ways to tune the phase of sub channels.
And this is THE issue.
To be clearer, in order to apply your trick:
the Fsample of all channels has to increase to 7680 Hz and bytes on each channel has to be replicated 4 times
thus :
a) the length of the waveform tables should be 4 times longer
or
b) you find an interrupt source at 240Hz
|
|
NYYRIKKI msx master Posts: 1503 | Posted: October 12 2007, 20:39   |
Quote:
|
let me recollect:
you can output 32*60Hz = 1920 bytes/sec
and this on 4 channels, i.e. corresponding to 7680 bytes/sec
If you stay with one channel you should set
the Fsample = 1920 Hz
This would allow you to get "perfect" synchronization (apart the actual problem you can get jitters and sample losses due to interrupt latency)
|
At this point we agree. The interrupt latency can cause some jittering, but how long it takes to get into your custom interrupt routine does not matter as long as you have initialized the SCC inside interrupt routine. (it should always take same time.) So the actual difference happens only if interrupt happens when interrupts are disabled. This is anyway reality and it is even very likely that you hear some noice. In my test I syncronized SCC in every interrupt, but I still didn't get it quite right. As I could not record the playback at that time I gave up...
Quote:
|
Now my problem in understanding
IMHO if you use your trick in order to get higher frequency you MUST have an higher Fsample and you MUST replicate
samples 4 times in order to add them.
I do not see other ways to tune the phase of sub channels.
And this is THE issue.
|
What I was doing I used bit 5 in deformation register and wrote the freq registers at correct time. Actually I didn't ever verify if it works or not. Maybe this could be a good starting point.  If it does not work then what about if I try to play higher freq sound only a very short perioid of time first? (half a sample or so...)
I really don't know enough of the inner parts of SCC to say anything sure about this issue... At least in PSG it is possible to get syncronization out of phase, but it is also otherways completely different device.
|
|
ARTRAG msx master Posts: 1592 | Posted: October 12 2007, 20:48   |
About bit 5 in deformation register:
From what I see on WIKI, setting it implies that the play of all the waveforms is reset.
So you cannot get offsets among channels in this way.
Unless not having 4 different "bit 5" one per channel, this way cannot lead to channel
offsets....
|
|
NYYRIKKI msx master Posts: 1503 | Posted: October 12 2007, 20:58   |
"If bit 5 is set, waveform playback is started from the beginning when a frequency register is written to"
So yes... They can be in different offsets but I don't know if the difference can be for example 0.25 or can it only be whole numbers. It depends, how accurate the freq counter is.
|
|
NYYRIKKI msx master Posts: 1503 | Posted: October 12 2007, 21:11   |
Actually, now that I look at the formula of freq
ftone=fclock/32*(p+1)
I see that this 32 is number of samples, so it is very likely that you are right and there is no half or quater steps inside SCC. Because this is same formula as with PSG it is likely that PSG can divide its sawtooth to 32 steps.
|
|
ARTRAG msx master Posts: 1592 | Posted: October 12 2007, 21:16   |
About the second point.... something can be done.....
but you need to accept severe distortion in high frequencies....
set ch1 at 1920Hz
set ch2 at 2X1920Hz
set ch3 at 3X1920Hz
set ch4 at 4X1920Hz
Lowpass the input at 1920/2
resample the result at 1920 Hz
segment the result in 32 byte bulks
this is channel 1
Lowpass the input at 1920
resample the result at 2x1920Hz
resample channel 1 at 2x1920Hz
subtract the two signals
segment the result in 64 byte bulks
choose which part composed by 32 successive bytes of the signal has
the highest energy (slide cyclically the 64 bytes finding the 32 bytes with
highest sum of the squares)
keep the bulks of 32 bytes composed in this way
they are channel 2
Lowpass the input at 1920x3/2
resample it at 1920x3Hz
take channel 1
resample it at 2x1920Hz
add ch1 to chl 2 (replicating twice each 32byte bulk of ch2)
resample the result at 1920x3Hz
subtract the result from the input lowpassed and resampled at 1920x3Hz
now segment the result in chunks of 32*3=96 bytes
for each chunk find the 32bytes with highest energy as before
keep the bulks of 32 bytes composed in this way
they are channel 3
do the same with channel 4
i.e.
lowpass the input at 1920x2Hz
resample the input at 1920x4Hz
subtract the reconstruction you have up to know using ch1+ch2+ch3 (replicate chunks of ch2 twice and those of ch3 tree times)
segment the result in chunks of 32*4=128 bytes
select in each chunk the 32bytes most representative
you get channel 4
what distortion you get ?
easy
channels with frequencies higher than 1920 replicate their samples in time.
actually
ch 2 replicate its samples 2 twice, ch3 tree times, ch4 four times.
This implies that in the spectrum some frequencies are cancelled (actually the spectrum is sampled)
moreover relative phases among channels are distorted, as we select the part of signal with more
energy, but this shouldn't be a big problem as we are not very sensible to phase distortion.
Do you like this idea ?
|
|
NYYRIKKI msx master Posts: 1503 | Posted: October 12 2007, 21:37   |
Ah, at least this is something I would have not ever thought. I just love your signal prosessing skills
Unfortunately I'm not that good at thinking how this might work out, but it may be a good solution...
At the moment I was thinking going back to 1ch representation of sample. How about this:
We make channel 4 & 5 rotating and keeping accurate track of when to update sample. ch1 is used for sample and the sample is updated 4 times in a screen update using custom lineinterrupts of VDP and polling the ch4.
To minimize the wait time caused by different time of executing the BIOS interrupt routine channel 4 can contain values from 32 to 0 (volume 0)and lineinterrupt can be adjusted on fly by using the first read value from the ch4.
|
|
|
|
|