Hello list, I am trying to build a granular patch with lisa, but for some reason I am getting clicks every time lisa repeats the buffer. Maybe it has to do with lisa's duration? Hope someone can explain me what I am doing wrong. Following I attach two examples one uses lisa the other uses an array. The one that runs with lisa has clicks, the other sounds pristine, why? (even if rampup and rampdown were set for lisa). The strange thing is that if recorded to file and checked with an audio editor I can't see any strange artifacts in the waveform. thanks for any help, eduard // the patch that uses lisa: LiSa lisa => dac; 1024 => int size; size::samp => lisa.duration; for (int i; i < size; i++) { lisa.valueAt(Math.sin(2.0*pi*60*i/size), i::samp); } 1 => lisa.play; while(true) { lisa.rampUp(10::samp); lisa.duration() - 20::samp => now; lisa.rampDown(10::samp); } // the other patch with a simple buffer: Impulse imp => dac; 1024 => int size; float buffer[size]; size - 1 => int bitmask; for (int i; i < size; i++) { Math.sin(2.0*pi*60*i/size) => buffer[i]; } 0 => int pos; while(true) { buffer[pos&bitmask] => imp.next; pos++; 1::samp => now; }
Ok, got the answer: lisa.valueAt(Math.sin(2.0*pi*60*i/(size-1)), i::samp); should be put into lisa and not lisa.valueAt(Math.sin(2.0*pi*60*i/size), i::samp); the difference is in using size or size-1. This seems not right though... eduard Begin forwarded message:
From: eduard aylon
Date: November 6, 2008 1:20:56 AM GMT+01:00 To: ChucK Users Mailing List Subject: help understanding lisa Hello list,
I am trying to build a granular patch with lisa, but for some reason I am getting clicks every time lisa repeats the buffer. Maybe it has to do with lisa's duration? Hope someone can explain me what I am doing wrong. Following I attach two examples one uses lisa the other uses an array. The one that runs with lisa has clicks, the other sounds pristine, why? (even if rampup and rampdown were set for lisa). The strange thing is that if recorded to file and checked with an audio editor I can't see any strange artifacts in the waveform.
thanks for any help,
eduard
// the patch that uses lisa:
LiSa lisa => dac; 1024 => int size; size::samp => lisa.duration;
for (int i; i < size; i++) { lisa.valueAt(Math.sin(2.0*pi*60*i/size), i::samp); }
1 => lisa.play; while(true) { lisa.rampUp(10::samp); lisa.duration() - 20::samp => now; lisa.rampDown(10::samp); }
// the other patch with a simple buffer:
Impulse imp => dac; 1024 => int size; float buffer[size]; size - 1 => int bitmask;
for (int i; i < size; i++) { Math.sin(2.0*pi*60*i/size) => buffer[i]; }
0 => int pos;
while(true) { buffer[pos&bitmask] => imp.next; pos++; 1::samp => now; }
yeah, i think i found and fixed this bug a while ago also, but again i don't think it got checked in.... apologies! dt On Nov 5, 2008, at 7:33 PM, eduard wrote:
Ok, got the answer:
lisa.valueAt(Math.sin(2.0*pi*60*i/(size-1)), i::samp);
should be put into lisa and not
lisa.valueAt(Math.sin(2.0*pi*60*i/size), i::samp);
the difference is in using size or size-1. This seems not right though...
eduard
Begin forwarded message:
From: eduard aylon
Date: November 6, 2008 1:20:56 AM GMT+01:00 To: ChucK Users Mailing List Subject: help understanding lisa Hello list,
I am trying to build a granular patch with lisa, but for some reason I am getting clicks every time lisa repeats the buffer. Maybe it has to do with lisa's duration? Hope someone can explain me what I am doing wrong. Following I attach two examples one uses lisa the other uses an array. The one that runs with lisa has clicks, the other sounds pristine, why? (even if rampup and rampdown were set for lisa). The strange thing is that if recorded to file and checked with an audio editor I can't see any strange artifacts in the waveform.
thanks for any help,
eduard
// the patch that uses lisa:
LiSa lisa => dac; 1024 => int size; size::samp => lisa.duration;
for (int i; i < size; i++) { lisa.valueAt(Math.sin(2.0*pi*60*i/size), i::samp); }
1 => lisa.play; while(true) { lisa.rampUp(10::samp); lisa.duration() - 20::samp => now; lisa.rampDown(10::samp); }
// the other patch with a simple buffer:
Impulse imp => dac; 1024 => int size; float buffer[size]; size - 1 => int bitmask;
for (int i; i < size; i++) { Math.sin(2.0*pi*60*i/size) => buffer[i]; }
0 => int pos;
while(true) { buffer[pos&bitmask] => imp.next; pos++; 1::samp => now; }
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
Hi Dan, do you mean It didn't get committed or that it just wasn't included in the release. If the latter, then I'll check out the cvs. eduard On Nov 6, 2008, at 1:40 AM, dan trueman wrote:
yeah, i think i found and fixed this bug a while ago also, but again i don't think it got checked in.... apologies!
dt
On Nov 5, 2008, at 7:33 PM, eduard wrote:
Ok, got the answer:
lisa.valueAt(Math.sin(2.0*pi*60*i/(size-1)), i::samp);
should be put into lisa and not
lisa.valueAt(Math.sin(2.0*pi*60*i/size), i::samp);
the difference is in using size or size-1. This seems not right though...
eduard
Begin forwarded message:
From: eduard aylon
Date: November 6, 2008 1:20:56 AM GMT+01:00 To: ChucK Users Mailing List Subject: help understanding lisa Hello list,
I am trying to build a granular patch with lisa, but for some reason I am getting clicks every time lisa repeats the buffer. Maybe it has to do with lisa's duration? Hope someone can explain me what I am doing wrong. Following I attach two examples one uses lisa the other uses an array. The one that runs with lisa has clicks, the other sounds pristine, why? (even if rampup and rampdown were set for lisa). The strange thing is that if recorded to file and checked with an audio editor I can't see any strange artifacts in the waveform.
thanks for any help,
eduard
// the patch that uses lisa:
LiSa lisa => dac; 1024 => int size; size::samp => lisa.duration;
for (int i; i < size; i++) { lisa.valueAt(Math.sin(2.0*pi*60*i/size), i::samp); }
1 => lisa.play; while(true) { lisa.rampUp(10::samp); lisa.duration() - 20::samp => now; lisa.rampDown(10::samp); }
// the other patch with a simple buffer:
Impulse imp => dac; 1024 => int size; float buffer[size]; size - 1 => int bitmask;
for (int i; i < size; i++) { Math.sin(2.0*pi*60*i/size) => buffer[i]; }
0 => int pos;
while(true) { buffer[pos&bitmask] => imp.next; pos++; 1::samp => now; }
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
i don't think i got it committed... dan On Nov 5, 2008, at 7:51 PM, eduard aylon wrote:
Hi Dan, do you mean It didn't get committed or that it just wasn't included in the release. If the latter, then I'll check out the cvs.
eduard
On Nov 6, 2008, at 1:40 AM, dan trueman wrote:
yeah, i think i found and fixed this bug a while ago also, but again i don't think it got checked in.... apologies!
dt
On Nov 5, 2008, at 7:33 PM, eduard wrote:
Ok, got the answer:
lisa.valueAt(Math.sin(2.0*pi*60*i/(size-1)), i::samp);
should be put into lisa and not
lisa.valueAt(Math.sin(2.0*pi*60*i/size), i::samp);
the difference is in using size or size-1. This seems not right though...
eduard
Begin forwarded message:
From: eduard aylon
Date: November 6, 2008 1:20:56 AM GMT+01:00 To: ChucK Users Mailing List Subject: help understanding lisa Hello list,
I am trying to build a granular patch with lisa, but for some reason I am getting clicks every time lisa repeats the buffer. Maybe it has to do with lisa's duration? Hope someone can explain me what I am doing wrong. Following I attach two examples one uses lisa the other uses an array. The one that runs with lisa has clicks, the other sounds pristine, why? (even if rampup and rampdown were set for lisa). The strange thing is that if recorded to file and checked with an audio editor I can't see any strange artifacts in the waveform.
thanks for any help,
eduard
// the patch that uses lisa:
LiSa lisa => dac; 1024 => int size; size::samp => lisa.duration;
for (int i; i < size; i++) { lisa.valueAt(Math.sin(2.0*pi*60*i/size), i::samp); }
1 => lisa.play; while(true) { lisa.rampUp(10::samp); lisa.duration() - 20::samp => now; lisa.rampDown(10::samp); }
// the other patch with a simple buffer:
Impulse imp => dac; 1024 => int size; float buffer[size]; size - 1 => int bitmask;
for (int i; i < size; i++) { Math.sin(2.0*pi*60*i/size) => buffer[i]; }
0 => int pos;
while(true) { buffer[pos&bitmask] => imp.next; pos++; 1::samp => now; }
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
2008/11/6 eduard aylon
Hello list,
Hey, Eduard! lisa.valueAt(Math.sin(2.0*pi*60*i/size), i::samp);
A bit (ok, a lot) off topic, but how long has valueAt() been there? I know Dan announced he wanted to do that and I'm really happy it's here because this will shave a lot of time off the "boot time" of my sequencer, but I can't remember seeing this anounced. I don't seem to be able to find it in the "VERSIONS" file either. You get points and Dan gets points but either my memory or the docs will have to lose points. Ah, just saw you got the answer to your question. I feel less guilty about interupting now. Yours, Kas.
er, i coded valueAt() quite some time ago and have been using it for a while, but i confess i'm not sure it made it into the last release (my fault!). i can't check it into cvs at the moment because i have a mess of other stuff in LiSa (multichannel LiSa) that doesn't work properly yet, but if i can't get that cleaned up soon, i'll revert and get valueAt checked in. sorry about this! dan On Nov 5, 2008, at 7:35 PM, Kassen wrote:
2008/11/6 eduard aylon
Hello list, Hey, Eduard!
lisa.valueAt(Math.sin(2.0*pi*60*i/size), i::samp);
A bit (ok, a lot) off topic, but how long has valueAt() been there? I know Dan announced he wanted to do that and I'm really happy it's here because this will shave a lot of time off the "boot time" of my sequencer, but I can't remember seeing this anounced. I don't seem to be able to find it in the "VERSIONS" file either.
You get points and Dan gets points but either my memory or the docs will have to lose points.
Ah, just saw you got the answer to your question. I feel less guilty about interupting now.
Yours, Kas. _______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
dan trueman; er, i coded valueAt() quite some time ago and have been using it for a
while, but i confess i'm not sure it made it into the last release (my fault!).
Well, if Eduard is using it that would mean it would be in there, right? Maybe that's naive reasoning again :¬). Anyway, I don't think there is any reason to apologise for adding features.
i can't check it into cvs at the moment because i have a mess of other stuff in LiSa (multichannel LiSa) that doesn't work properly yet, but if i can't get that cleaned up soon, i'll revert and get valueAt checked in. sorry about this!
That sounds good! I was also talking with Mike about LiSa for granular usage. I think the linear ramps that we have now are good for avoiding clicks in loops but they do tend to place a spectral footprint on shorter, denser grains. I wonder if there would be some way to have more advanced per-voice windowing/enveloping without the syntactic or CPU overhead getting too bad? Might be a thought for a future update? Yours, Kas.
yep, would be great. definitely on the to-do list. dan On Nov 6, 2008, at 5:00 AM, Kassen wrote:
I was also talking with Mike about LiSa for granular usage. I think the linear ramps that we have now are good for avoiding clicks in loops but they do tend to place a spectral footprint on shorter, denser grains. I wonder if there would be some way to have more advanced per-voice windowing/enveloping without the syntactic or CPU overhead getting too bad?
Kassen
"I think the linear ramps that we have now are good for avoiding
clicks in loops but they do tend to place a spectral footprint on
shorter, denser grains. I wonder if there would be some way to have
more advanced per-voice windowing/enveloping without the syntactic or
CPU overhead getting too bad?"
This is interesting. I have some code that does pretty cool graining
/ glitching on samples (that I have yet to post on the forum) that I'm
currently using linear ramps for. What would be the optimal shape for
the grain? Sine wave attack (sqare-root)? And what are the effects
on the spectrum?
Rogan
On Thu, Nov 6, 2008 at 7:28 AM, dan trueman
yep, would be great. definitely on the to-do list. dan
On Nov 6, 2008, at 5:00 AM, Kassen wrote:
I was also talking with Mike about LiSa for granular usage. I think the linear ramps that we have now are good for avoiding clicks in loops but they do tend to place a spectral footprint on shorter, denser grains. I wonder if there would be some way to have more advanced per-voice windowing/enveloping without the syntactic or CPU overhead getting too bad?
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
Hi Folks,
What would be the optimal shape for the grain?
I have been thinking about this for some time. I think that, for
certain purposes (wavelet resynthesis, certain forms of pure-sine
granular synthesis), it's helpful to be able to have some kinds of
"canned" envelope functions available as well as being able to
arbitrarily define your own envelopes. This applies to more than just
the LiSa object, of course, although at the moment LiSa is the best
thing we have in ChucK for doing granular stuff. For instance, I have
a granular patch I'm using right now which began its life using a
buffer containing one second of a 1hz tone. I could set this to loop
and the rate would become my frequency, in effect. While I could ramp
this up and down, my "best" envelope is trapezoidal and subject to the
kinds of spectral artifacts that Kassen has mentioned. Arbitrary
envelope shapes aside, it seems rather strange to me why I cannot
specify that my envelope shape should be "hanning" or "hamming" or
"gaussian" or whatever we might find useful for certain specific
tasks. These kinds of things must come up all the time for users of
ChucK as they do for users of other similar platforms. Something like
this:
LiSa sampler;
1::second => sampler.duration;
// set envelope type (canned scenario)
"hanning" => sampler.envelopeType;
sampler.rampUp();
0.5::second => now;
sampler.rampDown();
0.5::second => now;
Certainly, a custom envelope is another story, however, I think that
this could work the same way within LiSa as it might in an expanded
version of the Envelope UGen, or some special subclass thereof. I
also imagine that certain functions might have parameters that need to
be set up before use. I think that these could be set in a similar
manner to the syntax above.
The biggest thing that I regret is that my C++ skills are just not
up-to-snuff for tackling this task myself. I'm hoping that Steve's
faust2ck converter will provide some more mileage for UGen
development.
With regard to the creation of custom envelope types, I'm kind of at a
loss. I personally do not like the kinds of functions that have been
traditionally provided for this purpose (I'm thinking about CSound and
Cmix here type makegen() functions), but can't really think of a
particularly ChucKian way of doing this off the top of my head.
</ramble>
-Mike
On Thu, Nov 6, 2008 at 10:11 AM, Rogan Carr
Kassen
"I think the linear ramps that we have now are good for avoiding clicks in loops but they do tend to place a spectral footprint on shorter, denser grains. I wonder if there would be some way to have more advanced per-voice windowing/enveloping without the syntactic or CPU overhead getting too bad?"
This is interesting. I have some code that does pretty cool graining / glitching on samples (that I have yet to post on the forum) that I'm currently using linear ramps for. What would be the optimal shape for the grain? Sine wave attack (sqare-root)? And what are the effects on the spectrum?
Rogan
On Thu, Nov 6, 2008 at 7:28 AM, dan trueman
wrote: yep, would be great. definitely on the to-do list. dan
On Nov 6, 2008, at 5:00 AM, Kassen wrote:
I was also talking with Mike about LiSa for granular usage. I think the linear ramps that we have now are good for avoiding clicks in loops but they do tend to place a spectral footprint on shorter, denser grains. I wonder if there would be some way to have more advanced per-voice windowing/enveloping without the syntactic or CPU overhead getting too bad?
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
Rogan; This is interesting. I have some code that does pretty cool graining
/ glitching on samples (that I have yet to post on the forum) that I'm currently using linear ramps for.
Cool!
What would be the optimal shape for the grain?
Well, that's a good question... it's a question like what is the best instrument or the most beautiful animal. In other words; it depends on taste and application. A envelope shape (or grain "window" if you like) that's perfect for me may be completely unsuitable for you. I do think that if we only have one the simplicity of the linear ramp is nice but more can be said on the topic.
Sine wave attack (sqare-root)?
That would be a nice one, yes. Nothing could be "the best" but something like that would be a decent bet as a starting point, I think.
And what are the effects on the spectrum?
Well, what we have is a wave-form (the section of the buffer being played back) and a envelope over it which is actually another wave-form that gets multiplied with the first. For longer grains (or loops or recordings) this is no huge issue but as grains become shorter the envelope may approach a rate where it's wave-form comes close to the audible range in frequency. If we then consider that a multiplication of two wave-forms really comes down to a ring modulator we'll see that the spectral content of the envelope will start generating side-bands for the audio. This is not a bug, in fact it's a feature of granular (or pulselet, or....) synthesis and it gives us interesting options in sound-design. However, to make the most of those options we need to be able to talk about the curve of the ramps as the curve of the ramps will translate to harmonics of the "envelope wave-form" which will in turn end up in the sound. Hope fully we'll be able to find a way to talk about this to LiSa that doesn't make LiSa any more complicated then she needs to be; simple tools are nice. I hope that served as a introduction. If you'd like to know a lot more about this topic I think the best thing to do is to considder getting the book "Microsound" by Roads. That book goes into considerable depth in the various properties of granular systems, how they interact and how they influence the final result. Yours, Kas.
Listees,
This is just for fun, but it's totally relevant. This is currently
the state of DIY Hann (for example) envelopes for granular synthesis.
You get a couple more of these trainlets running, and you'll kill the
VM. I absolutely love ChucK's concurrency model, but it can't handle
too much of this kind of thing. The sample-level intervention is also
painful.
Also, you all might check my notably horrid math...
-----
1024 => int N; // length of grain in samples
fun float hann( int n ) {
return 0.5 * (1. - Math.cos( (2*pi*n)/(N-1) )); // thank you,
Wikipedia.org ;-)
}
fun void hannGrain( float f ) {
SinOsc s => dac;
f => s.freq;
0 => int n;
0. => float h;
while( n < N-1 ) {
hann( n ) => h => s.gain;
n++;
1::samp => now;
}
}
while( true ) {
spork ~ hannGrain(Math.rand2f(250.,500.));
me.yield();
1024::samp/2 => now; // 50% grain overlap
}
------
If you make the random frequency a constant, it will sound like a
SinOsc. This is mostly because of the nice envelope...
Enjoy,
Mike
On Thu, Nov 6, 2008 at 4:35 PM, Kassen
Rogan;
This is interesting. I have some code that does pretty cool graining / glitching on samples (that I have yet to post on the forum) that I'm currently using linear ramps for.
Cool!
What would be the optimal shape for the grain?
Well, that's a good question... it's a question like what is the best instrument or the most beautiful animal. In other words; it depends on taste and application. A envelope shape (or grain "window" if you like) that's perfect for me may be completely unsuitable for you. I do think that if we only have one the simplicity of the linear ramp is nice but more can be said on the topic.
Sine wave attack (sqare-root)?
That would be a nice one, yes. Nothing could be "the best" but something like that would be a decent bet as a starting point, I think.
And what are the effects on the spectrum?
Well, what we have is a wave-form (the section of the buffer being played back) and a envelope over it which is actually another wave-form that gets multiplied with the first. For longer grains (or loops or recordings) this is no huge issue but as grains become shorter the envelope may approach a rate where it's wave-form comes close to the audible range in frequency. If we then consider that a multiplication of two wave-forms really comes down to a ring modulator we'll see that the spectral content of the envelope will start generating side-bands for the audio.
This is not a bug, in fact it's a feature of granular (or pulselet, or....) synthesis and it gives us interesting options in sound-design. However, to make the most of those options we need to be able to talk about the curve of the ramps as the curve of the ramps will translate to harmonics of the "envelope wave-form" which will in turn end up in the sound. Hope fully we'll be able to find a way to talk about this to LiSa that doesn't make LiSa any more complicated then she needs to be; simple tools are nice.
I hope that served as a introduction. If you'd like to know a lot more about this topic I think the best thing to do is to considder getting the book "Microsound" by Roads. That book goes into considerable depth in the various properties of granular systems, how they interact and how they influence the final result.
Yours, Kas.
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
Mike;
You get a couple more of these trainlets running, and you'll kill the VM. I absolutely love ChucK's concurrency model, but it can't handle too much of this kind of thing. The sample-level intervention is also painful.
True. Here's a small mod. the trick is that it only updates the osc's gain
at zerocrossings, making it relatively glitch-free. The price is that CPU cost will now depend on the frequency used. =========================== fun void hannGrain( float f ) { SinOsc s => dac; f => s.freq; 0 => int n; 0. => float h; now => time start; now + N::samp => time later; while( now < later ) { hann( ((now-start)/ samp) $ int ) => h => s.gain; n++; .5::s.period() => now; } } ================================= This strategy is not at all perfect but I feel this gives a decent trade between CPU efficiently and sound quality. We can trade those using ChucK's timing but with clever trading we can get a better deal. Note this only works because we know the phase of the oscilator and we know the rate won't change. If you need changing frequencies this will have to be extended. I'd also think about sporking a static number of shreds and re-using those with signalled events as your current strategy is probably generating a lot of garbage. Hope that helps. Cool sound! Kas.
What?! That's sweet! What other methods are there in there undocumented? ;-)
-MIke
On Thu, Nov 6, 2008 at 6:23 PM, Kassen
Mike;
You get a couple more of these trainlets running, and you'll kill the VM. I absolutely love ChucK's concurrency model, but it can't handle too much of this kind of thing. The sample-level intervention is also painful.
True. Here's a small mod. the trick is that it only updates the osc's gain at zerocrossings, making it relatively glitch-free. The price is that CPU cost will now depend on the frequency used.
=========================== fun void hannGrain( float f ) { SinOsc s => dac; f => s.freq; 0 => int n; 0. => float h;
now => time start; now + N::samp => time later; while( now < later ) { hann( ((now-start)/ samp) $ int ) => h => s.gain; n++; .5::s.period() => now; }
} =================================
This strategy is not at all perfect but I feel this gives a decent trade between CPU efficiently and sound quality. We can trade those using ChucK's timing but with clever trading we can get a better deal. Note this only works because we know the phase of the oscilator and we know the rate won't change. If you need changing frequencies this will have to be extended.
I'd also think about sporking a static number of shreds and re-using those with signalled events as your current strategy is probably generating a lot of garbage.
Hope that helps. Cool sound!
Kas.
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
Kassen,
Here's an interesting by-product of your implementation: the effective
control rate of the enveloping is dependent on frequency. If you add
the ability to specify the number of cycles per grain, you get nasty
artifacts on low-cycle grains.
fun void hannGrain_cycles( float f, int cycles ) {
SinOsc s => dac;
f => s.freq;
0 => int n;
0. => float h;
cycles * (s.period()/samp) $ int => int N;
0 => s.gain;
Math.rand2f(0,4000)::samp => now;
0.2 => s.gain;
now => time start;
now + N::samp => time later;
while( now < later ) {
hann( ((now-start)/ samp) $ int, N ) => h => s.gain;
//<<< h >>>;
n++;
.5::s.period() => now;
}
}
Here, you'd have to pick something closer to the sample rate for gain-changes.
Cheers,
-Mike
On Thu, Nov 6, 2008 at 6:53 PM, mike clemow
What?! That's sweet! What other methods are there in there undocumented? ;-)
-MIke
On Thu, Nov 6, 2008 at 6:23 PM, Kassen
wrote: Mike;
You get a couple more of these trainlets running, and you'll kill the VM. I absolutely love ChucK's concurrency model, but it can't handle too much of this kind of thing. The sample-level intervention is also painful.
True. Here's a small mod. the trick is that it only updates the osc's gain at zerocrossings, making it relatively glitch-free. The price is that CPU cost will now depend on the frequency used.
=========================== fun void hannGrain( float f ) { SinOsc s => dac; f => s.freq; 0 => int n; 0. => float h;
now => time start; now + N::samp => time later; while( now < later ) { hann( ((now-start)/ samp) $ int ) => h => s.gain; n++; .5::s.period() => now; }
} =================================
This strategy is not at all perfect but I feel this gives a decent trade between CPU efficiently and sound quality. We can trade those using ChucK's timing but with clever trading we can get a better deal. Note this only works because we know the phase of the oscilator and we know the rate won't change. If you need changing frequencies this will have to be extended.
I'd also think about sporking a static number of shreds and re-using those with signalled events as your current strategy is probably generating a lot of garbage.
Hope that helps. Cool sound!
Kas.
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
mike; What?! That's sweet! The .period( ) one? Yeah I like that one and I should as I wishlisted it it :¬). It's good for optimising stuff like this and for setting LFO speeds to match BPM and so on.
What other methods are there in there undocumented? ;-)
Hmmm, is that undocumented? I think it was at least in the VERSIONS file, I think it is in other places too and I used it on the list before as well. As for other undocumented features; there is a complete list of all undocumented features, libraries and UGens on the WiKi but I lost the URL when my bookmarks got lost in a HD format. ;¬) Anyway, making the time-advancing of a controler loop a harmonic (or sub-harmonic) of the pitch is a great trick for good trades in CPU vs fidelity. As a extra bonus the artefacts of such operations should be hamonics as well so less objectionable then the less related artefacts caused by more or less random periods like 10::ms. This is of course without taking the quantizing effects of the sample-rate into account, at least rounding errors shouldn't carry like they will in some other systems where the control rate will be quantised as well and not just it's effects.
From your other post;
Here, you'd have to pick something closer to the sample rate for gain-changes.
Yes, I think so. Of course we need to take the context into account when trying to optimise like this. Personally I'd look into using one of the Gen UGens or some similar method to generate a envelope. You could also use a SndBuf to store a wave-table and use that as a arbitarily shaped envelope with a Gain used as a VCA. In that case, because of the memory usage of the buffers I'd definitely re-cycle shreds using Events and signalling. All of these have advantages and disadvantages; we *always* have to trade, I fear, but there are definitely interesting options open to you. Yours, Kas.
Hello Mike, storing hann in an array or a window class will also help to lower the cost of computing it at a sample level. Unless you change the size at each sample... eduard On Nov 6, 2008, at 11:55 PM, mike clemow wrote:
Listees,
This is just for fun, but it's totally relevant. This is currently the state of DIY Hann (for example) envelopes for granular synthesis. You get a couple more of these trainlets running, and you'll kill the VM. I absolutely love ChucK's concurrency model, but it can't handle too much of this kind of thing. The sample-level intervention is also painful.
Also, you all might check my notably horrid math...
-----
1024 => int N; // length of grain in samples
fun float hann( int n ) { return 0.5 * (1. - Math.cos( (2*pi*n)/(N-1) )); // thank you, Wikipedia.org ;-) }
fun void hannGrain( float f ) { SinOsc s => dac; f => s.freq; 0 => int n; 0. => float h;
while( n < N-1 ) { hann( n ) => h => s.gain; n++; 1::samp => now; } }
while( true ) { spork ~ hannGrain(Math.rand2f(250.,500.)); me.yield(); 1024::samp/2 => now; // 50% grain overlap }
------
If you make the random frequency a constant, it will sound like a SinOsc. This is mostly because of the nice envelope...
Enjoy, Mike
On Thu, Nov 6, 2008 at 4:35 PM, Kassen
wrote: Rogan;
This is interesting. I have some code that does pretty cool graining / glitching on samples (that I have yet to post on the forum) that I'm currently using linear ramps for.
Cool!
What would be the optimal shape for the grain?
Well, that's a good question... it's a question like what is the best instrument or the most beautiful animal. In other words; it depends on taste and application. A envelope shape (or grain "window" if you like) that's perfect for me may be completely unsuitable for you. I do think that if we only have one the simplicity of the linear ramp is nice but more can be said on the topic.
Sine wave attack (sqare-root)?
That would be a nice one, yes. Nothing could be "the best" but something like that would be a decent bet as a starting point, I think.
And what are the effects on the spectrum?
Well, what we have is a wave-form (the section of the buffer being played back) and a envelope over it which is actually another wave-form that gets multiplied with the first. For longer grains (or loops or recordings) this is no huge issue but as grains become shorter the envelope may approach a rate where it's wave-form comes close to the audible range in frequency. If we then consider that a multiplication of two wave-forms really comes down to a ring modulator we'll see that the spectral content of the envelope will start generating side-bands for the audio.
This is not a bug, in fact it's a feature of granular (or pulselet, or....) synthesis and it gives us interesting options in sound-design. However, to make the most of those options we need to be able to talk about the curve of the ramps as the curve of the ramps will translate to harmonics of the "envelope wave-form" which will in turn end up in the sound. Hope fully we'll be able to find a way to talk about this to LiSa that doesn't make LiSa any more complicated then she needs to be; simple tools are nice.
I hope that served as a introduction. If you'd like to know a lot more about this topic I think the best thing to do is to considder getting the book "Microsound" by Roads. That book goes into considerable depth in the various properties of granular systems, how they interact and how they influence the final result.
Yours, Kas.
_______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
-- http://michaelclemow.com http://semiotech.org _______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
Kassen;
If we then consider that a multiplication of two wave-forms really comes down to a ring modulator we'll see that the spectral content of the envelope will start generating side-bands for the audio.
Ah, right. It's all coming back to me know. Thanks for the great answer. This thread has made me excited to go work on my graining / glitching code. I'll see if I can't get it presentable, then I'll post it up on the forum. Rogan
participants (6)
-
dan trueman
-
eduard
-
eduard aylon
-
Kassen
-
mike clemow
-
Rogan Carr