Skip to content

1.0.5

Latest
Compare
Choose a tag to compare
@smoge smoge released this 18 Mar 13:48
· 11 commits to master since this release

I'd like to announce that I've made some performance optimizations and updates to the Rational Quark.
I found it fitting to revisit and adapt a classic example by JMC to showcase the Quark.

Before you dive into the example, please ensure you've updated your Quark to the latest version. This is important because I've introduced a new method in the example code below.

The code is robust and regularly tested. I'd love to hear your thoughts and feedback.

A quick note on the purpose of it: Why a Rational type in a programming language?

  1. Unlike floating-point representations, which can introduce rounding errors due to their binary nature, rational numbers maintain precision. This exact representation is crucial in fields like music, which works with metric rhythms and tunning systems.

  2. Operations on rational numbers (addition, subtraction, multiplication, division) can be done without loss of precision. This is especially important in algebraic computations where accuracy cannot be compromised.

  3. Floating-point arithmetic can lead to subtle bugs and inaccuracy and the infamous problem of not being able to precisely represent certain decimal fractions.

  4. Rational types can interact with other numeric types, the class is well-integrated with the standard library. They can be converted when necessary (e.g., sending a frequency number to the server).

https://github.com/smoge/Rational

// Quarks.install("https://github.com/smoge/Rational")
// Quarks.update("https://github.com/smoge/Rational")

s.boot;

(
var w, buttons;
var series, series2;

SynthDef("tone", { arg freq = 440, amp=0.1, gate =1;
	var tone, env;
	env = Linen.kr(gate, 0.01, amp, 0.2, 2);
	tone = OnePole.ar(Saw.ar(freq + {Rand(-0.05,0.05)}.dup, env), 0.95);
	Out.ar(0, tone);
}).add;

series = (8..15);
series.remove(13);

series2 = series ++ (2 * series) ++ (4 * (series ++ 16));
series = 4 * (series ++ 16);

w = Window("diamond", Rect(200,200,460,560));
w.view.decorator = FlowLayout(w.view.bounds);

series2.reverse.do { |denom|
	series.do { |numer|
		var b, label, ratio, id, freq;
		var color, rational;

        rational = numer %/ denom;
        
        rational.postln;
		
        freq = 50.midicps * rational;     

        label = rational.asString;
        
        b = Button(w, 50 @ 20);
   
		color = if (rational.numeratorIsPowerOfTwo && rational.denominatorIsPowerOfTwo) { Color.red(1, 0.4) } {
			if (numer.isPowerOfTwo || denom.isPowerOfTwo) { Color.yellow(1, 0.4) } { Color.clear }
		};
		b.states = [[label, Color.black, color], [label, Color.white, Color.black]];
		b.action = {
			if (b.value == 1) {
				s.sendMsg(\s_new, \tone, id = s.nextNodeID, 0, 1, \freq, freq.asFloat);
                [\on, rational].postln;
			}  {
				s.sendMsg(\n_set, id, \gate, 0);
				[\off, rational].postln;
			};
		};
	};
	w.view.decorator.nextLine;
};
w.front;

)

Full Changelog: v1.0.4...1.0.5