[{"data":1,"prerenderedAt":3717},["ShallowReactive",2],{"posts:\u002Fposts\u002F2022-04-08-karplus-on-a-worker":3},{"id":4,"title":5,"body":6,"categories":3702,"date":3704,"description":3705,"extension":3706,"image":3705,"lang":3705,"meta":3707,"navigation":75,"path":3708,"seo":3709,"stem":3710,"tags":3711,"titleInPicture":3715,"__hash__":3716},"posts\u002Fposts\u002F2022-04-08-karplus-on-a-worker.md","Worker + karplus synth example",{"type":7,"value":8,"toc":3684},"minimark",[9,14,18,23,26,59,63,66,222,226,229,423,427,437,441,444,1267,1271,1274,1277,1290,1743,1747,1750,1753,1756,2229,2236,2537,2541,2544,3043,3047,3051,3327,3331,3680],[10,11,13],"h2",{"id":12},"worker-code","Worker code",[15,16,17],"p",{},"You can add all this code into one file, if you like.",[19,20,22],"h3",{"id":21},"globals","Globals",[15,24,25],{},"I should fetch the samplingRate from the web audio context. But let's be lazy this time.",[27,28,33],"pre",{"className":29,"code":30,"language":31,"meta":32,"style":32},"language-js shiki shiki-themes github-dark","const samplingRate = 44100;\n","js","",[34,35,36],"code",{"__ignoreMap":32},[37,38,41,45,49,52,55],"span",{"class":39,"line":40},"line",1,[37,42,44],{"class":43},"snl16","const",[37,46,48],{"class":47},"sDLfK"," samplingRate",[37,50,51],{"class":43}," =",[37,53,54],{"class":47}," 44100",[37,56,58],{"class":57},"s95oV",";\n",[19,60,62],{"id":61},"main-types","Main types",[15,64,65],{},"This way it's easier to extend the functionality. The use will become clear below.",[27,67,69],{"className":29,"code":68,"language":31,"meta":32,"style":32},"\nclass SampleBySampleOperator {\n    operation = (inSample) => inSample;\n}\n\n\nclass Voice {\n    getBlock(size) { }\n    trigger({ freq, amp }) { }\n    stealTrigger = (p) => this.trigger(p);\n    isBusy = false;\n}\n",[34,70,71,77,90,114,120,125,130,140,155,176,204,217],{"__ignoreMap":32},[37,72,73],{"class":39,"line":40},[37,74,76],{"emptyLinePlaceholder":75},true,"\n",[37,78,80,83,87],{"class":39,"line":79},2,[37,81,82],{"class":43},"class",[37,84,86],{"class":85},"svObZ"," SampleBySampleOperator",[37,88,89],{"class":57}," {\n",[37,91,93,96,98,101,105,108,111],{"class":39,"line":92},3,[37,94,95],{"class":85},"    operation",[37,97,51],{"class":43},[37,99,100],{"class":57}," (",[37,102,104],{"class":103},"s9osk","inSample",[37,106,107],{"class":57},") ",[37,109,110],{"class":43},"=>",[37,112,113],{"class":57}," inSample;\n",[37,115,117],{"class":39,"line":116},4,[37,118,119],{"class":57},"}\n",[37,121,123],{"class":39,"line":122},5,[37,124,76],{"emptyLinePlaceholder":75},[37,126,128],{"class":39,"line":127},6,[37,129,76],{"emptyLinePlaceholder":75},[37,131,133,135,138],{"class":39,"line":132},7,[37,134,82],{"class":43},[37,136,137],{"class":85}," Voice",[37,139,89],{"class":57},[37,141,143,146,149,152],{"class":39,"line":142},8,[37,144,145],{"class":85},"    getBlock",[37,147,148],{"class":57},"(",[37,150,151],{"class":103},"size",[37,153,154],{"class":57},") { }\n",[37,156,158,161,164,167,170,173],{"class":39,"line":157},9,[37,159,160],{"class":85},"    trigger",[37,162,163],{"class":57},"({ ",[37,165,166],{"class":103},"freq",[37,168,169],{"class":57},", ",[37,171,172],{"class":103},"amp",[37,174,175],{"class":57}," }) { }\n",[37,177,179,182,184,186,188,190,192,195,198,201],{"class":39,"line":178},10,[37,180,181],{"class":85},"    stealTrigger",[37,183,51],{"class":43},[37,185,100],{"class":57},[37,187,15],{"class":103},[37,189,107],{"class":57},[37,191,110],{"class":43},[37,193,194],{"class":47}," this",[37,196,197],{"class":57},".",[37,199,200],{"class":85},"trigger",[37,202,203],{"class":57},"(p);\n",[37,205,207,210,212,215],{"class":39,"line":206},11,[37,208,209],{"class":103},"    isBusy",[37,211,51],{"class":43},[37,213,214],{"class":47}," false",[37,216,58],{"class":57},[37,218,220],{"class":39,"line":219},12,[37,221,119],{"class":57},[19,223,225],{"id":224},"faster-random-generator","Faster random generator",[15,227,228],{},"We are not using this for a security application, so we can really use any random generator.",[27,230,232],{"className":29,"code":231,"language":31,"meta":32,"style":32},"\nfunction mulberry32(a) {\n    return function() {\n      var t = a += 0x6D2B79F5;\n      t = Math.imul(t ^ t >>> 15, t | 1);\n      t ^= t + Math.imul(t ^ t >>> 7, t | 61);\n      return ((t ^ t >>> 14) >>> 0) \u002F 4294967296;\n    }\n}\nconst random = mulberry32(38913);\n\n",[34,233,234,238,254,265,287,326,362,396,401,405],{"__ignoreMap":32},[37,235,236],{"class":39,"line":40},[37,237,76],{"emptyLinePlaceholder":75},[37,239,240,243,246,248,251],{"class":39,"line":79},[37,241,242],{"class":43},"function",[37,244,245],{"class":85}," mulberry32",[37,247,148],{"class":57},[37,249,250],{"class":103},"a",[37,252,253],{"class":57},") {\n",[37,255,256,259,262],{"class":39,"line":92},[37,257,258],{"class":43},"    return",[37,260,261],{"class":43}," function",[37,263,264],{"class":57},"() {\n",[37,266,267,270,273,276,279,282,285],{"class":39,"line":116},[37,268,269],{"class":43},"      var",[37,271,272],{"class":57}," t ",[37,274,275],{"class":43},"=",[37,277,278],{"class":57}," a ",[37,280,281],{"class":43},"+=",[37,283,284],{"class":47}," 0x6D2B79F5",[37,286,58],{"class":57},[37,288,289,292,294,297,300,303,306,308,311,314,317,320,323],{"class":39,"line":122},[37,290,291],{"class":57},"      t ",[37,293,275],{"class":43},[37,295,296],{"class":57}," Math.",[37,298,299],{"class":85},"imul",[37,301,302],{"class":57},"(t ",[37,304,305],{"class":43},"^",[37,307,272],{"class":57},[37,309,310],{"class":43},">>>",[37,312,313],{"class":47}," 15",[37,315,316],{"class":57},", t ",[37,318,319],{"class":43},"|",[37,321,322],{"class":47}," 1",[37,324,325],{"class":57},");\n",[37,327,328,330,333,335,338,340,342,344,346,348,350,353,355,357,360],{"class":39,"line":127},[37,329,291],{"class":57},[37,331,332],{"class":43},"^=",[37,334,272],{"class":57},[37,336,337],{"class":43},"+",[37,339,296],{"class":57},[37,341,299],{"class":85},[37,343,302],{"class":57},[37,345,305],{"class":43},[37,347,272],{"class":57},[37,349,310],{"class":43},[37,351,352],{"class":47}," 7",[37,354,316],{"class":57},[37,356,319],{"class":43},[37,358,359],{"class":47}," 61",[37,361,325],{"class":57},[37,363,364,367,370,372,374,376,379,381,383,386,388,391,394],{"class":39,"line":132},[37,365,366],{"class":43},"      return",[37,368,369],{"class":57}," ((t ",[37,371,305],{"class":43},[37,373,272],{"class":57},[37,375,310],{"class":43},[37,377,378],{"class":47}," 14",[37,380,107],{"class":57},[37,382,310],{"class":43},[37,384,385],{"class":47}," 0",[37,387,107],{"class":57},[37,389,390],{"class":43},"\u002F",[37,392,393],{"class":47}," 4294967296",[37,395,58],{"class":57},[37,397,398],{"class":39,"line":142},[37,399,400],{"class":57},"    }\n",[37,402,403],{"class":39,"line":157},[37,404,119],{"class":57},[37,406,407,409,412,414,416,418,421],{"class":39,"line":178},[37,408,44],{"class":43},[37,410,411],{"class":47}," random",[37,413,51],{"class":43},[37,415,245],{"class":85},[37,417,148],{"class":57},[37,419,420],{"class":47},"38913",[37,422,325],{"class":57},[19,424,426],{"id":425},"the-actual-synthesis","The actual synthesis",[15,428,429,430,433,434,197],{},"These are the operators that produce the sound. The modules, if you will.\nNote that one of these operate on each sample, while the other works for each block, hence the need for different classes: ",[34,431,432],{},"SampleBySampleOperator"," and ",[34,435,436],{},"Voice",[19,438,440],{"id":439},"delay-line","Delay line",[15,442,443],{},"It's like a guitar delay. An effect can be sidechained; so that the sound is modified every time it's looped back. (tape delays are famous for doing this, for example).",[27,445,447],{"className":29,"code":446,"language":31,"meta":32,"style":32},"\nclass RingBuffer {\n    constructor(length) {\n        let pointer = 0\n        \u002F\u002F let buffer = new Float32Array(length);\n        let buffer = [];\n        this.length = length;\n\n        this.get = (key) => {\n            if (key \u003C 0) {\n                let t_pointer = pointer + key;\n                while (t_pointer \u003C 0) {\n                    t_pointer += length;\n                }\n                return buffer[pointer + key];\n            } else {\n                return buffer[(pointer + key) % length];\n            }\n        }\n        this.push = (item) => {\n            buffer[pointer] = item;\n            pointer = (pointer + 1) % length;\n            return pointer;\n        }\n        this.next = () => {\n            pointer = (pointer + 1) % length;\n            return buffer[pointer];\n        }\n        this.getCurrent = () => {\n            return buffer[pointer] || 0;\n        }\n        this.resize = (newLength) => {\n            if(newLength > length){\n                \u002F\u002F buffer = new Float32Array(\n                \u002F\u002F     buffer.slice(0, length)\n                \u002F\u002F );\n            }\n            length = newLength;\n            this.length = length;\n        }\n        this.getAll = () => buffer;\n    }\n};\n\nclass DelayLine extends SampleBySampleOperator {\n    \u002F** @type {RingBuffer}*\u002F\n    memory = new RingBuffer(512);\n    delaySamples = 400;\n    feedback = -0.99;\n\n    \u002F** @type {SampleBySampleOperator|null} *\u002F\n    sidechainEffect = null;\n\n    operation = (insample) => {\n        if (this.memory.length != this.delaySamples) {\n            this.memory.resize(this.delaySamples);\n        }\n\n        \u002F\u002F get delayed sample\n        let oldestSample = this.memory.getCurrent();\n        let ret = oldestSample + insample;\n\n        if (this.sidechainEffect) {\n            ret = this.sidechainEffect.operation(ret);\n        }\n\n        \u002F\u002Fwrite output into delay line\n        this.memory.push(ret * this.feedback);\n\n        return ret;\n    }\n}\n\n\n",[34,448,449,453,462,474,487,493,505,519,523,545,560,577,591,601,607,621,632,651,657,663,686,697,718,727,732,751,770,778,783,801,816,821,844,858,864,870,876,881,892,906,911,930,935,941,946,961,976,996,1009,1025,1030,1043,1056,1061,1079,1103,1119,1124,1129,1135,1154,1171,1176,1188,1207,1212,1217,1223,1243,1248,1257,1262],{"__ignoreMap":32},[37,450,451],{"class":39,"line":40},[37,452,76],{"emptyLinePlaceholder":75},[37,454,455,457,460],{"class":39,"line":79},[37,456,82],{"class":43},[37,458,459],{"class":85}," RingBuffer",[37,461,89],{"class":57},[37,463,464,467,469,472],{"class":39,"line":92},[37,465,466],{"class":43},"    constructor",[37,468,148],{"class":57},[37,470,471],{"class":103},"length",[37,473,253],{"class":57},[37,475,476,479,482,484],{"class":39,"line":116},[37,477,478],{"class":43},"        let",[37,480,481],{"class":57}," pointer ",[37,483,275],{"class":43},[37,485,486],{"class":47}," 0\n",[37,488,489],{"class":39,"line":122},[37,490,492],{"class":491},"sAwPA","        \u002F\u002F let buffer = new Float32Array(length);\n",[37,494,495,497,500,502],{"class":39,"line":127},[37,496,478],{"class":43},[37,498,499],{"class":57}," buffer ",[37,501,275],{"class":43},[37,503,504],{"class":57}," [];\n",[37,506,507,510,512,514,516],{"class":39,"line":132},[37,508,509],{"class":47},"        this",[37,511,197],{"class":57},[37,513,471],{"class":47},[37,515,51],{"class":43},[37,517,518],{"class":57}," length;\n",[37,520,521],{"class":39,"line":142},[37,522,76],{"emptyLinePlaceholder":75},[37,524,525,527,529,532,534,536,539,541,543],{"class":39,"line":157},[37,526,509],{"class":47},[37,528,197],{"class":57},[37,530,531],{"class":85},"get",[37,533,51],{"class":43},[37,535,100],{"class":57},[37,537,538],{"class":103},"key",[37,540,107],{"class":57},[37,542,110],{"class":43},[37,544,89],{"class":57},[37,546,547,550,553,556,558],{"class":39,"line":178},[37,548,549],{"class":43},"            if",[37,551,552],{"class":57}," (key ",[37,554,555],{"class":43},"\u003C",[37,557,385],{"class":47},[37,559,253],{"class":57},[37,561,562,565,568,570,572,574],{"class":39,"line":206},[37,563,564],{"class":43},"                let",[37,566,567],{"class":57}," t_pointer ",[37,569,275],{"class":43},[37,571,481],{"class":57},[37,573,337],{"class":43},[37,575,576],{"class":57}," key;\n",[37,578,579,582,585,587,589],{"class":39,"line":219},[37,580,581],{"class":43},"                while",[37,583,584],{"class":57}," (t_pointer ",[37,586,555],{"class":43},[37,588,385],{"class":47},[37,590,253],{"class":57},[37,592,594,597,599],{"class":39,"line":593},13,[37,595,596],{"class":57},"                    t_pointer ",[37,598,281],{"class":43},[37,600,518],{"class":57},[37,602,604],{"class":39,"line":603},14,[37,605,606],{"class":57},"                }\n",[37,608,610,613,616,618],{"class":39,"line":609},15,[37,611,612],{"class":43},"                return",[37,614,615],{"class":57}," buffer[pointer ",[37,617,337],{"class":43},[37,619,620],{"class":57}," key];\n",[37,622,624,627,630],{"class":39,"line":623},16,[37,625,626],{"class":57},"            } ",[37,628,629],{"class":43},"else",[37,631,89],{"class":57},[37,633,635,637,640,642,645,648],{"class":39,"line":634},17,[37,636,612],{"class":43},[37,638,639],{"class":57}," buffer[(pointer ",[37,641,337],{"class":43},[37,643,644],{"class":57}," key) ",[37,646,647],{"class":43},"%",[37,649,650],{"class":57}," length];\n",[37,652,654],{"class":39,"line":653},18,[37,655,656],{"class":57},"            }\n",[37,658,660],{"class":39,"line":659},19,[37,661,662],{"class":57},"        }\n",[37,664,666,668,670,673,675,677,680,682,684],{"class":39,"line":665},20,[37,667,509],{"class":47},[37,669,197],{"class":57},[37,671,672],{"class":85},"push",[37,674,51],{"class":43},[37,676,100],{"class":57},[37,678,679],{"class":103},"item",[37,681,107],{"class":57},[37,683,110],{"class":43},[37,685,89],{"class":57},[37,687,689,692,694],{"class":39,"line":688},21,[37,690,691],{"class":57},"            buffer[pointer] ",[37,693,275],{"class":43},[37,695,696],{"class":57}," item;\n",[37,698,700,703,705,708,710,712,714,716],{"class":39,"line":699},22,[37,701,702],{"class":57},"            pointer ",[37,704,275],{"class":43},[37,706,707],{"class":57}," (pointer ",[37,709,337],{"class":43},[37,711,322],{"class":47},[37,713,107],{"class":57},[37,715,647],{"class":43},[37,717,518],{"class":57},[37,719,721,724],{"class":39,"line":720},23,[37,722,723],{"class":43},"            return",[37,725,726],{"class":57}," pointer;\n",[37,728,730],{"class":39,"line":729},24,[37,731,662],{"class":57},[37,733,735,737,739,742,744,747,749],{"class":39,"line":734},25,[37,736,509],{"class":47},[37,738,197],{"class":57},[37,740,741],{"class":85},"next",[37,743,51],{"class":43},[37,745,746],{"class":57}," () ",[37,748,110],{"class":43},[37,750,89],{"class":57},[37,752,754,756,758,760,762,764,766,768],{"class":39,"line":753},26,[37,755,702],{"class":57},[37,757,275],{"class":43},[37,759,707],{"class":57},[37,761,337],{"class":43},[37,763,322],{"class":47},[37,765,107],{"class":57},[37,767,647],{"class":43},[37,769,518],{"class":57},[37,771,773,775],{"class":39,"line":772},27,[37,774,723],{"class":43},[37,776,777],{"class":57}," buffer[pointer];\n",[37,779,781],{"class":39,"line":780},28,[37,782,662],{"class":57},[37,784,786,788,790,793,795,797,799],{"class":39,"line":785},29,[37,787,509],{"class":47},[37,789,197],{"class":57},[37,791,792],{"class":85},"getCurrent",[37,794,51],{"class":43},[37,796,746],{"class":57},[37,798,110],{"class":43},[37,800,89],{"class":57},[37,802,804,806,809,812,814],{"class":39,"line":803},30,[37,805,723],{"class":43},[37,807,808],{"class":57}," buffer[pointer] ",[37,810,811],{"class":43},"||",[37,813,385],{"class":47},[37,815,58],{"class":57},[37,817,819],{"class":39,"line":818},31,[37,820,662],{"class":57},[37,822,824,826,828,831,833,835,838,840,842],{"class":39,"line":823},32,[37,825,509],{"class":47},[37,827,197],{"class":57},[37,829,830],{"class":85},"resize",[37,832,51],{"class":43},[37,834,100],{"class":57},[37,836,837],{"class":103},"newLength",[37,839,107],{"class":57},[37,841,110],{"class":43},[37,843,89],{"class":57},[37,845,847,849,852,855],{"class":39,"line":846},33,[37,848,549],{"class":43},[37,850,851],{"class":57},"(newLength ",[37,853,854],{"class":43},">",[37,856,857],{"class":57}," length){\n",[37,859,861],{"class":39,"line":860},34,[37,862,863],{"class":491},"                \u002F\u002F buffer = new Float32Array(\n",[37,865,867],{"class":39,"line":866},35,[37,868,869],{"class":491},"                \u002F\u002F     buffer.slice(0, length)\n",[37,871,873],{"class":39,"line":872},36,[37,874,875],{"class":491},"                \u002F\u002F );\n",[37,877,879],{"class":39,"line":878},37,[37,880,656],{"class":57},[37,882,884,887,889],{"class":39,"line":883},38,[37,885,886],{"class":57},"            length ",[37,888,275],{"class":43},[37,890,891],{"class":57}," newLength;\n",[37,893,895,898,900,902,904],{"class":39,"line":894},39,[37,896,897],{"class":47},"            this",[37,899,197],{"class":57},[37,901,471],{"class":47},[37,903,51],{"class":43},[37,905,518],{"class":57},[37,907,909],{"class":39,"line":908},40,[37,910,662],{"class":57},[37,912,914,916,918,921,923,925,927],{"class":39,"line":913},41,[37,915,509],{"class":47},[37,917,197],{"class":57},[37,919,920],{"class":85},"getAll",[37,922,51],{"class":43},[37,924,746],{"class":57},[37,926,110],{"class":43},[37,928,929],{"class":57}," buffer;\n",[37,931,933],{"class":39,"line":932},42,[37,934,400],{"class":57},[37,936,938],{"class":39,"line":937},43,[37,939,940],{"class":57},"};\n",[37,942,944],{"class":39,"line":943},44,[37,945,76],{"emptyLinePlaceholder":75},[37,947,949,951,954,957,959],{"class":39,"line":948},45,[37,950,82],{"class":43},[37,952,953],{"class":85}," DelayLine",[37,955,956],{"class":43}," extends",[37,958,86],{"class":85},[37,960,89],{"class":57},[37,962,964,967,970,973],{"class":39,"line":963},46,[37,965,966],{"class":491},"    \u002F** ",[37,968,969],{"class":43},"@type",[37,971,972],{"class":85}," {RingBuffer}",[37,974,975],{"class":491},"*\u002F\n",[37,977,979,982,984,987,989,991,994],{"class":39,"line":978},47,[37,980,981],{"class":103},"    memory",[37,983,51],{"class":43},[37,985,986],{"class":43}," new",[37,988,459],{"class":85},[37,990,148],{"class":57},[37,992,993],{"class":47},"512",[37,995,325],{"class":57},[37,997,999,1002,1004,1007],{"class":39,"line":998},48,[37,1000,1001],{"class":103},"    delaySamples",[37,1003,51],{"class":43},[37,1005,1006],{"class":47}," 400",[37,1008,58],{"class":57},[37,1010,1012,1015,1017,1020,1023],{"class":39,"line":1011},49,[37,1013,1014],{"class":103},"    feedback",[37,1016,51],{"class":43},[37,1018,1019],{"class":43}," -",[37,1021,1022],{"class":47},"0.99",[37,1024,58],{"class":57},[37,1026,1028],{"class":39,"line":1027},50,[37,1029,76],{"emptyLinePlaceholder":75},[37,1031,1033,1035,1037,1040],{"class":39,"line":1032},51,[37,1034,966],{"class":491},[37,1036,969],{"class":43},[37,1038,1039],{"class":85}," {SampleBySampleOperator|null}",[37,1041,1042],{"class":491}," *\u002F\n",[37,1044,1046,1049,1051,1054],{"class":39,"line":1045},52,[37,1047,1048],{"class":103},"    sidechainEffect",[37,1050,51],{"class":43},[37,1052,1053],{"class":47}," null",[37,1055,58],{"class":57},[37,1057,1059],{"class":39,"line":1058},53,[37,1060,76],{"emptyLinePlaceholder":75},[37,1062,1064,1066,1068,1070,1073,1075,1077],{"class":39,"line":1063},54,[37,1065,95],{"class":85},[37,1067,51],{"class":43},[37,1069,100],{"class":57},[37,1071,1072],{"class":103},"insample",[37,1074,107],{"class":57},[37,1076,110],{"class":43},[37,1078,89],{"class":57},[37,1080,1082,1085,1087,1090,1093,1095,1098,1100],{"class":39,"line":1081},55,[37,1083,1084],{"class":43},"        if",[37,1086,100],{"class":57},[37,1088,1089],{"class":47},"this",[37,1091,1092],{"class":57},".memory.",[37,1094,471],{"class":47},[37,1096,1097],{"class":43}," !=",[37,1099,194],{"class":47},[37,1101,1102],{"class":57},".delaySamples) {\n",[37,1104,1106,1108,1110,1112,1114,1116],{"class":39,"line":1105},56,[37,1107,897],{"class":47},[37,1109,1092],{"class":57},[37,1111,830],{"class":85},[37,1113,148],{"class":57},[37,1115,1089],{"class":47},[37,1117,1118],{"class":57},".delaySamples);\n",[37,1120,1122],{"class":39,"line":1121},57,[37,1123,662],{"class":57},[37,1125,1127],{"class":39,"line":1126},58,[37,1128,76],{"emptyLinePlaceholder":75},[37,1130,1132],{"class":39,"line":1131},59,[37,1133,1134],{"class":491},"        \u002F\u002F get delayed sample\n",[37,1136,1138,1140,1143,1145,1147,1149,1151],{"class":39,"line":1137},60,[37,1139,478],{"class":43},[37,1141,1142],{"class":57}," oldestSample ",[37,1144,275],{"class":43},[37,1146,194],{"class":47},[37,1148,1092],{"class":57},[37,1150,792],{"class":85},[37,1152,1153],{"class":57},"();\n",[37,1155,1157,1159,1162,1164,1166,1168],{"class":39,"line":1156},61,[37,1158,478],{"class":43},[37,1160,1161],{"class":57}," ret ",[37,1163,275],{"class":43},[37,1165,1142],{"class":57},[37,1167,337],{"class":43},[37,1169,1170],{"class":57}," insample;\n",[37,1172,1174],{"class":39,"line":1173},62,[37,1175,76],{"emptyLinePlaceholder":75},[37,1177,1179,1181,1183,1185],{"class":39,"line":1178},63,[37,1180,1084],{"class":43},[37,1182,100],{"class":57},[37,1184,1089],{"class":47},[37,1186,1187],{"class":57},".sidechainEffect) {\n",[37,1189,1191,1194,1196,1198,1201,1204],{"class":39,"line":1190},64,[37,1192,1193],{"class":57},"            ret ",[37,1195,275],{"class":43},[37,1197,194],{"class":47},[37,1199,1200],{"class":57},".sidechainEffect.",[37,1202,1203],{"class":85},"operation",[37,1205,1206],{"class":57},"(ret);\n",[37,1208,1210],{"class":39,"line":1209},65,[37,1211,662],{"class":57},[37,1213,1215],{"class":39,"line":1214},66,[37,1216,76],{"emptyLinePlaceholder":75},[37,1218,1220],{"class":39,"line":1219},67,[37,1221,1222],{"class":491},"        \u002F\u002Fwrite output into delay line\n",[37,1224,1226,1228,1230,1232,1235,1238,1240],{"class":39,"line":1225},68,[37,1227,509],{"class":47},[37,1229,1092],{"class":57},[37,1231,672],{"class":85},[37,1233,1234],{"class":57},"(ret ",[37,1236,1237],{"class":43},"*",[37,1239,194],{"class":47},[37,1241,1242],{"class":57},".feedback);\n",[37,1244,1246],{"class":39,"line":1245},69,[37,1247,76],{"emptyLinePlaceholder":75},[37,1249,1251,1254],{"class":39,"line":1250},70,[37,1252,1253],{"class":43},"        return",[37,1255,1256],{"class":57}," ret;\n",[37,1258,1260],{"class":39,"line":1259},71,[37,1261,400],{"class":57},[37,1263,1265],{"class":39,"line":1264},72,[37,1266,119],{"class":57},[19,1268,1270],{"id":1269},"infinite-impulse-response-filter","Infinite impulse response filter",[15,1272,1273],{},"These are not vital for this synth, but in my opinion, using filters on a karplus synth improves the sound and the possibilities a lot.",[15,1275,1276],{},"Filters that have a theoretically infinite state, because they pick up their own output as input.\nI like to think of filters in three ways:",[1278,1279,1280,1284,1287],"ul",{},[1281,1282,1283],"li",{},"A filter is a sample averager. By averaging current and past sample, the effect is a muffling of the output.",[1281,1285,1286],{},"A filter is a very short delay line. By mixing it's current output to some of past outputs, the result is an average of the last times.",[1281,1288,1289],{},"A filter is akin to image processing's kernel-based filters. Depending on the coefficients of each kernel (in this case, one-dimensional), one might get an \"edge detector\" which would be a high pass filter, or a \"blur\", which would be a low-pass.",[27,1291,1293],{"className":29,"code":1292,"language":31,"meta":32,"style":32},"\nclass IIRFilter extends SampleBySampleOperator {\n    \u002F** @type {Number}*\u002F\n    memory = 0;\n    k = 0.01;\n    amp = 0.99;\n    operation = (insample) => {\n        let ret = 0;\n        let ik = 1 - this.k;\n        ret = insample * ik;\n        ret += this.memory * this.k;\n        ret *= this.amp;\n\n        this.memory = ret;\n        return ret;\n    }\n    constructor(props = {}) {\n        super();\n        Object.assign(this, props);\n    }\n}\n\nclass IIRFilter1 extends SampleBySampleOperator {\n    \u002F** @type {Array\u003CNumber>}*\u002F\n    memory = [0, 0, 0];\n    amp = 0.99;\n    operation = (insample) => {\n        let ret = 0;\n\n        ret = insample * 0.01;\n        ret += this.memory[0] * 0.2;\n        ret += this.memory[1] * 0.3;\n        ret += this.memory[2] * 0.49;\n        ret *= this.amp;\n\n        this.memory.pop();\n        this.memory.unshift(ret);\n\n        return ret;\n    }\n}\n",[34,1294,1295,1299,1312,1323,1333,1345,1357,1373,1385,1403,1418,1435,1447,1451,1461,1467,1471,1485,1492,1507,1511,1515,1519,1532,1543,1566,1576,1592,1604,1608,1622,1645,1667,1689,1699,1703,1714,1725,1729,1735,1739],{"__ignoreMap":32},[37,1296,1297],{"class":39,"line":40},[37,1298,76],{"emptyLinePlaceholder":75},[37,1300,1301,1303,1306,1308,1310],{"class":39,"line":79},[37,1302,82],{"class":43},[37,1304,1305],{"class":85}," IIRFilter",[37,1307,956],{"class":43},[37,1309,86],{"class":85},[37,1311,89],{"class":57},[37,1313,1314,1316,1318,1321],{"class":39,"line":92},[37,1315,966],{"class":491},[37,1317,969],{"class":43},[37,1319,1320],{"class":85}," {Number}",[37,1322,975],{"class":491},[37,1324,1325,1327,1329,1331],{"class":39,"line":116},[37,1326,981],{"class":103},[37,1328,51],{"class":43},[37,1330,385],{"class":47},[37,1332,58],{"class":57},[37,1334,1335,1338,1340,1343],{"class":39,"line":122},[37,1336,1337],{"class":103},"    k",[37,1339,51],{"class":43},[37,1341,1342],{"class":47}," 0.01",[37,1344,58],{"class":57},[37,1346,1347,1350,1352,1355],{"class":39,"line":127},[37,1348,1349],{"class":103},"    amp",[37,1351,51],{"class":43},[37,1353,1354],{"class":47}," 0.99",[37,1356,58],{"class":57},[37,1358,1359,1361,1363,1365,1367,1369,1371],{"class":39,"line":132},[37,1360,95],{"class":85},[37,1362,51],{"class":43},[37,1364,100],{"class":57},[37,1366,1072],{"class":103},[37,1368,107],{"class":57},[37,1370,110],{"class":43},[37,1372,89],{"class":57},[37,1374,1375,1377,1379,1381,1383],{"class":39,"line":142},[37,1376,478],{"class":43},[37,1378,1161],{"class":57},[37,1380,275],{"class":43},[37,1382,385],{"class":47},[37,1384,58],{"class":57},[37,1386,1387,1389,1392,1394,1396,1398,1400],{"class":39,"line":157},[37,1388,478],{"class":43},[37,1390,1391],{"class":57}," ik ",[37,1393,275],{"class":43},[37,1395,322],{"class":47},[37,1397,1019],{"class":43},[37,1399,194],{"class":47},[37,1401,1402],{"class":57},".k;\n",[37,1404,1405,1408,1410,1413,1415],{"class":39,"line":178},[37,1406,1407],{"class":57},"        ret ",[37,1409,275],{"class":43},[37,1411,1412],{"class":57}," insample ",[37,1414,1237],{"class":43},[37,1416,1417],{"class":57}," ik;\n",[37,1419,1420,1422,1424,1426,1429,1431,1433],{"class":39,"line":206},[37,1421,1407],{"class":57},[37,1423,281],{"class":43},[37,1425,194],{"class":47},[37,1427,1428],{"class":57},".memory ",[37,1430,1237],{"class":43},[37,1432,194],{"class":47},[37,1434,1402],{"class":57},[37,1436,1437,1439,1442,1444],{"class":39,"line":219},[37,1438,1407],{"class":57},[37,1440,1441],{"class":43},"*=",[37,1443,194],{"class":47},[37,1445,1446],{"class":57},".amp;\n",[37,1448,1449],{"class":39,"line":593},[37,1450,76],{"emptyLinePlaceholder":75},[37,1452,1453,1455,1457,1459],{"class":39,"line":603},[37,1454,509],{"class":47},[37,1456,1428],{"class":57},[37,1458,275],{"class":43},[37,1460,1256],{"class":57},[37,1462,1463,1465],{"class":39,"line":609},[37,1464,1253],{"class":43},[37,1466,1256],{"class":57},[37,1468,1469],{"class":39,"line":623},[37,1470,400],{"class":57},[37,1472,1473,1475,1477,1480,1482],{"class":39,"line":634},[37,1474,466],{"class":43},[37,1476,148],{"class":57},[37,1478,1479],{"class":103},"props",[37,1481,51],{"class":43},[37,1483,1484],{"class":57}," {}) {\n",[37,1486,1487,1490],{"class":39,"line":653},[37,1488,1489],{"class":47},"        super",[37,1491,1153],{"class":57},[37,1493,1494,1497,1500,1502,1504],{"class":39,"line":659},[37,1495,1496],{"class":57},"        Object.",[37,1498,1499],{"class":85},"assign",[37,1501,148],{"class":57},[37,1503,1089],{"class":47},[37,1505,1506],{"class":57},", props);\n",[37,1508,1509],{"class":39,"line":665},[37,1510,400],{"class":57},[37,1512,1513],{"class":39,"line":688},[37,1514,119],{"class":57},[37,1516,1517],{"class":39,"line":699},[37,1518,76],{"emptyLinePlaceholder":75},[37,1520,1521,1523,1526,1528,1530],{"class":39,"line":720},[37,1522,82],{"class":43},[37,1524,1525],{"class":85}," IIRFilter1",[37,1527,956],{"class":43},[37,1529,86],{"class":85},[37,1531,89],{"class":57},[37,1533,1534,1536,1538,1541],{"class":39,"line":729},[37,1535,966],{"class":491},[37,1537,969],{"class":43},[37,1539,1540],{"class":85}," {Array\u003CNumber>}",[37,1542,975],{"class":491},[37,1544,1545,1547,1549,1552,1555,1557,1559,1561,1563],{"class":39,"line":734},[37,1546,981],{"class":103},[37,1548,51],{"class":43},[37,1550,1551],{"class":57}," [",[37,1553,1554],{"class":47},"0",[37,1556,169],{"class":57},[37,1558,1554],{"class":47},[37,1560,169],{"class":57},[37,1562,1554],{"class":47},[37,1564,1565],{"class":57},"];\n",[37,1567,1568,1570,1572,1574],{"class":39,"line":753},[37,1569,1349],{"class":103},[37,1571,51],{"class":43},[37,1573,1354],{"class":47},[37,1575,58],{"class":57},[37,1577,1578,1580,1582,1584,1586,1588,1590],{"class":39,"line":772},[37,1579,95],{"class":85},[37,1581,51],{"class":43},[37,1583,100],{"class":57},[37,1585,1072],{"class":103},[37,1587,107],{"class":57},[37,1589,110],{"class":43},[37,1591,89],{"class":57},[37,1593,1594,1596,1598,1600,1602],{"class":39,"line":780},[37,1595,478],{"class":43},[37,1597,1161],{"class":57},[37,1599,275],{"class":43},[37,1601,385],{"class":47},[37,1603,58],{"class":57},[37,1605,1606],{"class":39,"line":785},[37,1607,76],{"emptyLinePlaceholder":75},[37,1609,1610,1612,1614,1616,1618,1620],{"class":39,"line":803},[37,1611,1407],{"class":57},[37,1613,275],{"class":43},[37,1615,1412],{"class":57},[37,1617,1237],{"class":43},[37,1619,1342],{"class":47},[37,1621,58],{"class":57},[37,1623,1624,1626,1628,1630,1633,1635,1638,1640,1643],{"class":39,"line":818},[37,1625,1407],{"class":57},[37,1627,281],{"class":43},[37,1629,194],{"class":47},[37,1631,1632],{"class":57},".memory[",[37,1634,1554],{"class":47},[37,1636,1637],{"class":57},"] ",[37,1639,1237],{"class":43},[37,1641,1642],{"class":47}," 0.2",[37,1644,58],{"class":57},[37,1646,1647,1649,1651,1653,1655,1658,1660,1662,1665],{"class":39,"line":823},[37,1648,1407],{"class":57},[37,1650,281],{"class":43},[37,1652,194],{"class":47},[37,1654,1632],{"class":57},[37,1656,1657],{"class":47},"1",[37,1659,1637],{"class":57},[37,1661,1237],{"class":43},[37,1663,1664],{"class":47}," 0.3",[37,1666,58],{"class":57},[37,1668,1669,1671,1673,1675,1677,1680,1682,1684,1687],{"class":39,"line":846},[37,1670,1407],{"class":57},[37,1672,281],{"class":43},[37,1674,194],{"class":47},[37,1676,1632],{"class":57},[37,1678,1679],{"class":47},"2",[37,1681,1637],{"class":57},[37,1683,1237],{"class":43},[37,1685,1686],{"class":47}," 0.49",[37,1688,58],{"class":57},[37,1690,1691,1693,1695,1697],{"class":39,"line":860},[37,1692,1407],{"class":57},[37,1694,1441],{"class":43},[37,1696,194],{"class":47},[37,1698,1446],{"class":57},[37,1700,1701],{"class":39,"line":866},[37,1702,76],{"emptyLinePlaceholder":75},[37,1704,1705,1707,1709,1712],{"class":39,"line":872},[37,1706,509],{"class":47},[37,1708,1092],{"class":57},[37,1710,1711],{"class":85},"pop",[37,1713,1153],{"class":57},[37,1715,1716,1718,1720,1723],{"class":39,"line":878},[37,1717,509],{"class":47},[37,1719,1092],{"class":57},[37,1721,1722],{"class":85},"unshift",[37,1724,1206],{"class":57},[37,1726,1727],{"class":39,"line":883},[37,1728,76],{"emptyLinePlaceholder":75},[37,1730,1731,1733],{"class":39,"line":894},[37,1732,1253],{"class":43},[37,1734,1256],{"class":57},[37,1736,1737],{"class":39,"line":908},[37,1738,400],{"class":57},[37,1740,1741],{"class":39,"line":913},[37,1742,119],{"class":57},[19,1744,1746],{"id":1745},"karplus-voice","Karplus voice.",[15,1748,1749],{},"By making a \"voice\" abstraction, instead of implementing it directly on the worker, making it polyphonic becomes trivial.",[15,1751,1752],{},"A karplus synth is not much more than a delay, of very short delay time and high feedback (near 1, where 1 is infinite sustain). The delay time is adjusted so that it corresponds to a frequency, which represents the note. This makes it theoretically the model of a guitar string: when a guitar string receives an impulse, the impulse will travel through the string very fast, and bounce on the edges back. All the frequencies that are resonant to that string will meet their bounce from the opposite edge, enhancing them, whereas the non-resonant frequencies will disperse out very fast from the string. The same happens with the very short delay line: the resonant frequencies will be enhanced by the delay as it repeats the last samples, whereas the other frequencies will not.",[15,1754,1755],{},"I made a simple version, which is the bare bones of a karplus string, and another, more complex version that filters the sound a bit so that it sounds warmer.",[27,1757,1759],{"className":29,"code":1758,"language":31,"meta":32,"style":32},"\n\nclass KarplusVoice extends Voice {\n    envVal = 0;\n    decayPerSample = 1 \u002F (samplingRate * 0.01);\n\n    \u002F** @type {DelayLine}*\u002F\n    delayLine = new DelayLine();\n\n    constructor(){\n        super();\n        this.delayLine.sidechainEffect = new IIRFilter({\n            k:0.1,\n        });\n    }\n\n    setDecay = (seconds) => this.decayPerSample = 1 \u002F (samplingRate * seconds);\n\n    trig({ freq, amp }) {\n        this.delayLine.feedback = -1.001;\n        this.envVal = amp;\n        this.delayLine.delaySamples = Math.round(samplingRate \u002F freq);\n        this.isBusy = true;\n    }\n    \u002F** @param {number} blockSize*\u002F\n    getBlock(blockSize) {\n        const output = new Float32Array(blockSize);\n        for (let splN = 0; splN \u003C blockSize; splN++) {\n            let sampleNow = (random() - 0.5) * this.envVal;\n            sampleNow = this.delayLine.operation(sampleNow);\n            output[splN] = sampleNow;\n            if (this.envVal > 0) {\n                this.envVal -= this.decayPerSample;\n            } else {\n                this.envVal = 0;\n            }\n        }\n        return output;\n    }\n}\n\n",[34,1760,1761,1765,1769,1782,1793,1814,1818,1829,1842,1846,1853,1859,1875,1886,1891,1895,1899,1933,1937,1953,1969,1981,2003,2017,2021,2036,2047,2065,2095,2128,2145,2155,2171,2186,2194,2206,2210,2214,2221,2225],{"__ignoreMap":32},[37,1762,1763],{"class":39,"line":40},[37,1764,76],{"emptyLinePlaceholder":75},[37,1766,1767],{"class":39,"line":79},[37,1768,76],{"emptyLinePlaceholder":75},[37,1770,1771,1773,1776,1778,1780],{"class":39,"line":92},[37,1772,82],{"class":43},[37,1774,1775],{"class":85}," KarplusVoice",[37,1777,956],{"class":43},[37,1779,137],{"class":85},[37,1781,89],{"class":57},[37,1783,1784,1787,1789,1791],{"class":39,"line":116},[37,1785,1786],{"class":103},"    envVal",[37,1788,51],{"class":43},[37,1790,385],{"class":47},[37,1792,58],{"class":57},[37,1794,1795,1798,1800,1802,1805,1808,1810,1812],{"class":39,"line":122},[37,1796,1797],{"class":103},"    decayPerSample",[37,1799,51],{"class":43},[37,1801,322],{"class":47},[37,1803,1804],{"class":43}," \u002F",[37,1806,1807],{"class":57}," (samplingRate ",[37,1809,1237],{"class":43},[37,1811,1342],{"class":47},[37,1813,325],{"class":57},[37,1815,1816],{"class":39,"line":127},[37,1817,76],{"emptyLinePlaceholder":75},[37,1819,1820,1822,1824,1827],{"class":39,"line":132},[37,1821,966],{"class":491},[37,1823,969],{"class":43},[37,1825,1826],{"class":85}," {DelayLine}",[37,1828,975],{"class":491},[37,1830,1831,1834,1836,1838,1840],{"class":39,"line":142},[37,1832,1833],{"class":103},"    delayLine",[37,1835,51],{"class":43},[37,1837,986],{"class":43},[37,1839,953],{"class":85},[37,1841,1153],{"class":57},[37,1843,1844],{"class":39,"line":157},[37,1845,76],{"emptyLinePlaceholder":75},[37,1847,1848,1850],{"class":39,"line":178},[37,1849,466],{"class":43},[37,1851,1852],{"class":57},"(){\n",[37,1854,1855,1857],{"class":39,"line":206},[37,1856,1489],{"class":47},[37,1858,1153],{"class":57},[37,1860,1861,1863,1866,1868,1870,1872],{"class":39,"line":219},[37,1862,509],{"class":47},[37,1864,1865],{"class":57},".delayLine.sidechainEffect ",[37,1867,275],{"class":43},[37,1869,986],{"class":43},[37,1871,1305],{"class":85},[37,1873,1874],{"class":57},"({\n",[37,1876,1877,1880,1883],{"class":39,"line":593},[37,1878,1879],{"class":57},"            k:",[37,1881,1882],{"class":47},"0.1",[37,1884,1885],{"class":57},",\n",[37,1887,1888],{"class":39,"line":603},[37,1889,1890],{"class":57},"        });\n",[37,1892,1893],{"class":39,"line":609},[37,1894,400],{"class":57},[37,1896,1897],{"class":39,"line":623},[37,1898,76],{"emptyLinePlaceholder":75},[37,1900,1901,1904,1906,1908,1911,1913,1915,1917,1920,1922,1924,1926,1928,1930],{"class":39,"line":634},[37,1902,1903],{"class":85},"    setDecay",[37,1905,51],{"class":43},[37,1907,100],{"class":57},[37,1909,1910],{"class":103},"seconds",[37,1912,107],{"class":57},[37,1914,110],{"class":43},[37,1916,194],{"class":47},[37,1918,1919],{"class":57},".decayPerSample ",[37,1921,275],{"class":43},[37,1923,322],{"class":47},[37,1925,1804],{"class":43},[37,1927,1807],{"class":57},[37,1929,1237],{"class":43},[37,1931,1932],{"class":57}," seconds);\n",[37,1934,1935],{"class":39,"line":653},[37,1936,76],{"emptyLinePlaceholder":75},[37,1938,1939,1942,1944,1946,1948,1950],{"class":39,"line":659},[37,1940,1941],{"class":85},"    trig",[37,1943,163],{"class":57},[37,1945,166],{"class":103},[37,1947,169],{"class":57},[37,1949,172],{"class":103},[37,1951,1952],{"class":57}," }) {\n",[37,1954,1955,1957,1960,1962,1964,1967],{"class":39,"line":665},[37,1956,509],{"class":47},[37,1958,1959],{"class":57},".delayLine.feedback ",[37,1961,275],{"class":43},[37,1963,1019],{"class":43},[37,1965,1966],{"class":47},"1.001",[37,1968,58],{"class":57},[37,1970,1971,1973,1976,1978],{"class":39,"line":688},[37,1972,509],{"class":47},[37,1974,1975],{"class":57},".envVal ",[37,1977,275],{"class":43},[37,1979,1980],{"class":57}," amp;\n",[37,1982,1983,1985,1988,1990,1992,1995,1998,2000],{"class":39,"line":699},[37,1984,509],{"class":47},[37,1986,1987],{"class":57},".delayLine.delaySamples ",[37,1989,275],{"class":43},[37,1991,296],{"class":57},[37,1993,1994],{"class":85},"round",[37,1996,1997],{"class":57},"(samplingRate ",[37,1999,390],{"class":43},[37,2001,2002],{"class":57}," freq);\n",[37,2004,2005,2007,2010,2012,2015],{"class":39,"line":720},[37,2006,509],{"class":47},[37,2008,2009],{"class":57},".isBusy ",[37,2011,275],{"class":43},[37,2013,2014],{"class":47}," true",[37,2016,58],{"class":57},[37,2018,2019],{"class":39,"line":729},[37,2020,400],{"class":57},[37,2022,2023,2025,2028,2031,2034],{"class":39,"line":734},[37,2024,966],{"class":491},[37,2026,2027],{"class":43},"@param",[37,2029,2030],{"class":85}," {number}",[37,2032,2033],{"class":57}," blockSize",[37,2035,975],{"class":491},[37,2037,2038,2040,2042,2045],{"class":39,"line":753},[37,2039,145],{"class":85},[37,2041,148],{"class":57},[37,2043,2044],{"class":103},"blockSize",[37,2046,253],{"class":57},[37,2048,2049,2052,2055,2057,2059,2062],{"class":39,"line":772},[37,2050,2051],{"class":43},"        const",[37,2053,2054],{"class":47}," output",[37,2056,51],{"class":43},[37,2058,986],{"class":43},[37,2060,2061],{"class":85}," Float32Array",[37,2063,2064],{"class":57},"(blockSize);\n",[37,2066,2067,2070,2072,2075,2078,2080,2082,2085,2087,2090,2093],{"class":39,"line":780},[37,2068,2069],{"class":43},"        for",[37,2071,100],{"class":57},[37,2073,2074],{"class":43},"let",[37,2076,2077],{"class":57}," splN ",[37,2079,275],{"class":43},[37,2081,385],{"class":47},[37,2083,2084],{"class":57},"; splN ",[37,2086,555],{"class":43},[37,2088,2089],{"class":57}," blockSize; splN",[37,2091,2092],{"class":43},"++",[37,2094,253],{"class":57},[37,2096,2097,2100,2103,2105,2107,2110,2113,2116,2119,2121,2123,2125],{"class":39,"line":785},[37,2098,2099],{"class":43},"            let",[37,2101,2102],{"class":57}," sampleNow ",[37,2104,275],{"class":43},[37,2106,100],{"class":57},[37,2108,2109],{"class":85},"random",[37,2111,2112],{"class":57},"() ",[37,2114,2115],{"class":43},"-",[37,2117,2118],{"class":47}," 0.5",[37,2120,107],{"class":57},[37,2122,1237],{"class":43},[37,2124,194],{"class":47},[37,2126,2127],{"class":57},".envVal;\n",[37,2129,2130,2133,2135,2137,2140,2142],{"class":39,"line":803},[37,2131,2132],{"class":57},"            sampleNow ",[37,2134,275],{"class":43},[37,2136,194],{"class":47},[37,2138,2139],{"class":57},".delayLine.",[37,2141,1203],{"class":85},[37,2143,2144],{"class":57},"(sampleNow);\n",[37,2146,2147,2150,2152],{"class":39,"line":818},[37,2148,2149],{"class":57},"            output[splN] ",[37,2151,275],{"class":43},[37,2153,2154],{"class":57}," sampleNow;\n",[37,2156,2157,2159,2161,2163,2165,2167,2169],{"class":39,"line":823},[37,2158,549],{"class":43},[37,2160,100],{"class":57},[37,2162,1089],{"class":47},[37,2164,1975],{"class":57},[37,2166,854],{"class":43},[37,2168,385],{"class":47},[37,2170,253],{"class":57},[37,2172,2173,2176,2178,2181,2183],{"class":39,"line":846},[37,2174,2175],{"class":47},"                this",[37,2177,1975],{"class":57},[37,2179,2180],{"class":43},"-=",[37,2182,194],{"class":47},[37,2184,2185],{"class":57},".decayPerSample;\n",[37,2187,2188,2190,2192],{"class":39,"line":860},[37,2189,626],{"class":57},[37,2191,629],{"class":43},[37,2193,89],{"class":57},[37,2195,2196,2198,2200,2202,2204],{"class":39,"line":866},[37,2197,2175],{"class":47},[37,2199,1975],{"class":57},[37,2201,275],{"class":43},[37,2203,385],{"class":47},[37,2205,58],{"class":57},[37,2207,2208],{"class":39,"line":872},[37,2209,656],{"class":57},[37,2211,2212],{"class":39,"line":878},[37,2213,662],{"class":57},[37,2215,2216,2218],{"class":39,"line":883},[37,2217,1253],{"class":43},[37,2219,2220],{"class":57}," output;\n",[37,2222,2223],{"class":39,"line":894},[37,2224,400],{"class":57},[37,2226,2227],{"class":39,"line":908},[37,2228,119],{"class":57},[19,2230,2232,2233,2235],{"id":2231},"a-polyphony-manager-that-multiplies-the-karplus-voice-in-order-to-produce-polyphony-it-could-be-used-for-anyhting-that-extends-the-voice-prototype","A polyphony manager, that multiplies the karplus voice in order to produce polyphony. It could be used for anyhting that extends the ",[34,2234,436],{}," prototype.",[27,2237,2239],{"className":29,"code":2238,"language":31,"meta":32,"style":32},"\nclass PolyManager {\n    maxVoices = 32;\n    \u002F** @type {Array\u003CVoice>} *\u002F\n    list = [];\n    lastStolenVoice = 0;\n    \u002F** @type {ObjectConstructor} VoiceConstructor *\u002F\n    constructor(VoiceConstructor) {\n        this.getVoice = () => {\n            let found = null;\n            this.list.forEach(voice => {\n                if (!voice.isBusy) {\n                    found = voice;\n                }\n            });\n            if (!found) {\n                if (this.list.length > this.maxVoices) {\n                    found = this.list[this.lastStolenVoice];\n                    this.lastStolenVoice += 1;\n                    this.lastStolenVoice %= this.maxVoices;\n                } else {\n                    found = new VoiceConstructor();\n                    this.list.push(found);\n                }\n            }\n            return found;\n        }\n    }\n}\n",[34,2240,2241,2245,2254,2266,2277,2286,2297,2309,2320,2337,2350,2370,2383,2393,2397,2402,2413,2433,2449,2463,2477,2486,2499,2510,2514,2518,2525,2529,2533],{"__ignoreMap":32},[37,2242,2243],{"class":39,"line":40},[37,2244,76],{"emptyLinePlaceholder":75},[37,2246,2247,2249,2252],{"class":39,"line":79},[37,2248,82],{"class":43},[37,2250,2251],{"class":85}," PolyManager",[37,2253,89],{"class":57},[37,2255,2256,2259,2261,2264],{"class":39,"line":92},[37,2257,2258],{"class":103},"    maxVoices",[37,2260,51],{"class":43},[37,2262,2263],{"class":47}," 32",[37,2265,58],{"class":57},[37,2267,2268,2270,2272,2275],{"class":39,"line":116},[37,2269,966],{"class":491},[37,2271,969],{"class":43},[37,2273,2274],{"class":85}," {Array\u003CVoice>}",[37,2276,1042],{"class":491},[37,2278,2279,2282,2284],{"class":39,"line":122},[37,2280,2281],{"class":103},"    list",[37,2283,51],{"class":43},[37,2285,504],{"class":57},[37,2287,2288,2291,2293,2295],{"class":39,"line":127},[37,2289,2290],{"class":103},"    lastStolenVoice",[37,2292,51],{"class":43},[37,2294,385],{"class":47},[37,2296,58],{"class":57},[37,2298,2299,2301,2303,2306],{"class":39,"line":132},[37,2300,966],{"class":491},[37,2302,969],{"class":43},[37,2304,2305],{"class":85}," {ObjectConstructor}",[37,2307,2308],{"class":491}," VoiceConstructor *\u002F\n",[37,2310,2311,2313,2315,2318],{"class":39,"line":142},[37,2312,466],{"class":43},[37,2314,148],{"class":57},[37,2316,2317],{"class":103},"VoiceConstructor",[37,2319,253],{"class":57},[37,2321,2322,2324,2326,2329,2331,2333,2335],{"class":39,"line":157},[37,2323,509],{"class":47},[37,2325,197],{"class":57},[37,2327,2328],{"class":85},"getVoice",[37,2330,51],{"class":43},[37,2332,746],{"class":57},[37,2334,110],{"class":43},[37,2336,89],{"class":57},[37,2338,2339,2341,2344,2346,2348],{"class":39,"line":178},[37,2340,2099],{"class":43},[37,2342,2343],{"class":57}," found ",[37,2345,275],{"class":43},[37,2347,1053],{"class":47},[37,2349,58],{"class":57},[37,2351,2352,2354,2357,2360,2362,2365,2368],{"class":39,"line":206},[37,2353,897],{"class":47},[37,2355,2356],{"class":57},".list.",[37,2358,2359],{"class":85},"forEach",[37,2361,148],{"class":57},[37,2363,2364],{"class":103},"voice",[37,2366,2367],{"class":43}," =>",[37,2369,89],{"class":57},[37,2371,2372,2375,2377,2380],{"class":39,"line":219},[37,2373,2374],{"class":43},"                if",[37,2376,100],{"class":57},[37,2378,2379],{"class":43},"!",[37,2381,2382],{"class":57},"voice.isBusy) {\n",[37,2384,2385,2388,2390],{"class":39,"line":593},[37,2386,2387],{"class":57},"                    found ",[37,2389,275],{"class":43},[37,2391,2392],{"class":57}," voice;\n",[37,2394,2395],{"class":39,"line":603},[37,2396,606],{"class":57},[37,2398,2399],{"class":39,"line":609},[37,2400,2401],{"class":57},"            });\n",[37,2403,2404,2406,2408,2410],{"class":39,"line":623},[37,2405,549],{"class":43},[37,2407,100],{"class":57},[37,2409,2379],{"class":43},[37,2411,2412],{"class":57},"found) {\n",[37,2414,2415,2417,2419,2421,2423,2425,2428,2430],{"class":39,"line":634},[37,2416,2374],{"class":43},[37,2418,100],{"class":57},[37,2420,1089],{"class":47},[37,2422,2356],{"class":57},[37,2424,471],{"class":47},[37,2426,2427],{"class":43}," >",[37,2429,194],{"class":47},[37,2431,2432],{"class":57},".maxVoices) {\n",[37,2434,2435,2437,2439,2441,2444,2446],{"class":39,"line":653},[37,2436,2387],{"class":57},[37,2438,275],{"class":43},[37,2440,194],{"class":47},[37,2442,2443],{"class":57},".list[",[37,2445,1089],{"class":47},[37,2447,2448],{"class":57},".lastStolenVoice];\n",[37,2450,2451,2454,2457,2459,2461],{"class":39,"line":659},[37,2452,2453],{"class":47},"                    this",[37,2455,2456],{"class":57},".lastStolenVoice ",[37,2458,281],{"class":43},[37,2460,322],{"class":47},[37,2462,58],{"class":57},[37,2464,2465,2467,2469,2472,2474],{"class":39,"line":665},[37,2466,2453],{"class":47},[37,2468,2456],{"class":57},[37,2470,2471],{"class":43},"%=",[37,2473,194],{"class":47},[37,2475,2476],{"class":57},".maxVoices;\n",[37,2478,2479,2482,2484],{"class":39,"line":688},[37,2480,2481],{"class":57},"                } ",[37,2483,629],{"class":43},[37,2485,89],{"class":57},[37,2487,2488,2490,2492,2494,2497],{"class":39,"line":699},[37,2489,2387],{"class":57},[37,2491,275],{"class":43},[37,2493,986],{"class":43},[37,2495,2496],{"class":85}," VoiceConstructor",[37,2498,1153],{"class":57},[37,2500,2501,2503,2505,2507],{"class":39,"line":720},[37,2502,2453],{"class":47},[37,2504,2356],{"class":57},[37,2506,672],{"class":85},[37,2508,2509],{"class":57},"(found);\n",[37,2511,2512],{"class":39,"line":729},[37,2513,606],{"class":57},[37,2515,2516],{"class":39,"line":734},[37,2517,656],{"class":57},[37,2519,2520,2522],{"class":39,"line":753},[37,2521,723],{"class":43},[37,2523,2524],{"class":57}," found;\n",[37,2526,2527],{"class":39,"line":772},[37,2528,662],{"class":57},[37,2530,2531],{"class":39,"line":780},[37,2532,400],{"class":57},[37,2534,2535],{"class":39,"line":785},[37,2536,119],{"class":57},[19,2538,2540],{"id":2539},"the-worklet","The worklet",[15,2542,2543],{},"This one does not much more than to present the synth to the worklet invoker.\nI implemented a very basic note-to frequency converter. For me it's a placeholder, because I'd like to experiment with tuning systems on this synth.",[27,2545,2547],{"className":29,"code":2546,"language":31,"meta":32,"style":32},"\nclass RustWorklet extends AudioWorkletProcessor {\n    constructor() {\n        super();\n\n        this.samples = [];\n        this.totalSamples = 0;\n\n        this.port.onmessage = ({ data }) => {\n            \u002F\u002F console.log(data);\n\n            const freq = data.frequency?data.frequency:55 * Math.pow(2, data.note \u002F 12);\n            const tVoice = this.policarpo.getVoice();\n            tVoice.trig({ freq, amp: 1 });\n        };\n    }\n\n    policarpo = new PolyManager(KarplusVoice);\n\n    process(inputs, outputs, parameters) {\n        const output = outputs[0];\n        const blockSize = outputs[0][0].length;\n        const mix = new Float32Array(blockSize);\n        this.policarpo.list.forEach((voice) => {\n            const voiceResults = voice.getBlock(blockSize);\n            for (let sampleN = 0; sampleN \u003C blockSize; sampleN++) {\n                mix[sampleN] += voiceResults[sampleN] \u002F 10;\n            }\n        });\n\n        output.forEach(\n            \u002F**\n             * @param {Float32Array} channel\n             * @param {number} channelN\n             *\u002F\n            (channel, channelN) => {\n                channel.set(mix)\n            }\n        )\n        return true\n    }\n}\n\nregisterProcessor(\"magic-worklet-2\", RustWorklet);\n\n",[34,2548,2549,2553,2567,2573,2579,2583,2594,2607,2611,2636,2641,2645,2692,2710,2726,2731,2735,2739,2753,2757,2779,2794,2818,2833,2853,2870,2898,2915,2919,2923,2927,2937,2942,2955,2966,2971,2990,3001,3005,3010,3017,3021,3025,3029],{"__ignoreMap":32},[37,2550,2551],{"class":39,"line":40},[37,2552,76],{"emptyLinePlaceholder":75},[37,2554,2555,2557,2560,2562,2565],{"class":39,"line":79},[37,2556,82],{"class":43},[37,2558,2559],{"class":85}," RustWorklet",[37,2561,956],{"class":43},[37,2563,2564],{"class":85}," AudioWorkletProcessor",[37,2566,89],{"class":57},[37,2568,2569,2571],{"class":39,"line":92},[37,2570,466],{"class":43},[37,2572,264],{"class":57},[37,2574,2575,2577],{"class":39,"line":116},[37,2576,1489],{"class":47},[37,2578,1153],{"class":57},[37,2580,2581],{"class":39,"line":122},[37,2582,76],{"emptyLinePlaceholder":75},[37,2584,2585,2587,2590,2592],{"class":39,"line":127},[37,2586,509],{"class":47},[37,2588,2589],{"class":57},".samples ",[37,2591,275],{"class":43},[37,2593,504],{"class":57},[37,2595,2596,2598,2601,2603,2605],{"class":39,"line":132},[37,2597,509],{"class":47},[37,2599,2600],{"class":57},".totalSamples ",[37,2602,275],{"class":43},[37,2604,385],{"class":47},[37,2606,58],{"class":57},[37,2608,2609],{"class":39,"line":142},[37,2610,76],{"emptyLinePlaceholder":75},[37,2612,2613,2615,2618,2621,2623,2626,2629,2632,2634],{"class":39,"line":157},[37,2614,509],{"class":47},[37,2616,2617],{"class":57},".port.",[37,2619,2620],{"class":85},"onmessage",[37,2622,51],{"class":43},[37,2624,2625],{"class":57}," ({ ",[37,2627,2628],{"class":103},"data",[37,2630,2631],{"class":57}," }) ",[37,2633,110],{"class":43},[37,2635,89],{"class":57},[37,2637,2638],{"class":39,"line":178},[37,2639,2640],{"class":491},"            \u002F\u002F console.log(data);\n",[37,2642,2643],{"class":39,"line":206},[37,2644,76],{"emptyLinePlaceholder":75},[37,2646,2647,2650,2653,2655,2658,2661,2664,2667,2670,2673,2675,2678,2680,2682,2685,2687,2690],{"class":39,"line":219},[37,2648,2649],{"class":43},"            const",[37,2651,2652],{"class":47}," freq",[37,2654,51],{"class":43},[37,2656,2657],{"class":57}," data.frequency",[37,2659,2660],{"class":43},"?",[37,2662,2663],{"class":57},"data.frequency",[37,2665,2666],{"class":43},":",[37,2668,2669],{"class":47},"55",[37,2671,2672],{"class":43}," *",[37,2674,296],{"class":57},[37,2676,2677],{"class":85},"pow",[37,2679,148],{"class":57},[37,2681,1679],{"class":47},[37,2683,2684],{"class":57},", data.note ",[37,2686,390],{"class":43},[37,2688,2689],{"class":47}," 12",[37,2691,325],{"class":57},[37,2693,2694,2696,2699,2701,2703,2706,2708],{"class":39,"line":593},[37,2695,2649],{"class":43},[37,2697,2698],{"class":47}," tVoice",[37,2700,51],{"class":43},[37,2702,194],{"class":47},[37,2704,2705],{"class":57},".policarpo.",[37,2707,2328],{"class":85},[37,2709,1153],{"class":57},[37,2711,2712,2715,2718,2721,2723],{"class":39,"line":603},[37,2713,2714],{"class":57},"            tVoice.",[37,2716,2717],{"class":85},"trig",[37,2719,2720],{"class":57},"({ freq, amp: ",[37,2722,1657],{"class":47},[37,2724,2725],{"class":57}," });\n",[37,2727,2728],{"class":39,"line":609},[37,2729,2730],{"class":57},"        };\n",[37,2732,2733],{"class":39,"line":623},[37,2734,400],{"class":57},[37,2736,2737],{"class":39,"line":634},[37,2738,76],{"emptyLinePlaceholder":75},[37,2740,2741,2744,2746,2748,2750],{"class":39,"line":653},[37,2742,2743],{"class":103},"    policarpo",[37,2745,51],{"class":43},[37,2747,986],{"class":43},[37,2749,2251],{"class":85},[37,2751,2752],{"class":57},"(KarplusVoice);\n",[37,2754,2755],{"class":39,"line":659},[37,2756,76],{"emptyLinePlaceholder":75},[37,2758,2759,2762,2764,2767,2769,2772,2774,2777],{"class":39,"line":665},[37,2760,2761],{"class":85},"    process",[37,2763,148],{"class":57},[37,2765,2766],{"class":103},"inputs",[37,2768,169],{"class":57},[37,2770,2771],{"class":103},"outputs",[37,2773,169],{"class":57},[37,2775,2776],{"class":103},"parameters",[37,2778,253],{"class":57},[37,2780,2781,2783,2785,2787,2790,2792],{"class":39,"line":688},[37,2782,2051],{"class":43},[37,2784,2054],{"class":47},[37,2786,51],{"class":43},[37,2788,2789],{"class":57}," outputs[",[37,2791,1554],{"class":47},[37,2793,1565],{"class":57},[37,2795,2796,2798,2800,2802,2804,2806,2809,2811,2814,2816],{"class":39,"line":699},[37,2797,2051],{"class":43},[37,2799,2033],{"class":47},[37,2801,51],{"class":43},[37,2803,2789],{"class":57},[37,2805,1554],{"class":47},[37,2807,2808],{"class":57},"][",[37,2810,1554],{"class":47},[37,2812,2813],{"class":57},"].",[37,2815,471],{"class":47},[37,2817,58],{"class":57},[37,2819,2820,2822,2825,2827,2829,2831],{"class":39,"line":720},[37,2821,2051],{"class":43},[37,2823,2824],{"class":47}," mix",[37,2826,51],{"class":43},[37,2828,986],{"class":43},[37,2830,2061],{"class":85},[37,2832,2064],{"class":57},[37,2834,2835,2837,2840,2842,2845,2847,2849,2851],{"class":39,"line":729},[37,2836,509],{"class":47},[37,2838,2839],{"class":57},".policarpo.list.",[37,2841,2359],{"class":85},[37,2843,2844],{"class":57},"((",[37,2846,2364],{"class":103},[37,2848,107],{"class":57},[37,2850,110],{"class":43},[37,2852,89],{"class":57},[37,2854,2855,2857,2860,2862,2865,2868],{"class":39,"line":734},[37,2856,2649],{"class":43},[37,2858,2859],{"class":47}," voiceResults",[37,2861,51],{"class":43},[37,2863,2864],{"class":57}," voice.",[37,2866,2867],{"class":85},"getBlock",[37,2869,2064],{"class":57},[37,2871,2872,2875,2877,2879,2882,2884,2886,2889,2891,2894,2896],{"class":39,"line":753},[37,2873,2874],{"class":43},"            for",[37,2876,100],{"class":57},[37,2878,2074],{"class":43},[37,2880,2881],{"class":57}," sampleN ",[37,2883,275],{"class":43},[37,2885,385],{"class":47},[37,2887,2888],{"class":57},"; sampleN ",[37,2890,555],{"class":43},[37,2892,2893],{"class":57}," blockSize; sampleN",[37,2895,2092],{"class":43},[37,2897,253],{"class":57},[37,2899,2900,2903,2905,2908,2910,2913],{"class":39,"line":772},[37,2901,2902],{"class":57},"                mix[sampleN] ",[37,2904,281],{"class":43},[37,2906,2907],{"class":57}," voiceResults[sampleN] ",[37,2909,390],{"class":43},[37,2911,2912],{"class":47}," 10",[37,2914,58],{"class":57},[37,2916,2917],{"class":39,"line":780},[37,2918,656],{"class":57},[37,2920,2921],{"class":39,"line":785},[37,2922,1890],{"class":57},[37,2924,2925],{"class":39,"line":803},[37,2926,76],{"emptyLinePlaceholder":75},[37,2928,2929,2932,2934],{"class":39,"line":818},[37,2930,2931],{"class":57},"        output.",[37,2933,2359],{"class":85},[37,2935,2936],{"class":57},"(\n",[37,2938,2939],{"class":39,"line":823},[37,2940,2941],{"class":491},"            \u002F**\n",[37,2943,2944,2947,2949,2952],{"class":39,"line":846},[37,2945,2946],{"class":491},"             * ",[37,2948,2027],{"class":43},[37,2950,2951],{"class":85}," {Float32Array}",[37,2953,2954],{"class":57}," channel\n",[37,2956,2957,2959,2961,2963],{"class":39,"line":860},[37,2958,2946],{"class":491},[37,2960,2027],{"class":43},[37,2962,2030],{"class":85},[37,2964,2965],{"class":57}," channelN\n",[37,2967,2968],{"class":39,"line":866},[37,2969,2970],{"class":491},"             *\u002F\n",[37,2972,2973,2976,2979,2981,2984,2986,2988],{"class":39,"line":872},[37,2974,2975],{"class":57},"            (",[37,2977,2978],{"class":103},"channel",[37,2980,169],{"class":57},[37,2982,2983],{"class":103},"channelN",[37,2985,107],{"class":57},[37,2987,110],{"class":43},[37,2989,89],{"class":57},[37,2991,2992,2995,2998],{"class":39,"line":878},[37,2993,2994],{"class":57},"                channel.",[37,2996,2997],{"class":85},"set",[37,2999,3000],{"class":57},"(mix)\n",[37,3002,3003],{"class":39,"line":883},[37,3004,656],{"class":57},[37,3006,3007],{"class":39,"line":894},[37,3008,3009],{"class":57},"        )\n",[37,3011,3012,3014],{"class":39,"line":908},[37,3013,1253],{"class":43},[37,3015,3016],{"class":47}," true\n",[37,3018,3019],{"class":39,"line":913},[37,3020,400],{"class":57},[37,3022,3023],{"class":39,"line":932},[37,3024,119],{"class":57},[37,3026,3027],{"class":39,"line":937},[37,3028,76],{"emptyLinePlaceholder":75},[37,3030,3031,3034,3036,3040],{"class":39,"line":943},[37,3032,3033],{"class":85},"registerProcessor",[37,3035,148],{"class":57},[37,3037,3039],{"class":3038},"sU2Wk","\"magic-worklet-2\"",[37,3041,3042],{"class":57},", RustWorklet);\n",[10,3044,3046],{"id":3045},"code-to-use-the-worklet","Code to use the worklet",[19,3048,3050],{"id":3049},"audio-context-getter-helper-optional","Audio context getter helper (optional)",[27,3052,3054],{"className":29,"code":3053,"language":31,"meta":32,"style":32},"\n\u002F**\n * Creates an audiocontext and deals with no-autoplay policy nuisance by waiting \n * user click before starting context. \n *\u002F\nclass AudioContextGetter {\n    constructor(){\n        \u002F** @type {AudioContext|false} *\u002F\n        let audioContext=false;\n        \u002F** @returns {Promise\u003CAudioContext>} *\u002F\n        this.get = () => {\n            return new Promise((resolve)=>{\n                if(audioContext){\n                    resolve(audioContext);\n                }else{\n                    document.addEventListener(\"mousedown\",()=>{\n                        \n                        if(!audioContext){\n                            console.log(\"creating audio context (user gesture)\");\n                            audioContext = new(window.AudioContext || window.webkitAudioContext)();\n                        }\n\n                        if(audioContext) resolve(audioContext);\n                    });\n                }\n            });\n        }\n    }\n}\n\nlet audioContextGetter = new AudioContextGetter();\n",[34,3055,3056,3060,3065,3070,3075,3079,3088,3094,3106,3120,3132,3148,3170,3177,3185,3194,3214,3219,3231,3246,3263,3268,3272,3283,3288,3292,3296,3300,3304,3308,3312],{"__ignoreMap":32},[37,3057,3058],{"class":39,"line":40},[37,3059,76],{"emptyLinePlaceholder":75},[37,3061,3062],{"class":39,"line":79},[37,3063,3064],{"class":491},"\u002F**\n",[37,3066,3067],{"class":39,"line":92},[37,3068,3069],{"class":491}," * Creates an audiocontext and deals with no-autoplay policy nuisance by waiting \n",[37,3071,3072],{"class":39,"line":116},[37,3073,3074],{"class":491}," * user click before starting context. \n",[37,3076,3077],{"class":39,"line":122},[37,3078,1042],{"class":491},[37,3080,3081,3083,3086],{"class":39,"line":127},[37,3082,82],{"class":43},[37,3084,3085],{"class":85}," AudioContextGetter",[37,3087,89],{"class":57},[37,3089,3090,3092],{"class":39,"line":132},[37,3091,466],{"class":43},[37,3093,1852],{"class":57},[37,3095,3096,3099,3101,3104],{"class":39,"line":142},[37,3097,3098],{"class":491},"        \u002F** ",[37,3100,969],{"class":43},[37,3102,3103],{"class":85}," {AudioContext|false}",[37,3105,1042],{"class":491},[37,3107,3108,3110,3113,3115,3118],{"class":39,"line":157},[37,3109,478],{"class":43},[37,3111,3112],{"class":57}," audioContext",[37,3114,275],{"class":43},[37,3116,3117],{"class":47},"false",[37,3119,58],{"class":57},[37,3121,3122,3124,3127,3130],{"class":39,"line":178},[37,3123,3098],{"class":491},[37,3125,3126],{"class":43},"@returns",[37,3128,3129],{"class":85}," {Promise\u003CAudioContext>}",[37,3131,1042],{"class":491},[37,3133,3134,3136,3138,3140,3142,3144,3146],{"class":39,"line":206},[37,3135,509],{"class":47},[37,3137,197],{"class":57},[37,3139,531],{"class":85},[37,3141,51],{"class":43},[37,3143,746],{"class":57},[37,3145,110],{"class":43},[37,3147,89],{"class":57},[37,3149,3150,3152,3154,3157,3159,3162,3165,3167],{"class":39,"line":219},[37,3151,723],{"class":43},[37,3153,986],{"class":43},[37,3155,3156],{"class":47}," Promise",[37,3158,2844],{"class":57},[37,3160,3161],{"class":103},"resolve",[37,3163,3164],{"class":57},")",[37,3166,110],{"class":43},[37,3168,3169],{"class":57},"{\n",[37,3171,3172,3174],{"class":39,"line":593},[37,3173,2374],{"class":43},[37,3175,3176],{"class":57},"(audioContext){\n",[37,3178,3179,3182],{"class":39,"line":603},[37,3180,3181],{"class":85},"                    resolve",[37,3183,3184],{"class":57},"(audioContext);\n",[37,3186,3187,3190,3192],{"class":39,"line":609},[37,3188,3189],{"class":57},"                }",[37,3191,629],{"class":43},[37,3193,3169],{"class":57},[37,3195,3196,3199,3202,3204,3207,3210,3212],{"class":39,"line":623},[37,3197,3198],{"class":57},"                    document.",[37,3200,3201],{"class":85},"addEventListener",[37,3203,148],{"class":57},[37,3205,3206],{"class":3038},"\"mousedown\"",[37,3208,3209],{"class":57},",()",[37,3211,110],{"class":43},[37,3213,3169],{"class":57},[37,3215,3216],{"class":39,"line":634},[37,3217,3218],{"class":57},"                        \n",[37,3220,3221,3224,3226,3228],{"class":39,"line":653},[37,3222,3223],{"class":43},"                        if",[37,3225,148],{"class":57},[37,3227,2379],{"class":43},[37,3229,3230],{"class":57},"audioContext){\n",[37,3232,3233,3236,3239,3241,3244],{"class":39,"line":659},[37,3234,3235],{"class":57},"                            console.",[37,3237,3238],{"class":85},"log",[37,3240,148],{"class":57},[37,3242,3243],{"class":3038},"\"creating audio context (user gesture)\"",[37,3245,325],{"class":57},[37,3247,3248,3251,3253,3255,3258,3260],{"class":39,"line":665},[37,3249,3250],{"class":57},"                            audioContext ",[37,3252,275],{"class":43},[37,3254,986],{"class":43},[37,3256,3257],{"class":57},"(window.AudioContext ",[37,3259,811],{"class":43},[37,3261,3262],{"class":57}," window.webkitAudioContext)();\n",[37,3264,3265],{"class":39,"line":688},[37,3266,3267],{"class":57},"                        }\n",[37,3269,3270],{"class":39,"line":699},[37,3271,76],{"emptyLinePlaceholder":75},[37,3273,3274,3276,3279,3281],{"class":39,"line":720},[37,3275,3223],{"class":43},[37,3277,3278],{"class":57},"(audioContext) ",[37,3280,3161],{"class":85},[37,3282,3184],{"class":57},[37,3284,3285],{"class":39,"line":729},[37,3286,3287],{"class":57},"                    });\n",[37,3289,3290],{"class":39,"line":734},[37,3291,606],{"class":57},[37,3293,3294],{"class":39,"line":753},[37,3295,2401],{"class":57},[37,3297,3298],{"class":39,"line":772},[37,3299,662],{"class":57},[37,3301,3302],{"class":39,"line":780},[37,3303,400],{"class":57},[37,3305,3306],{"class":39,"line":785},[37,3307,119],{"class":57},[37,3309,3310],{"class":39,"line":803},[37,3311,76],{"emptyLinePlaceholder":75},[37,3313,3314,3316,3319,3321,3323,3325],{"class":39,"line":818},[37,3315,2074],{"class":43},[37,3317,3318],{"class":57}," audioContextGetter ",[37,3320,275],{"class":43},[37,3322,986],{"class":43},[37,3324,3085],{"class":85},[37,3326,1153],{"class":57},[19,3328,3330],{"id":3329},"worklet-loader","Worklet loader",[27,3332,3334],{"className":29,"code":3333,"language":31,"meta":32,"style":32},"\nclass Synth {\n    operation = (event) => {}\n    \n    constructor(){\n        audioContextGetter.get().then((audioContext) => {\n            console.log(\"start audio\");\n\n\n            console.log(\"loading worklet:\");\n\n            audioContext.audioWorklet.addModule('MagicEngineWorklet.js').then(() => {\n                console.log(\"worklet loaded!\");\n\n                \u002F** @type {AudioWorkletNode} *\u002F\n                let rustWorklet = new AudioWorkletNode(audioContext, 'MagicWorklet');\n\n                \u002F\u002F setInterval(() => rustWorklet.port.postMessage('yuiim'), 1000);\n                rustWorklet.port.onmessage = (e) => console.log(e.data)\n                rustWorklet.connect(audioContext.destination);\n\n                \u002F** @param {{note:number, val:number}} event *\u002F\n                this.operation = ({note,val}) => {\n                    if(event.isTrigger()){\n                        rustWorklet.port.postMessage({\n                            note,\n                            val,\n                        });\n                    }\n                    \n                }\n            });\n        });\n    }\n}\n\n",[34,3335,3336,3340,3349,3367,3372,3378,3402,3416,3420,3424,3437,3441,3466,3480,3484,3496,3518,3522,3527,3553,3564,3568,3582,3611,3625,3635,3640,3645,3650,3655,3660,3664,3668,3672,3676],{"__ignoreMap":32},[37,3337,3338],{"class":39,"line":40},[37,3339,76],{"emptyLinePlaceholder":75},[37,3341,3342,3344,3347],{"class":39,"line":79},[37,3343,82],{"class":43},[37,3345,3346],{"class":85}," Synth",[37,3348,89],{"class":57},[37,3350,3351,3353,3355,3357,3360,3362,3364],{"class":39,"line":92},[37,3352,95],{"class":85},[37,3354,51],{"class":43},[37,3356,100],{"class":57},[37,3358,3359],{"class":103},"event",[37,3361,107],{"class":57},[37,3363,110],{"class":43},[37,3365,3366],{"class":57}," {}\n",[37,3368,3369],{"class":39,"line":116},[37,3370,3371],{"class":57},"    \n",[37,3373,3374,3376],{"class":39,"line":122},[37,3375,466],{"class":43},[37,3377,1852],{"class":57},[37,3379,3380,3383,3385,3388,3391,3393,3396,3398,3400],{"class":39,"line":127},[37,3381,3382],{"class":57},"        audioContextGetter.",[37,3384,531],{"class":85},[37,3386,3387],{"class":57},"().",[37,3389,3390],{"class":85},"then",[37,3392,2844],{"class":57},[37,3394,3395],{"class":103},"audioContext",[37,3397,107],{"class":57},[37,3399,110],{"class":43},[37,3401,89],{"class":57},[37,3403,3404,3407,3409,3411,3414],{"class":39,"line":132},[37,3405,3406],{"class":57},"            console.",[37,3408,3238],{"class":85},[37,3410,148],{"class":57},[37,3412,3413],{"class":3038},"\"start audio\"",[37,3415,325],{"class":57},[37,3417,3418],{"class":39,"line":142},[37,3419,76],{"emptyLinePlaceholder":75},[37,3421,3422],{"class":39,"line":157},[37,3423,76],{"emptyLinePlaceholder":75},[37,3425,3426,3428,3430,3432,3435],{"class":39,"line":178},[37,3427,3406],{"class":57},[37,3429,3238],{"class":85},[37,3431,148],{"class":57},[37,3433,3434],{"class":3038},"\"loading worklet:\"",[37,3436,325],{"class":57},[37,3438,3439],{"class":39,"line":206},[37,3440,76],{"emptyLinePlaceholder":75},[37,3442,3443,3446,3449,3451,3454,3457,3459,3462,3464],{"class":39,"line":219},[37,3444,3445],{"class":57},"            audioContext.audioWorklet.",[37,3447,3448],{"class":85},"addModule",[37,3450,148],{"class":57},[37,3452,3453],{"class":3038},"'MagicEngineWorklet.js'",[37,3455,3456],{"class":57},").",[37,3458,3390],{"class":85},[37,3460,3461],{"class":57},"(() ",[37,3463,110],{"class":43},[37,3465,89],{"class":57},[37,3467,3468,3471,3473,3475,3478],{"class":39,"line":593},[37,3469,3470],{"class":57},"                console.",[37,3472,3238],{"class":85},[37,3474,148],{"class":57},[37,3476,3477],{"class":3038},"\"worklet loaded!\"",[37,3479,325],{"class":57},[37,3481,3482],{"class":39,"line":603},[37,3483,76],{"emptyLinePlaceholder":75},[37,3485,3486,3489,3491,3494],{"class":39,"line":609},[37,3487,3488],{"class":491},"                \u002F** ",[37,3490,969],{"class":43},[37,3492,3493],{"class":85}," {AudioWorkletNode}",[37,3495,1042],{"class":491},[37,3497,3498,3500,3503,3505,3507,3510,3513,3516],{"class":39,"line":623},[37,3499,564],{"class":43},[37,3501,3502],{"class":57}," rustWorklet ",[37,3504,275],{"class":43},[37,3506,986],{"class":43},[37,3508,3509],{"class":85}," AudioWorkletNode",[37,3511,3512],{"class":57},"(audioContext, ",[37,3514,3515],{"class":3038},"'MagicWorklet'",[37,3517,325],{"class":57},[37,3519,3520],{"class":39,"line":634},[37,3521,76],{"emptyLinePlaceholder":75},[37,3523,3524],{"class":39,"line":653},[37,3525,3526],{"class":491},"                \u002F\u002F setInterval(() => rustWorklet.port.postMessage('yuiim'), 1000);\n",[37,3528,3529,3532,3534,3536,3538,3541,3543,3545,3548,3550],{"class":39,"line":659},[37,3530,3531],{"class":57},"                rustWorklet.port.",[37,3533,2620],{"class":85},[37,3535,51],{"class":43},[37,3537,100],{"class":57},[37,3539,3540],{"class":103},"e",[37,3542,107],{"class":57},[37,3544,110],{"class":43},[37,3546,3547],{"class":57}," console.",[37,3549,3238],{"class":85},[37,3551,3552],{"class":57},"(e.data)\n",[37,3554,3555,3558,3561],{"class":39,"line":665},[37,3556,3557],{"class":57},"                rustWorklet.",[37,3559,3560],{"class":85},"connect",[37,3562,3563],{"class":57},"(audioContext.destination);\n",[37,3565,3566],{"class":39,"line":688},[37,3567,76],{"emptyLinePlaceholder":75},[37,3569,3570,3572,3574,3577,3580],{"class":39,"line":699},[37,3571,3488],{"class":491},[37,3573,2027],{"class":43},[37,3575,3576],{"class":85}," {{note:number, val:number}}",[37,3578,3579],{"class":57}," event",[37,3581,1042],{"class":491},[37,3583,3584,3586,3588,3590,3592,3595,3598,3601,3604,3607,3609],{"class":39,"line":720},[37,3585,2175],{"class":47},[37,3587,197],{"class":57},[37,3589,1203],{"class":85},[37,3591,51],{"class":43},[37,3593,3594],{"class":57}," ({",[37,3596,3597],{"class":103},"note",[37,3599,3600],{"class":57},",",[37,3602,3603],{"class":103},"val",[37,3605,3606],{"class":57},"}) ",[37,3608,110],{"class":43},[37,3610,89],{"class":57},[37,3612,3613,3616,3619,3622],{"class":39,"line":729},[37,3614,3615],{"class":43},"                    if",[37,3617,3618],{"class":57},"(event.",[37,3620,3621],{"class":85},"isTrigger",[37,3623,3624],{"class":57},"()){\n",[37,3626,3627,3630,3633],{"class":39,"line":734},[37,3628,3629],{"class":57},"                        rustWorklet.port.",[37,3631,3632],{"class":85},"postMessage",[37,3634,1874],{"class":57},[37,3636,3637],{"class":39,"line":753},[37,3638,3639],{"class":57},"                            note,\n",[37,3641,3642],{"class":39,"line":772},[37,3643,3644],{"class":57},"                            val,\n",[37,3646,3647],{"class":39,"line":780},[37,3648,3649],{"class":57},"                        });\n",[37,3651,3652],{"class":39,"line":785},[37,3653,3654],{"class":57},"                    }\n",[37,3656,3657],{"class":39,"line":803},[37,3658,3659],{"class":57},"                    \n",[37,3661,3662],{"class":39,"line":818},[37,3663,606],{"class":57},[37,3665,3666],{"class":39,"line":823},[37,3667,2401],{"class":57},[37,3669,3670],{"class":39,"line":846},[37,3671,1890],{"class":57},[37,3673,3674],{"class":39,"line":860},[37,3675,400],{"class":57},[37,3677,3678],{"class":39,"line":866},[37,3679,119],{"class":57},[3681,3682,3683],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}",{"title":32,"searchDepth":79,"depth":79,"links":3685},[3686,3698],{"id":12,"depth":79,"text":13,"children":3687},[3688,3689,3690,3691,3692,3693,3694,3695,3697],{"id":21,"depth":92,"text":22},{"id":61,"depth":92,"text":62},{"id":224,"depth":92,"text":225},{"id":425,"depth":92,"text":426},{"id":439,"depth":92,"text":440},{"id":1269,"depth":92,"text":1270},{"id":1745,"depth":92,"text":1746},{"id":2231,"depth":92,"text":3696},"A polyphony manager, that multiplies the karplus voice in order to produce polyphony. It could be used for anyhting that extends the Voice prototype.",{"id":2539,"depth":92,"text":2540},{"id":3045,"depth":79,"text":3046,"children":3699},[3700,3701],{"id":3049,"depth":92,"text":3050},{"id":3329,"depth":92,"text":3330},[3703],"blog","2022-04-08",null,"md",{},"\u002Fposts\u002F2022-04-08-karplus-on-a-worker",{"title":5,"description":32},"posts\u002F2022-04-08-karplus-on-a-worker",[3712,3713,3714],"process-notes","tool_javascript","tool_web-audio-api",false,"ojaRSSWNJLYfCL8qLAw3B9tCVz_6fWTNN6euASgWizI",1790978019178]