14 September 2013, 19:18 | #21 | |
Registered User
Join Date: Sep 2009
Location: Norway
Posts: 1,710
|
Quote:
|
|
14 September 2013, 23:59 | #22 |
Moderator
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,602
|
Oh. Well, you just multiply 54229 by 61858 / 65536 n times and halve the result o times, where n is the note 0-11 (0 is C, 1 is C#, etc) and o is the octave 0-5.
Code:
uint get1Note(n,o) { uint x=54229; for (int i=0;i<(n-1);i++) { x=(x*61858) >> 16 } x=x >> (o+4); //shift to a range of usable octaves return x; } uint D1=get1Note(2,1); //D-note in 2nd octave Last edited by Photon; 15 September 2013 at 12:10. |
15 September 2013, 00:17 | #23 |
Registered User
Join Date: Sep 2009
Location: Norway
Posts: 1,710
|
I made a little snippet out of your example:
Code:
#include <stdio.h> #include <stdlib.h> /* note = 0..35 (C-0 .. B-2) */ unsigned short noteToPeriod(char note) { char i; char octave; unsigned int x; octave = note / 12; note %= 12; x = 54299; for (i = 0; i < note; ++i) x = (x * 61858) >> 16; x = (x + 4) >> octave; return x; } int main(int argc, char* argv[]) { char i; for (i = 0; i < 35; ++i) printf("%d\n", noteToPeriod(i)); system("pause"); return 0; } 54303 51255 48378 45663 43100 40681 38398 36243 34209 32289 30477 28766 27151 25627 24189 22831 21550 20340 19199 18121 17104 16144 15238 14383 13575 12813 12094 11415 10775 10170 9599 9060 8552 8072 7619 It should output something spanning from 856 to 113.... |
15 September 2013, 01:28 | #24 |
Moderator
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,602
|
Yes, add 4 to oct (shift value) not to x
This still puts you 2 octs below the octave you need. 848 is correct, 856 is incorrect Just put 856<<6 as start x for PT table / Sleepy Photon using mobile g'night Last edited by Photon; 15 September 2013 at 01:34. |
15 September 2013, 02:29 | #25 |
Registered User
Join Date: Sep 2009
Location: Norway
Posts: 1,710
|
|
15 September 2013, 12:54 | #26 |
Moderator
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,602
|
Not if the # DMA cycles is 3546895 and the standard A is 440 Hz.
You can calculate it on your calculator: (the "8" is the number of samples in your waveform.) notestep = 2^(1/12)=1.0594630943592952645618252949463 prdA = 3546895/440/8 prdA# = prdA/notestep prdB = prdA#/notestep prdC = prdB/notestep = 847.32138942651245571147266932506 baseC = prdC*64 = 54228.568923296797165534250836804 ~= 54229. (Sorry for saying 848 is correct, I had gone to bed so I just halved one of the integers from your ouput there a couple of times I think. ) Last edited by Photon; 15 September 2013 at 13:04. |
15 September 2013, 19:14 | #27 |
Registered User
Join Date: Sep 2009
Location: Norway
Posts: 1,710
|
That's not what I mean. This is not the same values as in the PT period table. I want an accurate PT table output. :P
|
15 September 2013, 20:31 | #28 |
Moderator
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,602
|
But the values were written by hand, not generated.
You've already spotted the manual errors they made (as, I think, has many a coder who wondered why the base note differed from the one in HRM, not that HRM is perfect either). Unless the errors are consistent between octaves (higher octave values are all half of the lower), it'll be hard to "save some table words". If you want compatibility, keep the original table with the errors (I did that in P6108). If you want to be correct, you have my generator (from 1Klång). The "corrected wrong-base table" seems terrible to me, unless you can point out which of the values in the whole table is the correct one. You picked 856 and corrected the others, but this is arbitrary. What is to say 856 wasn't wrong and C# or A is the correct period to modify the others from? So anyway, good luck and if I sound like I "come on strong" it's because I do care about some pet subjects on Amiga, music is one of them |
15 September 2013, 21:43 | #29 |
Registered User
Join Date: Sep 2009
Location: Norway
Posts: 1,710
|
Again, I strive for Amiga output accuracy, not note frequency accuracy. By errors, I mean values that mismatched those of the original bad PT table used in the original replayers.
I just wanted the smallest possible way to generate this bad table, that's it. I'm not saying that its values are correct, they are definitely wrong at some points. |
16 September 2013, 10:56 | #30 |
Moderator
Join Date: Nov 2004
Location: Eksjö / Sweden
Posts: 5,602
|
Well, as I said, check if all matches in the higher octaves match if you shift down (halve) the lower ones.
Else you're out of luck. You could do the above and perhaps it matches 95% of the values, and you could fix up the ones that don't match exactly by storing the "diff". I don't see how the diffs could be stored in less space, though. |
29 September 2017, 12:16 | #31 | |
Registered User
Join Date: Sep 2017
Location: Czech Republic
Posts: 20
|
Quote:
With permission, this extended table will be written on the Czech forum too |
|
11 June 2020, 18:13 | #32 |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,468
|
I came across this thread looking for a solution for generating a table of periods (protracker compatible) and in fact I did not find anything valid available.
The table needs 3*12*16 word values (3 octaves, 12-tone equal temperament scale plus fine-tune from -8 to +7) = 1152 bytes (in fact with the separator it is 1184, but since my player does not use it, I generate only the raw values). Anyway if your module player require the $0 separator, adding it is straightforward. Of course a table of 1152 bytes may seem little, but in a small intro every byte counts and since the values are somehow related (even if in fact I've not found a general formula.. because some values are wrong) I thought of creating my own generator. The end result is very good: the code (/ data) is only 190 bytes. Code:
pt_period_generator lea bit+$4a(pc),a1 moveq #$128/8-1,d2 .p0 moveq #8-1,d3 move.w -(a1),d0 .p1 moveq #3,d1 and.w d0,d1 move.w d1,-(sp) lsr.w #2,d0 dbf d3,.p1 dbf d2,.p0 lea (sp),a1 moveq #4,d1 .a0 moveq #$28-1,d0 .a1 add.w d1,(a1)+ dbf d0,.a1 subq.w #1,d1 bne.b .a0 moveq #36-1,d0 move.w #907,d1 .c0 moveq #8-1,d2 addq.w #1,d3 .c1 move.w d1,(a0) tst.w d3 beq.b .c2 move.w d1,-36*8*2-2(a0) .c2 sub.w (sp)+,d1 lea 36*2(a0),a0 dbf d2,.c1 lea -36*8*2+2(a0),a0 dbf d0,.c0 lea -36*8*2-2(a0),a0 moveq #-1,d3 not.l d0 bne.b .c0 moveq #9-1,d1 .u move.b fix-1(pc,d1.l),d0 addq.b #1,589(a0) adda.l d0,a0 dbf d1,.u rts fix dc.b $6a,$c6,$30,$74,$44,$02,$04,$22 bit dc.b $EE,$BA,$AA,$AA,$A6,$9A,$59,$65,$65,$56,$5A,$9B,$56,$67,$19,$5A dc.b $15,$56,$05,$52,$5A,$66,$59,$96,$55,$95,$55,$55,$55,$15,$6A,$66 dc.b $99,$9A,$59,$66,$55,$96,$55,$56,$6A,$AB,$6A,$AA,$6A,$9A,$9A,$6A dc.b $66,$66,$99,$99,$96,$66,$56,$59,$65,$65,$65,$59,$55,$59,$55,$55 dc.b $55,$55,$55,$55,$52,$15,$51,$55,$15,$44 Code:
period_table ds.w 36*16 Code:
lea period_table+36*8*2,a0 bsr pt_period_generator |
11 June 2020, 18:47 | #33 |
move.l #$c0ff33,throat
Join Date: Dec 2005
Location: Berlin/Joymoney
Posts: 6,863
|
I coded a period table generator for one of my 4k intros about 15 years ago. There is no fine tuning or any other "fancy" stuff supported.
Code:
; calc period table ; not 100% correct, e-3,g-3,g#3 too low (-1) .TAB lea mt4k_periodtab(pc),a0 lea mt4k_adds(pc),a1 moveq #12-1,d7 move.w #856,d0 ; start value (C-1) .loop2 move.w d0,(a0)+ move.w d0,d1 lsr.w #1,d1 ; octave 2 move.w d1,12*2-2(a0) lsr.w #1,d1 ; octave 3 move.w d1,12*2*2-2(a0) move.b (a1)+,d1 sub.w d1,d0 dbf d7,.loop2 rts mt4k_adds dc.b 48,46,42,42,38,36,34,32,30,28,27,0 |
11 June 2020, 19:03 | #34 |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,468
|
|
24 June 2020, 23:03 | #35 |
Registered User
Join Date: Sep 2009
Location: Norway
Posts: 1,710
|
Adding finetune for periods is easy and doesn't require a full finetuned period table. Just calculate 16 exponential 16-bit mul values and put them in a LUT, then look-up using finetune as index. Then you multiply period by that value and swap the register to get the finetuned period. Though if I remember correctly, the finetuned sections of the ProTracker period table also has mystical off-by-one values. If you want max accuracy, you need to go down another rabbit hole.
Something like this. Not tested, and maybe it compiles into too many bytes for it to be smaller than a full table generator. Code:
; d0.w = period, d1.w = finetune (0..15) getPeriod lea ftuneTab(pc),a0 add.b d1,d1 mulu.w (a0,d1.w),d0 ; expects upper byte of d1.w to be zero swap d0 rts ; for (i = 0; i < 16; i++) ; x=round(65536.0 / exp2(((i^8)-8) / (12.0 * 8.0))); ftuneTab dc.w 65536,65065,64596,64132,63670,63212,62757,62306 dc.w 69433,68933,68438,67945,67456,66971,66489,66011 Last edited by 8bitbubsy; 24 June 2020 at 23:36. |
24 June 2020, 23:35 | #36 |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,468
|
It is the way I tried initially.
Unfortunately, even if in theory it is correct, it produces rounding error or results too far from what they are (full of mistakes..) in the table used by protracker. So I changed my approach and studied a custom encoder built on how existing data is. But if you can generate a 'perfect' period+finetute table with code+data <190 then I use it instead of mine |
27 June 2020, 09:56 | #37 |
Registered User
Join Date: Nov 2019
Location: Groningen / the Netherlands
Posts: 16
|
This is the routine I wrote to precalculate the original Protracker mt_PeriodTable.
The size is 127 bytes of code ( Windows x86 MASM assembly ) and the result is 100% exact as the original mt_PeriodTable. Fully commented, so you could convert it to Amiga assembly. All rounding errors are restored and put back into the table. Code:
mov edi,offset PeriodTable+576 ; Start at the second half of the Period Table memory buffer movss xmm1,BasePeriod_907 ; 906.9023 -> ( 3546895 / 3911 ) mov ebx,093E07E8h ; Magic repair number for 14 "Tuning -8" mismatches mov dl,2 ; Split the Period Table in 2 halves Split_LP2: mov dh,8 ; 8 fine tune stages per half Period Table Next_finetune_step2: mov cl,36 ; 3 octaves ( 3 * 12 notes ) movss xmm0,xmm1 ; Set BasePeriod to next "Tuning" stage Octaves_LP2: cvtss2si eax,xmm0 ; Convert float to 32 bit integer cmp dh,8 ; Are we in "Tuning 0" or "Tuning -8" ? jne finetune_checked test bl,1 ; Yes, check if we need to repair a period jz repair_checked dec eax ; Yes, subtract 1 of the period value repair_checked: shr ebx,1 ; Shift through the Magic repair numbers finetune_checked: mov [edi],ax ; Save period value as 16 bit integer mulss xmm0,twelfth_root_of_2_rec ; Calculate next semitone value in the present octave -> 1/(2^(1/12)) = 0.943874 add edi,2 ; Next period position in the Period Table memory buffer dec cl ; Loop 36 times to create 3 octaves per "Tuning" stage jnz Octaves_LP2 mulss xmm1,fine_tune_step_rec ; Calculate next fine tune step -> 1/(2^(1/12/8)) = 0.992806 dec dh ; Loop 8 times to create 8 "Tuning" stages jnz Next_finetune_step2 mov ebx,049F03F4h ; Magic repair number for 14 "Tuning 0" mismatches mov edi,offset PeriodTable ; Start at the first half of the Period Table memory buffer dec dl ; Goto Pass 2 ( split buffer! ) jnz Split_LP2 ; Code size = 89 bytes and 9 scattered period mismatches left mov ecx,0ff040105h ; 2 loop and sign pairs mov ebx,0F6744604h ; Magic repair offset bytes for 5 scattered -1 period value mismatches dec byte ptr[edi+80] ; Repair 1 ( out of byte range ) +1 period value mismatch Scattered_LP: add byte ptr[edi+116],ch ; Repair the -1 and +1 period value mismatches Sign_switch: movzx eax,bl ; Get next byte offset add edi,eax ; Calculate the next offset in the Period Table memory buffer shr ebx,8 ; Shift through the offset bytes dec cl ; Loop 5 times for +1 repairs and 3 times for -1 repairs ( plus 1 offset bytes restore loop ) jnz Scattered_LP mov ebx,000E8286Ch ; Magic repair offset bytes for 3 scattered +1 period value mismatches shr ecx,16 ; Shift to last loop and sign pair, if zero we are done jnz Sign_switch ; Total code size = 127 bytes ( -> 100% correct match with original Protracker mt_PeriodTable. ) |
27 June 2020, 11:47 | #38 | |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,468
|
Quote:
The challenge here is that the routine need to be for a bare 68k (16x16 mul, 32/16 div) and no FP and SIMD units. Probably your code require a Pentium III processor, a bit too much for us geezer |
|
27 June 2020, 12:31 | #39 |
Registered User
Join Date: Nov 2019
Location: Groningen / the Netherlands
Posts: 16
|
Maybe you can calculate with 10:22 bit fixed-point instead of floating-point numbers.
And use my algorithm to reduce the code size. ( it only uses multiplications ) The gain is in the algorithm. |
27 June 2020, 13:08 | #40 | |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,468
|
Quote:
But failed because of the fixed-point math Maybe on a 020+ or 030+/FPU could succeed, I've not tried. When I have some time I will do more tests. |
|
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Looking for the most accurate Paula audio emulation | craig64 | support.Other | 69 | 23 July 2023 19:36 |
What is the most accurate speed test for WinUAE? | Steve | support.OtherUAE | 5 | 04 December 2012 18:04 |
Calculating percentages in assembly aka bpm and period | h0ffman | Coders. Asm / Hardware | 8 | 16 September 2012 18:49 |
Software for generating screenshots and videos | Edi (FZ2D) | Retrogaming General Discussion | 5 | 08 April 2010 23:34 |
How accurate is the emulation? | manicx | support.WinUAE | 26 | 07 July 2003 08:35 |
|
|