{
   "name" : "fraction2basimal",
   "author" : "eli.rosenkim",
   "description" : "function that extracts repeating digits in \"basimal\" representations of ratios",
   "ancestor_list" : [],
   "labels" : [
      "formant",
      "just intonation",
      "hordijk",
      "basimal",
      "decimal",
      "partch",
      "integers"
   ],
   "id" : "1-5fR",
   "is_private" : null,
   "code" : "//I wanted some interesting periodic sets of integers for just intonation music.\r\n//Rational fractions often yield periodic decimals in base 10 if they can't be formed using multiples of 2s and 5s. Prime base number systems have even greater potential for these periodic sequences. Choosing the base also acts to constrain the maximum magnitude of the numbers, useful to stay roughly within a certain \"limit\" in the Partch sense.\r\n\r\n//Conversion of decimal fraction to basimal algorithim from https://mnmathleague.org/wp-content/uploads/2013/06/Basimal-Fractions-Part-A-only.pdf\r\n\r\n\r\n//it doesn't work perfectly due to floating point errors, I can't find an arbitrary precision float for SC\r\n~fraction2basimal.(1/3, 10); //without rounding in the equals comparision, this returns a bunch of threes (should only return two) and then after a few digits turns to rando errors\r\n~fraction2basimal.(pi, 10); //pi and phi are both \"terminating\" after less than 50 digits with or without rounding in the equals comparison\r\n\r\n//function\r\n(\r\n~fraction2basimal = {\r\n\targ x, base;\r\n\tvar message = \"max iterations computed\", messageList = List.newClear(size: 0), a = 0, d=x, c, maxIterations=15, i=0, cList = List.newClear(size: 0), dList = List.newClear(size: 0);\r\n\td = d - d.floor.asInteger; //removes integer component to avoid double digit numbers in the array when there shouldn't be\r\n\twhile(\r\n\t\t////conditions for stopping section////\r\n\t\t{i < maxIterations} //limit on maximum numbers of iterations for safety\r\n\t\t&& {d != 0}//if d=0 the basimal repetition is done and non-repeating\r\n\t\t&&{//if d at i is equal to any previous d, then the basimal repetition is the previous digits repeating\r\n\t\t\tvar result = true;\r\n\t\t\tdList.do{\r\n\t\t\t\targ item, i;\r\n\t\t\t\t//dList.postln; d.postln; //for testing //*************\r\n\t\t\t\tif(\r\n\t\t\t\t\t({i > 0}.value;) && //if i = 0 then i-1.max(0) is 0, and d will be compared with itself!\r\n\t\t\t\t\t({dList[(i-1).max(0)].equalWithPrecision(d, 0.0000001)}.value;), //equalWithPrecision nessescarry to avoid floating point errors, I wish it wasn't! Comment out to test //*************\r\n\t\t\t\t\t//({dList[(i-1).max(0)] == d}.value;), //broken version without rounding to showcase issue, comment in for testing //*************\r\n\t\t\t\t\t{message = \"repeating\"; result = false;},\r\n\t\t\t);\r\n\t\t\t\tif(result == false, {messageList.add(cList[i])});\r\n\t\t\t};\r\n\t\t\tresult;\r\n\t\t\t}\r\n\t\t,\r\n\t\t////body of the algo section////\r\n\t\t{\r\n\t\t\ti = i+1;\r\n\t\t\ta = d*base;\r\n\t\t\tc = a.floor.asInteger; //the integer part of a\r\n\t\t\td = a - c; //the fractional part of a\r\n\t\t\tcList.add(c);\r\n\t\t\tdList.add(d);\r\n\t\t}\r\n\t);\r\n\t//post and return section\r\n\tif(d == 0, {message = \"terminating\"});\r\n\tif((message == \"repeating\"), {postf(\"%\",messageList.asArray);(\" repeating\").postln;}, {message.postln;});\r\n\tcList.asArray;\r\n\t};\r\n)\r\n\r\n//examples\r\n~fraction2basimal.(1/3, 10);\r\n~fraction2basimal.(4/5, 7);\r\n~fraction2basimal.(6/7, 7);\r\n//results from the paper\r\n~fraction2basimal.(3/8, 4);\r\n~fraction2basimal.(3/8, 3);\r\n//supports bases over 10. Note that all digits in the output are represented in base 10 even if the computation is in a different base.\r\n~fraction2basimal.(6/7, 3);\r\n//decimals to basimals also works\r\n~fraction2basimal.((1+(5.sqrt))/2, 10);//golden ratio and other irrationals will yield infinite series that should always hit the max iterations. A precision error might at some point cause it to mistakenly terminate if you set the max iterations high enough though.\r\n~fraction2basimal.(pi, 10);//floating point poops out at about 47 iterations\r\n~fraction2basimal.(pi, 6);\r\n//note that one should always imagine a decimal before the first place, the function discards everything to the left of the decimal\r\n~fraction2basimal.(1/3, 10);\r\n~fraction2basimal.(4/3, 10); //same thing\r\n\r\n\r\n\r\n\r\n\r\n//fun formant sound, disperser taken from https://scsynth.org/t/phase-rotation-fos/5575\r\n(\r\nSynthDef(\\Harrison3, {\r\n\targ root = 100, oTone = 1, uTone = 1, fb1 = 0, formant = 1760, tube = 0, amp = 1, pan = 0, gate = 0.5, ratio = 1, k= 0.5;\r\n\tvar finalFreq, sig1, sig, sigL, sigR, sigM, sigS, hornbostelwertheimerkonstante = 0.00063;\r\n\tfinalFreq = (oTone/uTone) * root;\r\n\tsig1 = (0.2*Formant.ar(finalFreq, formfreq: formant)) + //osc1\r\n\t(0.2*SinOscFB.ar(finalFreq, feedback: fb1)); //osc2\r\n\tsig = sig1;\r\n\tsig = Limiter.ar(LeakDC.ar(NTube.ar(sig,`[0.97,1.0,1.0,1.0,0.97],`[0.5, tube.range(-1, 1),0.2],`([0.01,0.02,0.01,0.005]*0.01)))*3);//vocal tract filter\r\n\tsig = 0.1  * sig;\r\n\tsigL = DelayL.ar(sig, 1, LFNoise1.ar(1, finalFreq * hornbostelwertheimerkonstante * 0.1));\r\n\tsigR = DelayL.ar(sig, 1, LFNoise1.ar(1.3, finalFreq * hornbostelwertheimerkonstante * 0.1));\r\n\tsigM = sigL + sigR;\r\n\tsigS = sigL - sigR;\r\n\t100.do {sigS = FOS.ar(sigS, k.neg, 1, k);}; //allpass disperser\r\n\tsigL = (sigM + sigS);\r\n\tsigR =  (sigM - sigS);\r\n\tsig = [sigL, sigR];\r\n\tsig = Pan2.ar(Limiter.ar(sig), pan, amp);\r\n\tsig = DFM1.ar(sig, 22000 - (500 * ((finalFreq/20 + 1).log2)), 0.3, 2, 0, 0);//filter\r\n\tsig = sig*EnvGen.kr(Env.adsr(0.04, 0.2, 0.6, 0.1), gate, doneAction: Done.freeSelf);//env\r\n\tsig = Limiter.ar(sig);\r\n\t//sig = Friction.ar(sig, friction: MouseX.kr(0.00001, 0.03, 1), spring: MouseY.kr(0.01, 0.1, 1), beltmass: MouseY.kr(2, 0.01, 1));\r\n\tOffsetOut.ar(0, sig);\r\n}).add;\r\n)\r\n\r\n\r\n\r\n//patern using 8/9 in base 11 for musical purposes\r\n(\r\n~long.stop;\r\n~short1.stop;\r\n~short2.stop;\r\n~basimal = ~fraction2basimal.(8/9, 11); // 8/9 in base 11 is .986124 repeating\r\n~basimal.pop; //this results in ~basimal = [9,8,6,1,2,4]\r\n//~basimal = ~basimal.rotate(0);\r\n~antiTempo = 6/16;\r\n~long = PmonoArtic(\r\n\t\\Harrison2,\r\n\t\\formant, Pseq(~basimal++~basimal, inf),\r\n\t\\fb1, Pseq(~basimal++~basimal++[3], inf)*1/4,\r\n\t\\tube, Pseq([0, 0, 0, 1/2, -1/2, 1/2], inf);,\r\n\t\\root, 144* Pstep([9/10, 1, 1], ~antiTempo*4/5, inf),\r\n\t\\uTone, Pstep(~basimal.rotate(-1), ~antiTempo*8/9, inf),\r\n\t\\oTone, Pstep(~basimal, ~antiTempo, inf),\r\n\t\\dur, Pseq(~basimal, inf)*(~antiTempo/10),\r\n\t\\legato, Pseq(~basimal.mirror2, inf)*2/19\r\n).play;\r\n\r\n~short = PmonoArtic(\r\n\t\\Harrison2,\r\n\t\\formant, Pseq(~basimal, inf),\r\n\t\\fb1, Pseq([10, 1, 1], inf)*1/4,\r\n\t\\tube, Pseq([-0.9, -0.8, 1, 1/2, -1/2, -0.9], inf),\r\n\t\\root, 288* Pstep([9/10, 1, 1], ~antiTempo*3/5, inf),\r\n\t\\uTone, Pstep(~basimal.rotate(1), ~antiTempo*8/9, inf),\r\n\t\\oTone, Pstep(~basimal, ~antiTempo, inf),\r\n\t\\dur, Pseq(~basimal, inf)*(~antiTempo/10),\r\n\t\\legato, Pseq(~basimal, inf)*1/20\r\n).play;\r\n)\r\n\r\n\r\n\r\n\r\n\r\n//another pattern\r\n(\r\n~long.stop;\r\n~short.stop;\r\n~short1.stop;\r\n~short2.stop;\r\n~basimal = ~fraction2basimal.(4/5, 13);\r\n~basimal.pop;\r\n~basimal = ~basimal.rotate(5);\r\n~antiTempo = 6/32;\r\n~root = 288;\r\n//~ratiolong = 25/24;\r\n~ratiolong = 1;\r\n~long = PmonoArtic(\r\n\t\\Harrison2,\r\n\t\\formant, Pseq(~basimal, inf),\r\n\t\\fb1, Pseq(~basimal, inf)*0.1,\r\n\t\\tube, Pseq([0, 0, 0, 1/2, -1/2, 1/2], inf);,\r\n\t\\root, ~root *(~ratiolong)* Pstep([3/4, 1, 1], ~antiTempo*5/4, inf),\r\n\t\\uTone, Pstep(~basimal, ~antiTempo*4/5, inf),\r\n\t\\oTone, Pstep(~basimal, ~antiTempo, inf),\r\n\t\\dur, Pseq(~basimal, inf)*(~antiTempo/10),\r\n\t\\legato, Pseq(~basimal.mirror2, inf)*3/19\r\n).play;\r\n\r\n\r\n\r\n~short1 = PmonoArtic(\r\n\t\\Harrison2,\r\n\t\\formant, Pseq(~basimal, inf),\r\n\t\\fb1, Pseq([10, 1, 1], inf)*1/4,\r\n\t\\tube, Pseq([-0.9, -0.8, 1, 1/2, -1/2, -0.9], inf),\r\n\t\\root, ~root* Pstep([9/10, 1, 1], ~antiTempo*3/5, inf),\r\n\t\\uTone, Pstep(~basimal.rotate(1), ~antiTempo*4/5, inf),\r\n\t\\oTone, Pstep(~basimal, ~antiTempo, inf),\r\n\t\\dur, Pseq(~basimal, inf)*(~antiTempo/10),\r\n\t\\legato, Pseq(~basimal, inf)*1/20).play;\r\n\r\n~short2 = PmonoArtic(\r\n\t\\Harrison2,\r\n\t\\formant, Pseq(~basimal, inf),\r\n\t\\fb1, Pseq([10, 1, 1], inf)*1/4,\r\n\t\\tube, Pseq([-0.9, -0.8, 1, 1/2, -1/2, -0.9], inf),\r\n\t\\root, ~root* Pstep([9/10, 1, 1], ~antiTempo*3/5, inf),\r\n\t\\uTone, Pstep(~\r\n\t\tbasimal.rotate(3), ~antiTempo*4/5, inf),\r\n\t\\oTone, Pstep(~basimal, ~antiTempo, inf),\r\n\t\\dur, Pseq(~basimal, inf)*(~antiTempo/10),\r\n\t\\legato, Pseq(~basimal, inf)*1/20\r\n).play;\r\n)"
}
