Hi list,
I'm trying to simulate how adc conversion works using chuck. However,
I'm not succeeding as I'm getting too many artifacts in the output
sound. Don't know whether i'm getting this wrong from a conceptual
point of view or I'm using/setting chuck's UGens wrongly. The patch I
use is:
<<<"usage:", "sample_and_hold.ck:output_gain:sr" >>>;
adc => OnePole lpf => blackhole;
Impulse pulse => lpf => Gain g => dac;
.8 => g.gain;
if( me.args() ) Std.atof( me.arg(0) ) => g.gain;
1::second/1::samp => float chuck_sr => float new_sr;
if( me.args() > 1 ) Std.atof( me.arg(1) ) => new_sr;
chuck_sr/new_sr => float next_samp;
1. - new_sr/chuck_sr => lpf.pole;
<<
eduard; a Onepole filter will not
suffice to get rid off all frequencies above the cutoff. Is there a way of having a kind of brickwall filter in chuck?
Oh. dear. I fear we are on the edge of a situation where some massive LiSa abuse to use her as a FIR filter would become almost sensible (loop at -sample rate- over a set of LiSa voices that all hold your impulse responce, writing my_signal.last() to their gain, then starting the sample in non-looped mode. You need at least as many voices as there are samples in your impulse-response. For a high cutoff (and thus short IR) that might actually even work). Fortunately for LiSa there is very little use, IMHO, in emulating high-quality DAC's as those sound like a straight (if filtered) signal by definition. The digital good-stuff (Akai s-612, Roland s-550, Amiga 500, etc) on the other hand sounds like it does due to a rather non-perfect implementation which I suspect involves a plain analogue filter with a huge ripple (which adds character, in retrospect and at second hand prices in a market hardly anyone cares for....) in order to get a steeper roll off that's placed as high (in Hz) as they dared to go, trading fidelity for brightness. I didn't analyse the cerquit but I think it's a good guess that for the S-612 Akai simply bolted a envelope to the same filter and presented that as the modulated filter. So; I'd say add rounding to 8 or 12 bits, try to make the AD and DA stages slightly non-linear in ways that don't perfectly match and tune the filters by ear.... But then again, you may have a very different opinion on what the digital "Good stuff" is, I like the S-612 :¬) Oh, and for bonus trickery; the S-550 has a digital filter that's not quite stable at high cutoffs with modulation and particularly a high Q. I suspect part of the blame lies in it being a 12 bit system and I suspect rounding errors in filter coefficients act up there. This can be charming, at times. Perhaps some of our real filter experts will be able to comment on how likely my theory is, I know it goes semi chaotic in that range, the rounding is my own theory. I believe rounding everything to the sample frequency won't improve matters at such bit-rates either, and I always take it down to 15KHz sampling frequency..... Not sure if that might help or just make it all harder, I'm a bit of a enthusiast for low-fidelity yet nice sounding stuff. Yours, Kas.
Sorry... I think I get were the problem is. I am using the same lpf before and after conversion. Using a separate lpf gives better results. One of the problems is that I was passing lpf.last to pulse.next, but pulse is also connected to lpf in the patch. On Oct 12, 2007, at 6:41 PM, eduard wrote:
Hi list,
I'm trying to simulate how adc conversion works using chuck. However, I'm not succeeding as I'm getting too many artifacts in the output sound. Don't know whether i'm getting this wrong from a conceptual point of view or I'm using/setting chuck's UGens wrongly. The patch I use is:
<<<"usage:", "sample_and_hold.ck:output_gain:sr" >>>; adc => OnePole lpf => blackhole; Impulse pulse => lpf => Gain g => dac; .8 => g.gain; if( me.args() ) Std.atof( me.arg(0) ) => g.gain; 1::second/1::samp => float chuck_sr => float new_sr; if( me.args() > 1 ) Std.atof( me.arg(1) ) => new_sr; chuck_sr/new_sr => float next_samp; 1. - new_sr/chuck_sr => lpf.pole; <<
>>; <<< next_samp>>>; while(true) { now => time T; next_samp::samp +=> T; lpf.last() => pulse.next; while( now < T ) { 1::samp => now; } } Then the user should be able to give a certain SR and experience how the input sound would sound when sampled at SR. I'd like to be able to set lpf cutoff frequency at SR/2 and what I thougt of is something like:
1. - new_sr/chuck_sr => lpf.pole;
thus, if user_sr= 44100, then pole=0 and cutoff freq=chuck_sr/2 (should be 22050 if running at 44.1). if user_sr=22050, then pole=0.5 and cutoff freq=chuck_sr/4 (should be 11025 if running at 44.1) etc...
Am I doing this right? On the other hand, a Onepole filter will not suffice to get rid off all frequencies above the cutoff. Is there a way of having a kind of brickwall filter in chuck?
Thanks,
eduard _______________________________________________ chuck-users mailing list chuck-users@lists.cs.princeton.edu https://lists.cs.princeton.edu/mailman/listinfo/chuck-users
On 10/12/07, eduard aylon
Also, to be accurate, should be using a Step instead of an Impulse, right? However, this results in lesser quality sounds...
Yes. asuming your emulated bit-rate is lower then your actual rate (if not I'm out of my league....) you should use Step instead of Impulse for the DAC because one emulated cycle will cover sever "real" ones and the value shouldn't change in between (either that or the CPU will get more work then it needs to have). Hope that helps, Kas.
Hi, got something more usable, but still get some sort of grainy sound. I am using a spectral filter in order to obtain a steeper filter and guess the grainy sound comes from there. If someone could comment on this, I'd be very thankful. Files attached below. thanks, eduard
On 10/13/07, eduard aylon
Hi,
got something more usable, but still get some sort of grainy sound. I am using a spectral filter in order to obtain a steeper filter and guess the grainy sound comes from there. If someone could comment on this, I'd be very thankful. Files attached below.
Comments? Well I think it's very clever. I also think it's quite normal that this will sound somewhat grainy because you are in fact using a grain-like technique.... And I think it's entirely normal that it turns out to be hard to make a artefact-free brick-wall filter (see articles on how various DAW's handle re-sampling *cough*). THE way to handle re-sampling filtering should be a sinx/x function ( http://en.wikipedia.org/wiki/Sinc_function ), modern hardware converters (which I gather you are after) often use a FIR filter, I think, and as I wrote in my previous note about this you could make one of those using LiSa. In fact once the update Dan just announced arrives I think you could basically feed this; http://en.wikipedia.org/wiki/Sinc_filter straight to LiSa's buffer. Hope that's of some help. Yours, Kas.
Hi kassen, Thanks for the link. The sync filter is exactly what I am doing. I am applying a rectangular window in the frequency domain (so all bins=0 above the specified freq), which in fact translates into a sync function in the time domain. This way is more efficient than convolving in the time domain with the sync function. I'll have a look at your previous post, with more detail.
And I think it's entirely normal that it turns out to be hard to make a artefact-free brick-wall filter
Yes, I also think so. I am hoping some experienced dsp guru in the list may have some tips. thanks again, eduard
by the way, supplying the resolution bits doesn't work unless you change the following line in adc-to-dac2.ck: if( me.args() > 2 ) Std.atoi( me.arg(2) ) => nbits; to if( me.args() > 1 ) Std.atoi( me.arg(1) ) => nbits; eduard
participants (3)
-
eduard
-
eduard aylon
-
Kassen