From c0eed84e4d0dfec58d485b97f8ee96ea3467894a Mon Sep 17 00:00:00 2001 From: David Runge Date: Mon, 30 Mar 2015 19:33:40 +0200 Subject: SNPAudio.sc: Moving/Renaming SNPSonificator.sc to SNPAudio.sc --- SNPAudio.sc | 399 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 399 insertions(+) create mode 100644 SNPAudio.sc (limited to 'SNPAudio.sc') diff --git a/SNPAudio.sc b/SNPAudio.sc new file mode 100644 index 0000000..a86a750 --- /dev/null +++ b/SNPAudio.sc @@ -0,0 +1,399 @@ +SNPSonificator { + var <>numChannels;//number of channels to use + var snpDict;//the SNPDict to use + var <>playTime;//calculated play time of a single SNP, defined by playTime setup on init + var <>includeUnknown;//wether to include SNPs with unknown resolvers (aka. SNPS with only bases set) + var <>ignoreSNPs = #[];//Array of Symbols of chromosomes to ignore (1-22,X,Y,MT) + var compression + var recording/out + var recPath;//String representing directory to use for recording + var \base_pair".postln; + SynthDef(\base_pair, {|out=0, freq=#[0.0,0.0,0.0] ,amplitude=0.6, attackTime = 0.01, releaseTime = 0.3, curve = -4| + var env = EnvGen.kr( + Env.perc(attackTime,releaseTime,amplitude,curve),doneAction:2//free the enclosing Synth when done + ); + Out.ar( + sonBus.index+out,//speaker to play on + SinOsc.ar(//sine tone for the base pair + freq[0],0,env, + SinOsc.ar(//sine tone for the first (lower) resolver + freq[1],0,env*0.5 + )+ + SinOsc.ar(//sine tone for the second (upper) resolver + freq[2],0,env * 0.5 + ) + ) + );}, variants: (//variants for 23 first chromosomes + 1: [amplitude: 0.10, attackTime:0.01, releaseTime:0.7, curve:-4],//0.125 + 2: [amplitude: 0.10, attackTime:0.01, releaseTime:0.7, curve:-4],//0.125 + 3: [amplitude: 0.08, attackTime:0.01, releaseTime:0.6, curve:-4],//0.250 + 4: [amplitude: 0.08, attackTime:0.01, releaseTime:0.6, curve:-4],//0.250 + 5: [amplitude: 0.08, attackTime:0.01, releaseTime:0.6, curve:-4],//0.250 + 6: [amplitude: 0.08, attackTime:0.01, releaseTime:0.6, curve:-4],//0.250 + 7: [amplitude: 0.08, attackTime:0.01, releaseTime:0.6, curve:-4],//0.250 + 8: [amplitude: 0.08, attackTime:0.01, releaseTime:0.6, curve:-4],//0.250 + 9: [amplitude: 0.08, attackTime:0.01, releaseTime:0.6, curve:-4],//0.250 + 10: [amplitude: 0.06, attackTime:0.01, releaseTime:0.5, curve:-2],//0.375 + 11: [amplitude: 0.06, attackTime:0.01, releaseTime:0.5, curve:-2],//0.375 + 12: [amplitude: 0.06, attackTime:0.01, releaseTime:0.5, curve:-2],//0.375 + 13: [amplitude: 0.06, attackTime:0.01, releaseTime:0.5, curve:-2],//0.375 + 14: [amplitude: 0.06, attackTime:0.01, releaseTime:0.5, curve:-2],//0.375 + 15: [amplitude: 0.06, attackTime:0.01, releaseTime:0.5, curve:-2],//0.375 + 16: [amplitude: 0.04, attackTime:0.01, releaseTime:0.5, curve:-2],//0.500 + 17: [amplitude: 0.04, attackTime:0.01, releaseTime:0.5, curve:-2],//0.500 + 18: [amplitude: 0.04, attackTime:0.01, releaseTime:0.5, curve:-2],//0.500 + 19: [amplitude: 0.04, attackTime:0.01, releaseTime:0.5, curve:-2],//0.750 + 20: [amplitude: 0.05, attackTime:0.01, releaseTime:0.5, curve:-2],//0.625 + 21: [amplitude: 0.05, attackTime:0.01, releaseTime:0.5, curve:-2],//0.875 + 22: [amplitude: 0.05, attackTime:0.01, releaseTime:0.5, curve:-2],//0.875 + 23: [amplitude: 0.05, attackTime:0.01, releaseTime:0.5, curve:-2]//0.875 + )).add; + "Adding SynthDef for single bases -> \base_single".postln; + SynthDef(\base_single, {|out=0, freq=#[0.0,0.0] ,amplitude=0.6, attackTime = 0.01, releaseTime = 0.3, curve = -4| + var env = EnvGen.kr( + Env.perc(attackTime,releaseTime,amplitude,curve),doneAction:2//free the enclosing Synth when done + ); + Out.ar( + sonBus.index+out, + Saw.ar(//sine tone for the base + freq[0],env,SinOsc.ar(//sine tone for the resolver + freq[1],0,env*0.5 + ) + ) + );},variants: (//variants for X and Y chromosomes + 23:[amplitude: 0.07, attackTime: 0.01, releaseTime: 0.5, curve: -4],//0.250 -> X + 24:[amplitude: 0.10, attackTime: 0.01, releaseTime: 0.7, curve: -4]//0.75 ->Y + )).add; + "Adding SynthDef for MT bases -> \base_mt".postln; + SynthDef(\base_mt, {|startPosition = 0, freq = #[0.0,0.0], attackTime = 0.01, releaseTime = 1.5, amplitude = 0.4, curve = -4 | + var mtSynth, panAround; + var env = EnvGen.kr( + Env.perc(attackTime,releaseTime,amplitude,curve),doneAction:2//free the enclosing Synth when done + ); + mtSynth = Saw.ar(//sine tone for the base + freq[0],env,SinOsc.ar(//sine tone for the resolver + freq[1],0,env*0.5 + ) + ); + panAround = PanAz.ar( + numChannels,//span the whole number of channels available + mtSynth,//use the MT Synth as input + LFSaw.kr(2,0),//pan around TODO: + startPosition + 0.5,//control level + 2,//width of sound + startPosition//random starting point + ); + Out.ar(sonBus, panAround); + }).add; + } + + addCompressionSynths{ + "Adding SynthDef for compression -> \compressor".postln; + SynthDef(\compressor, {|inBus| + var in,compressed; + in = In.ar(inBus,numChannels); + compressed = Compander.ar( + in,//signal in + in,//control signal + 0.5,//threshold + 1,//slopeBelow + 0.3,//slopeAbove + 0.002,//clampTime + 0.01//relaxTime + ); + ReplaceOut.ar(0, compressed*0.1); + Out.ar(recBus, compressed*0.1); + }).add; + } + + startDSPSynths{//start compression and possibly recording Synths + ("Starting compression Synth.").postln; + Synth(\compressor, [inBus:sonBus], compressionGroup);//play compression Synth + compressionGroup.run(true);//explicitely turn on compressionGroup (needed for pause/play) + if(record,{//if recording, play recording Synth + ("Starting recording Synth for recording to file.").postln; + Synth(\recordSNP, [buffer: this.recordingBuffer], recordingGroup); + },{//FIXME: Do we have to explicitely deactivate recordingGroup when not used? + recordingGroup.run(false); + }); + } + + stopDSPSynths{//stop compression and possibly recording Synths + Routine{ + 2.wait; + if(record,{ + ("Stopping recording to file.").postln; + recordingBuffer.close; + recordingBuffer.free; + if(recordingGroup.isRunning,{ + recordingGroup.run(false); + }); + }); + 1.wait; + if(compressionGroup.isRunning,{ + ("Stopping compressor Synth.").postln; + compressionGroup.run(false); + }); + }.play; + } + + playFromTo{//start from a position (if none set, start from the beginning), play to a position (or end, if none set) + arg fromPosition = 0.0, toPosition = snpDict.positions;//start from position, play to position + var startTime=0.0;//time to first position (if not playing from the beginning, this stays the same) + this.startDSPSynths;//start Synths for compression and recording + isPlaying = true; //set play parameter + if((fromPosition == 0.0) || (snpDict.positionssnpDict.positions) || (toPosition < fromPosition) || (toPosition.isNil),{//if to position is out of bounds or smaller then from, set to total length + lastStep = snpDict.positions; + },{//else play up to that position + lastStep = toPosition; + }); + ("Starting to play positions: "++currentStep++" - "++lastStep).postln; + SystemClock.sched(startTime,{//start a SystemClock immediately or with calculated startTime to read from the SNPDict + arg time; + var resched = 0.0; + if((isPlaying) && (snpDict.positions>currentStep) && (currentStep <= lastStep),{//if playing and positions are left, play the position and reschedule SystemClock to the next SNP +// ("Playing SNP #"++currentStep++" of "++snpDict.positions++".").postln; + resched = lengthOfSNP*this.playPosition(snpDict.snpAtPosition(snpDict.snpArr[currentStep]), snpDict.snpArr[currentStep]); + currentStep = currentStep+1.0; +// ("Rescheduling in "++resched++"s for step #"++currentStep++" of "++snpDict.positions).postln; + resched; + },{//end the SystemClock and print out last position + ("Done playing. Last position: "++(currentStep-1).asString).postln; + this.stopDSPSynths; + nil; + }); + }); + } + + pausePlay{//pause the sonification + isPlaying = false; + } + + resumePlay{//resume the sonification from last position played + isPlaying = true; + ("current: "++currentStep++" - last: "++lastStep).postln; + this.playFromTo(currentStep, lastStep); + } + + playPosition{//play the SNP(s) at a position and return the distance to the next + arg posDict, position; + posDict.keysValuesDo{ + arg key, value; + if(ignoreSNPs.includes(key).not,{//ignore chromosomes if that is set up + if(includeUnknown,{//if SNPs without resolvers should be ignored, do that + this.playBase(value); + },{ + if(value.hasResolver,{ + this.playBase(value); + }); + }); + }); + }; + ^snpDict.distanceToNextPosition(position); + } + + playBase{//play the actual base/base pair + arg snp; + var baseKey = keyToFrq.at(keys[snp.vecChromosome-1]); + if(SNPInfo.isBasePair(snp.base),{//play base pairs + Synth('base_pair.'++snp.vecChromosome.asSymbol, [out: this.findSpeaker(snp.vecChromosome), freq: [baseKey.at(snp.vecBase), baseKey.at(snp.vecResolver[0]), baseKey.at(snp.vecResolver[1])]], synthGroup); + },{ + if(SNPInfo.isBase(snp.base), {//play single bases + if(snp.chromosome==\MT, {//play the MT chromosome + Synth('base_mt', [startPosition: rrand(numChannels,0), freq: [baseKey.at(snp.vecBase), baseKey.at(snp.vecResolver[0])]], synthGroup); + },{//play parts of the X and the Y chromosome + Synth('base_single.'++snp.vecChromosome.asSymbol, [out: this.findSpeaker(snp.vecChromosome), freq: [baseKey.at(snp.vecBase), baseKey.at(snp.vecResolver[0])]], synthGroup); + }); + }); + }); + //update the currently playing base of the chromosome in gui, if it has been spawned + if(gui.notNil,{ + gui.setIntermediateText(snp.vecChromosome, snp.base); + }); + baseKey.free; + } + + findSpeaker{//find the speaker for the chromosome (defined in speakerSetup) + arg chromosome; + var speaker = 0; + speakerSetup.do({ + arg item, i; + if(item.includes(chromosome),{ + speaker = i; + }); + }); + ^speaker; + } + + calcSNPTime{//calculate the clock time for a single SNP + arg playTime; + var snpTime; + snpTime = ((1/SNPInfo.lengthAtOneMs)*playTime)/1000; + ^snpTime; + } + + queryTimeAndPosition{//query current time and position + ("Positions: "++currentStep.asString++" - "++lastStep.asString++".").postln; + ("Play time: "++(currentStep*lengthOfSNP*1000).asString++"s - "++(lastStep*lengthOfSNP*1000).asString++"s.").postln; + } + + // create a new SNPGUI instance + spawnView{ + gui = SNPGUI.new(speakerSetup); + } +} -- cgit v1.2.3-54-g00ecf