CPCWiki forum

General Category => Programming => Topic started by: Ast on 00:43, 27 December 14

Title: Sample frequency
Post by: Ast on 00:43, 27 December 14
hello,


My question is :


I've done a sample played using dma on Cpc Plus. How can i do to change the frequency of my sample.
For example, i play A note and i wanted to play A#. Can someone help me ?
Title: Re: Sample frequency
Post by: Ast on 18:39, 29 December 14
Has anyone got an idea ??




















Title: Re: Sample frequency
Post by: Targhan on 20:04, 29 December 14
Sorry to ask, but how did you play Sids in one of your demo, whereas you can't imagine how to change a sample replay ?


Anyway... Playing one sample ("byte") every "tick" plays the sample at its normal frequency. Playing one sample out of two will double its replay frequency. Now you must find a way to play a sample and jump "less than a byte" further to play the intermediate notes. You can check my article on Push'n'Pop (http://pushnpop.net/articles-15.html) about Zooming, it's exactly the same thing.
Title: Re: Sample frequency
Post by: Ast on 20:30, 29 December 14

Nice to see you Targhan.


I already know what you say here. What I want to know is :
How can I find the correct value ? Just doing that from scratch ? Earing each note ? Is it a faster way to precalc all that ?


Thanks.
Title: Re: Sample frequency
Post by: Prodatron on 22:19, 29 December 14
Have a look here:

Piano key frequencies - Wikipedia, the free encyclopedia (http://en.wikipedia.org/wiki/Piano_key_frequencies)

A has 440.000Hz, A# has 466.164Hz.
That means, you have to play the sample, which is based on A, 1,0594636times faster to get a A# (= 466.164 / 440.000).

Title: Re: Sample frequency
Post by: Ast on 22:23, 29 December 14
Thanks Prodatron  :D



Title: Re: Sample frequency
Post by: opqa on 23:00, 29 December 14
Generally speaking, the frequency relation between 2 notes is given by 2^(n/12), where n stands for the number of semitones separating those two notes.

In your example n=1 as this is the distance between A and A#, it would be n=2 to pass from A to B for instance. Take in account that some notes are separated by 2 semitones while other only by 1, e.g: n=1 between E and F or between B and C.

Also, it would be helpful if you explained a little bit more what you're trying to achieve. If you want to make some kind of execution-time effect or transposition then you have to use this trick.

But if what you have is a sample and you want to transpose it just once and play it always the same in the CPC there are better ways to do it. The play-it-faster/slower trick to change pitch is effective, but it shortens of lengthens the duration of the sample as a side effect. Modern audio processing tools like Audacity can process a recording and change its pitch without affecting its duration. Though the best option, if you can, is just to redo the sample from scratch with the desired tone.
Title: Re: Sample frequency
Post by: Prodatron on 23:59, 29 December 14
I think it's impossible to play samples in realtime on the CPC with different pitches in a way, that their lengthes stay the same.
So I think the "simple" faster/slower methode is still the best one.
In Digitracker I used fixed-point values for moving the sample pointers (8bit+8bit IIRC). If it's played 1:1 the lower 8bit part is 0 and the higher 8bit part is 1.
Calculating such values can be done by using the formular by Opqa.
Title: Re: Sample frequency
Post by: Targhan on 12:32, 30 December 14
If like me you don't like math, don't hesitate to do it by ear, it works fine :). After all, it's only 12 notes to find.
Title: Re: Sample frequency
Post by: Ast on 14:18, 30 December 14
I'll try probably the 2 possibilities, and I'm certain to find some differences. 8)
Title: Re: Sample frequency
Post by: opqa on 16:33, 30 December 14
I don't know how DMA playing works on the Plus, if calculating when to skip one sample needs to be fast and you don't need a lot of accuracy I've thought a way to do it that would be really fast. I involves only one 8-bit register and constant additions to it. I could explain it if you're interested.
Title: Re: Sample frequency
Post by: Prodatron on 16:47, 30 December 14
Quote from: opqa on 16:33, 30 December 14
I don't know how DMA playing works on the Plus, if calculating when to skip one sample needs to be fast and you don't need a lot of accuracy I've thought a way to do it that would be really fast. I involves only one 8-bit register and constant additions to it. I could explain it if you're interested.

You probably know WEEE!s DMA music demo (http://www.cpcwiki.eu/index.php/DMA_Music_Demo) (unfortunately I can't find a video on YouTube...). AFAIK it's generating one 50Hz sample part for each channel in each frame with this byte skipping methode. The DMA of the Plus isn't able to play samples with different speeds in a way that you can play them like on the Amiga.
Title: Re: Sample frequency
Post by: andycadley on 19:16, 30 December 14
Quote from: opqa on 16:33, 30 December 14
I don't know how DMA playing works on the Plus, if calculating when to skip one sample needs to be fast and you don't need a lot of accuracy I've thought a way to do it that would be really fast. I involves only one 8-bit register and constant additions to it. I could explain it if you're interested.
Definitely curious.

BTW, here's that DMA demo on YouTube

Cadjo Clan DMA Demo - YouTube (https://www.youtube.com/watch?v=eNnT2uUMVFA)
Title: Re: Sample frequency
Post by: Ast on 19:17, 30 December 14
Prodatron, how can you forget Prehistorik 2 (https://m.youtube.com/watch?v=CoWHkuI-REQ) with this fabulous Weee! Composition ?  :P
Title: Re: Sample frequency
Post by: Ast on 19:36, 30 December 14
Concerning Dma from Cpc plus, you must create an AyList which is composed of data like that :


AyList defw #0801,#0804...etc

Each AyList is finished by #4020.
Each AyList instruction is readed during the hbl !
So only one instruction per rasterline. You can
do more if you use vertical splitscreen
At the normal rate AyList is played at 15,625 kHz.
It's really good when you Know that a lot if samples on
Cpc are played in 8khz only !
Title: Re: Sample frequency
Post by: McKlain on 20:13, 30 December 14
Quote from: andycadley on 19:16, 30 December 14
Definitely curious.

BTW, here's that DMA demo on YouTube

Cadjo Clan DMA Demo - YouTube (https://www.youtube.com/watch?v=eNnT2uUMVFA)


This made me remember the Sappy demo from Semilanceata.


Amstrad 128 Plus: Sappy (Semilanceata) - VideoRip by ASiC - YouTube (https://www.youtube.com/watch?v=7GIdHz0KjV8)
Title: Re: Sample frequency
Post by: Ast on 20:21, 30 December 14
And .... Hate Beats (https://m.youtube.com/watch?v=GjJ5Q0ubn7o) from Ukonx. Power, the coder did a good job!
Title: Re: Sample frequency
Post by: opqa on 10:20, 31 December 14
Quote from: andycadley on 19:16, 30 December 14Definitely curious.BTW, here's that DMA demo on YouTubeCadjo Clan DMA Demo - YouTube (https://www.youtube.com/watch?v=eNnT2uUMVFA)

Ok then, here it goes.

Contrary to Targhan, I do like maths, so this is going to be a little bit mathemagical post. Also, all this is (more or less) untested theory and it may contain lots of errors.

Let's guess we are in the inital case Ast proposed, we want to increase pitch by a semitone, so as Prodatron pointed we need to play the sample ~1,0594631 times faster than the original. Playing it faster means we need to skip some samples from time to time but, how many? Taking the inverse of this quantity we have 1/1,0594631=0,943874. This means that we need to play about 94,4% of the samples and skip the rest. But we still don't know the "skipping interval". To calculate it we can write the above quantity like this:

0,943874 = 1 - 0,0561257 = 1 - 1 / 17,8172

The last expression can be interpreted this way, we need to shorten each sample 1/17,8172 of its original duration, as we can't do that, we can achieve the same effect just skipping one sample out of each 17,8172. Still, we can't do that, but we can round this number to its nearest integer and skip one sample out of each 18. This way we would be playing at a rate:

1 - 1 / 18 = 0,94444

Which is not bad approximation compared to its original value (0,943874). The code for doing so is somehow tricky, to skip one sample out of every group of 18 we need to count 17 and then increase the sample pointer by 1. Something like this.


; Sample skipping routine:
; INPUT
; HL - Pointer to the current sample
; B   - Partial counter, initially loaded to 17, it should be kept somewhere between calls

call play_sample
inc hl
dec b
ret nz
inc hl
ld b,17
ret

This is a quite accurate match in this particular case, but it can be improved doing a little bit more math, more on this later.
Title: Re: Sample frequency
Post by: opqa on 11:04, 31 December 14
Second part, we can improve the previous algorithm, but it will require some more maths and fine tuning by hand. Let's go back to this expression:

1 - 1 / 17,8172

Now, the trick, we are not going to round this number yet. Let's guess that, as before, we are going to count up to 16,8172 and then skip one sample. What we are going to do is to write this last number in an accurate fractional form. To do this, let's try to find a multiple of this number lower than 256 (that fits in a 8 bit register) which can be rounded to an integer more accurately. This is the hand-tuning part:

16,8172   x 1  =   16,8172
16,8172   x 2  =   33,6344
16,8172   x 3  =   50,4516
16,8172   x 4  =   67,2688
16,8172   x 5  =   84,086
16,8172   x 6  =   100,9032
16,8172   x 7  =   117,7204
16,8172   x 8  =   134,5376
16,8172   x 9  =   151,3548
16,8172   x 10 =   168,172
16,8172   x 11 =   184,9892 ~ 185
16,8172   x 12 =   201,8064
16,8172   x 13 =   218,6236
16,8172   x 14 =   235,4408
16,8172   x 15 =   252,258

The best match is highlighted, so we can write 16,8172 quite accurately as 185/11. By counting this number of samples and skipping one we would be playing at a rate:

1 - 1 / (185/11 + 1) = 0,943878

Which is almost a perfect match.

But 185/11 still isn't an integer number, so, how can we "count" up to it?. Easy, we can perform the "division" in real time using a single 8 bit register, keeping the remainder for the next division. This way, sometimes we will skip one sample out of 17 and sometimes we will skip one out of 18, but in the long term it would be exactly one skipped sample out of 17,8181...

The code for doing so would be like this.


; Sample skipping routine:
; INPUT
; HL - Pointer to the current sample
; A   - Partial counter, initially loaded to 185, it should be kept somewhere between calls

call play_sample
inc hl
sub 11
ret nc
inc hl
add 185
ret


Now, instead of decrementing the counter 1 by 1 we perform the division by subtracting 11. When the counter reaches 0 we know it's time to skip one sample. And, instead of resetting it to the same value, we just add 185 and start again, this way we are taking in account the remainder of each division for the next one.
Title: Re: Sample frequency
Post by: Ast on 17:39, 03 January 15
Just to know, what is this 'sub l1' ? :-\
Édit :
Oups Sorry after reading and reading again, i finally find 'sub 11' instead of 'sub l1'...
I think i'd need glasses  :D
Title: Re: Sample frequency
Post by: Prodatron on 19:26, 03 January 15
Btw in this way you can only generate the output for one octave.
Powered by SMFPacks Menu Editor Mod