| |
stunt Account closed
Registered: Jul 2006 Posts: 48 |
How to players and trackers usually deal with these modulation issues? --> Bit-scaling? (sid related, but not nescesarily, not a question related to the battlestar galactica music btw;-)
hi all!
I use the output of osc3(8bit) ($d41b) to modulate the pulsewidth osc1 (12bit) ($d402 & $d403), but now i still do that by just modulating OR the lobyte OR the hibyte register which gives very coarse results and also causes the modulation not to be active on the whole scale of the parameter.
I want to improve this situation so i came up with two strategies, and i'd like to hear your comments on them.
Ok. let's take a look at the situ:
The 8 lsbs reside in d402, the 4 msbs are bits 0,1,3 & 4 of $d403.
Ofcourse I want to spend as less time as possible doing the math.
Now I thought of two strategies:
Strategy 1: To modulate just the 8 most sig. bits of the 12bit word. That would mean to split the modulator byte in two and use the 4 most sig bits to modulate the 4 least sig bits of $d403, and to take the other 4 bits and use them to modulate the 4 most sig bits of $d402.
pros: prolly a time efficient solution
cons: coarse way of modulating: takes 16 steps at a time.
Strategy 2: to "bitscale" or strech up the 8bit modulator value up to a 12 bit value and modulate the 12 bits.
pros: more detailled modulation
cons: prolly lot of math and thus time consuming.
My question: what would be the most time efficient ways to implement both strategies, and which strategy would you guys advice me.
How do players and trackers usually deal with the 12bit wide pulsewidth modulation?
Ofcourse i also want to modulate the 16 bit pitch, the 11 bit filtercutoff and the 4 bit volume parameters.
so i'd like to see a solution for the stretching to all these.
so :
8 bit value modulates 4 bit value
8 bit value modulates 16 bit value
8 bit value modulates 12 bit value
8 bit value modulates 11 bit value
i can imagine dat streching up and down to 4 or 16 is less difficult and strechting up to 11 is the hardest to do. is my intuition right?
very interested to see your solutions to my problem.
And prolly my most important question:
How do players and trackers usually deal with these modulation issues?
Greetz,
Stunt
|
|
| |
Laxity
Registered: Aug 2005 Posts: 459 |
Eh...
lda pulseWidthLow
clc
adc pulseSweepLow
sta pulseWidthLow
sta $d402
lda pulseWidthHigh
adc pulseSweepHigh
sta pulseWidthHigh
sta $d403
???
That's not what you're looking for, right?.. Actually I'm not sure what exactly you want to accomplish! |
| |
cadaver
Registered: Feb 2002 Posts: 1160 |
@Laxity: maybe an official synth package should do things the modulation-way, instead of direct calculations .. but SID doesn't have a lot of modulators :)
|
| |
Laxity
Registered: Aug 2005 Posts: 459 |
Nope ;) |
| |
stunt Account closed
Registered: Jul 2006 Posts: 48 |
Quote: Eh...
lda pulseWidthLow
clc
adc pulseSweepLow
sta pulseWidthLow
sta $d402
lda pulseWidthHigh
adc pulseSweepHigh
sta pulseWidthHigh
sta $d403
???
That's not what you're looking for, right?.. Actually I'm not sure what exactly you want to accomplish!
Ok what you are suggesting is that I read from tables, and that i have precaculculated different tables for 16, 12, 11, 8 and 4 bit modulation?
Might not be a bad suggestion. Thx.
Furthermore I'll explain what i want to accomplish: I use osc3 and env3 as a modulators. So switch the sound off osc3 and just use for modulation purposes.
Why?: so i can jam live. It's for example really cool to manually (with a pot) controll the speed (pitch) of osc3 while osc3 is modulating cutoff or pitch of osc 1.
Now osc3 only provides 8bit output so in that case my intuition tells me i will have to bitschale/strech it to match 16,12,11 and 4 bit values.
My main question still stands: how do trackers/players deal with modulation? do they use tables? according to the c664 reference guide osc3 and env3 are meant for exactly the purpose that i want to use them for, so i imagine that coders faced the same problem as me.
How was this worked around in the past?
How to players/trackers deal with modulation?
Thx
ps. I didn't code (on any platform) for 15 years, and back then i was also just a beginners. Now I started refreshing my skills since a couple of weeks. So my question might be really stupid, still help would be appreciated. I'll promise to make progress really fast.
|
| |
cadaver
Registered: Feb 2002 Posts: 1160 |
What Laxity suggested is that the pulsewidth has some starting value, then a value is being manually added to it with a fixed period (like once per 50Hz frame) to create a modulation effect.
The vast majority of C64 music editors/players do exactly this, instead of "real" modulation. |
| |
Hein
Registered: Apr 2004 Posts: 954 |
With 3 voices to do music, it's a waste to use voice 3 output to modulate pw of one of the other voices. You'd loose 1 voice .
besides:
lda $d41b
and #$fe
tax
lda pwtable,x
sta $d402
lda pwtable+1,x
sta $d403
also looses a lot of detail. Then again, who notices when doing live gigs? :) |
| |
Kenho Account closed
Registered: Jan 2003 Posts: 26 |
Hi, a bit offtopic but have you tried out the Prophet64 package? here->http://www.prophet64.com/ it might be the only things you need :-)
/K |
| |
stunt Account closed
Registered: Jul 2006 Posts: 48 |
Quote: With 3 voices to do music, it's a waste to use voice 3 output to modulate pw of one of the other voices. You'd loose 1 voice .
besides:
lda $d41b
and #$fe
tax
lda pwtable,x
sta $d402
lda pwtable+1,x
sta $d403
also looses a lot of detail. Then again, who notices when doing live gigs? :)
@ Hein:
I studied your piece of code and it seems to be just what i'm looking for. Great man thx a lot! c64 coders are the best with time efficient solutions. i knew i could count on you guys.
question1: It's just the and #%11111110 that i dont understand. can you clarify? thx.
question2: why do you say that it loses a lot of detail? I dont understand. please clarify.
PS. (apart from the fact that i'm currently pimping a c64 with more sids, and apart from the fact that indeed i will create my thing for performing) --> i believe i can do great stuff with just 2 properly modulated voices. the great advantage of osc3 is that you can use it like a realtime calculated goniometric movement without wasting cpu. you can read from it as fast as from a table and still the content can easily be modified realtime. I have some great ideas i want to implement, im creating this for performing purposes, but i promise to share the code so they can also be implemented in players and demo's. i mean once i started this stuff, why not also create some cool tunesfor the demoscene:) |
| |
stunt Account closed
Registered: Jul 2006 Posts: 48 |
Quote: Hi, a bit offtopic but have you tried out the Prophet64 package? here->http://www.prophet64.com/ it might be the only things you need :-)
/K
@ offtopic:
Prophet64 is actually what comes the closest to what i'm doing. But to me it's sort of useless because it turns your c64 into a 303-like thingy.
I have very specific wishes on terms of interfacing, whereas the prophet is like any standard synth on the market: boring, heard it 10000 times before.
Besides it provides a cubase/logic like mac/pc style sequencer that runs on the c64. I will run my sequencer on pc/mac and talk to c64 with midi so i can I dedicate all available power and memory to the soundengine, and not to horny marketing interface. Besides. the greatest sin is that it uses 1531mouse for navigation. This sucks because it comsumes potx and y of sid. Potx and y are ports that you want to use for controllingpurposes (pedals, knobs, faders for realtime fiddling). So i dont know what gotten into the head of the designer, but we definately have a totally different view on how experimental and original a sid should sound. So my thing is actually an alternative for guys that really want to bleep.
Bleep on
Stunt |
| |
Hein
Registered: Apr 2004 Posts: 954 |
you dont need to and #$fe I guess. 2 tables should work out aswell, giving more detail.
ldx $d41b
lda pw_low,x
sta $d402
lda pw_hi,x
sta $d403
frankly, Im not a sidprogramming expert at all, I've been told that its better to collect all parameters, store them, and next frame write them to sid. Doing these inbetween sidwrites might make it jitter, I think.
You're bount to loose detail, because you spread your 8bits over 12bits. Maybe there's a skilled programmer who can do a routine that calculates the in between values, but with a noise waveform modulator, it might be a bit tricky to calculate the correct value. (Or just take a random one. :)
I think this $d41b thing ain't made for pw-modulation, not even filter-modulation, despite of what the manual says. The manual never said anything about open sideborders. It's better to have your own routine doing the modulation. (like Laxity and Cadaver stated) |
| |
stunt Account closed
Registered: Jul 2006 Posts: 48 |
Quote: you dont need to and #$fe I guess. 2 tables should work out aswell, giving more detail.
ldx $d41b
lda pw_low,x
sta $d402
lda pw_hi,x
sta $d403
frankly, Im not a sidprogramming expert at all, I've been told that its better to collect all parameters, store them, and next frame write them to sid. Doing these inbetween sidwrites might make it jitter, I think.
You're bount to loose detail, because you spread your 8bits over 12bits. Maybe there's a skilled programmer who can do a routine that calculates the in between values, but with a noise waveform modulator, it might be a bit tricky to calculate the correct value. (Or just take a random one. :)
I think this $d41b thing ain't made for pw-modulation, not even filter-modulation, despite of what the manual says. The manual never said anything about open sideborders. It's better to have your own routine doing the modulation. (like Laxity and Cadaver stated)
I figured that in hein's first example he had an interleaved table in mind (table .byte hi,lo,hi,lo, etc)that provided the same amount of detail as two seperatate tables for hi and lo. Is there a difference in detail between two options?
And yes, i will loose detail when i streched 8 bit to 11,12 and 16 bit, but still the modulation will have a 8bitresolution so that's pretty funky if you ask me. Interpolation will indeed provide even smoother modulation but requires realtime math and will prolly cost too much time. Even the streching without interpolation will prolly be quite cpu intensive, altough i'd love to see some expert coder comming up with some lean realtime bitscaling code! |
| |
stunt Account closed
Registered: Jul 2006 Posts: 48 |
So, did none of you coders ever adress the problem of bitscaling?
|
| |
Laxity
Registered: Aug 2005 Posts: 459 |
lda $d41b
pha
asl
asl
asl
asl
sta $d402
pla
lsr
lsr
lsr
lsr
sta $d403 |
| |
stunt Account closed
Registered: Jul 2006 Posts: 48 |
@laxity: ok. that's strategy 1. briliant. thxalot. |
| |
stunt Account closed
Registered: Jul 2006 Posts: 48 |
now for strategy 2, tables would be a solution.
so for every of the $ff steps, to enlist in table two corespondend bytes (hi and lobyte) and precalulate those values for 11,12 and 16 bit values.
But my intuition tells me there must be smarter (calculated) ways, for example to scale an 8 bit byte to a 16 bit word seems easy:
11111111 would become 11111111 11111111
00001111 would become 00000000 11111111
10101010 would become 11001100 11001100
right?
so it means taking bits 8, put it on both
bit 8 and 7 of the hibyte of the word,
take bit 7, put in on bit 6 and 5 of the word.
etc.
what would te most elegant way in asm to do that?
----
now getting from a byte to a nibble seems easy too:
create the nyble out of bits 8 6 4 and 2 of the byte.
any suggestions for how to do that in asm?
----
but getting from byte to 11 and 12 bit words seems the hardest to me...
any elegant (calculated) sollutions?
Thx.
Stunt |
| |
Laxity
Registered: Aug 2005 Posts: 459 |
I get your method, but how would you go about scaling from 8 to 12 bit in that way?.. Anyway, I think the result of the "bit streching" (and loss of resolution) will be A LOT more audiable than disregarding the 4 least significant bits of the pulse width as they are indeed the least significant bits ;). |
| |
stunt Account closed
Registered: Jul 2006 Posts: 48 |
Quote: I get your method, but how would you go about scaling from 8 to 12 bit in that way?.. Anyway, I think the result of the "bit streching" (and loss of resolution) will be A LOT more audiable than disregarding the 4 least significant bits of the pulse width as they are indeed the least significant bits ;).
scaling from 8 to 11 or 12 bits,
that was exactly my question :-)
hoped some genius would come up with a solution for that:-)
and about the resoltion : is that so are you rigth about that?
hmm... |
| |
tlr
Registered: Sep 2003 Posts: 1790 |
Quote: scaling from 8 to 11 or 12 bits,
that was exactly my question :-)
hoped some genius would come up with a solution for that:-)
and about the resoltion : is that so are you rigth about that?
hmm...
Laxity is correct.
Shifting (=multiplying) is the way to convert an 8-bit number to a different number of bits.
Your way is might make sense for something visual, but for mathematics, it's just strange. :) |
| |
stunt Account closed
Registered: Jul 2006 Posts: 48 |
Ok thx. u guys are right. Hein and laxity thx for the code.
Now the next challenge. Take the example of vibrato (but i'd like to come with similar appraoches for modulation of all paramters like cutoff pulsewith, volume etc):
Ofcourse there has to be a centre value to which vibrato has to be apllied. That means the modulationvalue has to be inverterd and subtracted to the played pitch value when it is 127 or lower, or subtracted by 127 and added to the played pitch value if it's 128 and higher, right? (because 127/128 is like the zero of the goniometric modulation figure, and values of 127 represent negative modulation, and 128 and above represents positive modulation).
On top of that, ofcourse there has to be something like 'vibrato dept'. (in the world of 'normal' synthesis) this comes down to mupliplying the modulationvalue with the dept-value. So when dept is 0, the modulation will be 0, and when dept is max, the modluation will have a radius of +/-128.
This last thing i figured could easily be done by having a 3bit modulationdept that makes the modulationvalue be devided by 2 ("ror a"-ed) 1 to 8 times depending on the value of the modulation dept. This is already working but i was wondering wether you guys had a better solution that has nmore then 8 steps and that is linear instead of exponential.
For the first thing i really don't know how to do this so i hope you guys can help me (i'm still not good at math in asm). Ok here's my plan, hope you can help me implement it/transfer it to code:
1. Read the modulationvalue (can be osc3,env3 or value from a osc- or env-table)
2. If value is 127 or lower, then:
-Invert it (so 127 becomes 1, 126 becomes 2 , ... , 1 becomes 127, 0 becomes 128)
-Create an adress and use one bit as an add/subtract flag, and set it to 'subtract'.
3. If value is 128 or higher, then:
-Subtract the value by 127
-Create an adress and use one bit as an add/subtract flag, and set it to 'add'.
4. Multiply the 'absolute' modulation with the intensity value.
5. add or subtract (depending on what the flag says) the value with the pitch value.
Ok. esp how to create this "absolute" modulation value i don't know. So plz come with suggestions. Or if this whole thing can be simplified or done more efficient --> REally interested in your sollutions. Thx.
Stunt
|
| |
Jetboy
Registered: Jul 2006 Posts: 337 |
Sorry but there is beter approach:
When you use bit 7 as a sign you understand values of 0-127 as 0-127, and values of 128-255 as -128 to -1. So 255 is -1, 254 is -2 and so on.
You just do your math as usual (if its one byte long).
There are instructions that support that build into 6502.
There is N flag, standing for negative in status register.
So if bit 7 in acumulator is set the flag is set acordingly.
and there is BMI - Branch if MInus, and BPL - Branch if PLus conditional jumps to support that.
That way steps 2-3 becomes obsolete, and in step 5 you only need just add.
Sorry but i'm totaly green on sound programming so i dont understand fully those modulations and stuff. I dont really know if they are 8 or 16 bit, hence i wont be able to help much more. But if they are 8 bit it should be fairly easy. |
| |
stunt Account closed
Registered: Jul 2006 Posts: 48 |
Quote: Sorry but there is beter approach:
When you use bit 7 as a sign you understand values of 0-127 as 0-127, and values of 128-255 as -128 to -1. So 255 is -1, 254 is -2 and so on.
You just do your math as usual (if its one byte long).
There are instructions that support that build into 6502.
There is N flag, standing for negative in status register.
So if bit 7 in acumulator is set the flag is set acordingly.
and there is BMI - Branch if MInus, and BPL - Branch if PLus conditional jumps to support that.
That way steps 2-3 becomes obsolete, and in step 5 you only need just add.
Sorry but i'm totaly green on sound programming so i dont understand fully those modulations and stuff. I dont really know if they are 8 or 16 bit, hence i wont be able to help much more. But if they are 8 bit it should be fairly easy.
Jetboy, there's never reason to say 'sorry' when you provide a better way to fix things. B/c i can only be happy with that. This kind of feedback is exactly what i'm looking for.
Can you give an example as to how i implement it?
(I never worked with n-flag before, just carry)
By the way, what i would like to have is, that 0-127 become -128 to -1, and 128-255 become 0-127, so that is slightly different than in your example.
As for the math, after this 'absolution' is done the value still needs to be divided/multiplied by the modulation-intensity value before it can be added subtracted to the pitch value.
And yes, apart from 8bit, the value needs to be added/subtracted to 16,12,11 and 4 bit values also.
Now the bitshifting-thing seems both a good solution for both easily applying the intensity as well as a solution for multiple 8bit+ modulation.
I wonder wether i can still use Laxity's code (see above in this thread) to do it.
I dont see how to do stuff but i will draw it, maybe that will make cloud go a away:
ok so let's take example of the pitch. It has two bytes:
7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0
and then there is the modulation byte
7 6 5 4 3 2 1 0.
So bit 7 of the modulation-byte determines negative or positie, and bit 6-0 determine modulation 128 values. So the the number that is added/subtracted to the pitch is 7 bit long.
Now how i see it in my head, there's an intensity-value that determines the 'dept' of modulation.
How i see it the modulation will look like this:
mod.dept:16 (=max.modulation)
7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0
^ ^ ^ ^ ^ ^ ^
6 5 4 3 2 1 0
mod.dept:15
7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0
^ ^ ^ ^ ^ ^ ^
6 5 4 3 2 1 0
mod.dept:14
7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0
^ ^ ^ ^ ^ ^ ^
6 5 4 3 2 1 0
[....]
mod.dept: 7
7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0
^ ^ ^ ^ ^ ^ ^
6 5 4 3 2 1 0
[... ]
mod.dept: 1
7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0
^
6
mod.dept:0 (=modulation off)
7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0
----------
So let's take for example mod.dept 14 and see what will have to happen, to make things clear:
As you can see in my drawn example, the 7bit mod.value is splitted in two:
a 6 bitpart that modulates (add/subtr) the 6 lsbs of the pitch-hibyte, and a 1 bit part that modulates just the msb of the pitch-lobyte.
So laxity's approach is useful: just take two instances of the mod.value, and sfift one two bits left and add/subtract it with hibyte. Then take the other instance and shift it 7 times right, and add/subtract that with the lobyte.
And ofcourse, if lobyte exceeds $ff bit 1 of the hybite has to be set.
and if hybite passes zero then ofcourse bit 7 of lobyte has to ... ehm.. wel the adding/subtracting just have to make sense basically and hi and lobyte have to act as one big 16bit byte :D
How would i implement something like this?
I'm sure this kind of math has been needed lots and lots of times before.
Stunt |
| |
stunt Account closed
Registered: Jul 2006 Posts: 48 |
i suddenly came up with a better idea maybe:
why do all the stuff with the n-flag and signing?
why not subtract 128 of the pitchvalue first and then add the unchanged modulation value?
Stunt
|
| |
tlr
Registered: Sep 2003 Posts: 1790 |
Quote: i suddenly came up with a better idea maybe:
why do all the stuff with the n-flag and signing?
why not subtract 128 of the pitchvalue first and then add the unchanged modulation value?
Stunt
The you'd get $80 as the centervalue, but everyone would expect it to be a 2-complement signed value. (-128 to -1 is $80-$ff, 0 to 127 is $00-$7f)
2-complement is pretty much standard nowadays because it is what most CPU's use internally, and it is what is used in C/C++ and many other languages...
|
| |
stunt Account closed
Registered: Jul 2006 Posts: 48 |
ok. i see. that's why it's useful for me to learn and understand 2-complement way.
But from an optimiser point-of-view,my way might save time and provide the same result?
Stunt |
| |
tlr
Registered: Sep 2003 Posts: 1790 |
It is not necessary to make the editor display the same representation that is used in the actual player data.
If it saves time in the player, go for it, but make the editor present it as a 2-complement value if possible.
|
| |
stunt Account closed
Registered: Jul 2006 Posts: 48 |
well the interface is very hardcore and now just shows 8 bits of osc3 flippin in binary and just aside that the value osc3 is modulating, and beside that the mod.dept (intensity). And you can see to which waveform osc3 is set. So that's as far as the visual interface goes. I'd rather spend my time on math then on visuals here :P
Anyhow, altough all you guys' insights were helpful, this pig ain't fully washed yet (is that a proper expression in english?)
Can you guys see why the last strategy (the 16bit solution that i presented visually) isn't correct?
I'm still thinkin gof a solution, will keep you guys updated.
|