aboutsummaryrefslogtreecommitdiffstats
path: root/SNPSonificator.sc
diff options
context:
space:
mode:
Diffstat (limited to 'SNPSonificator.sc')
-rw-r--r--SNPSonificator.sc399
1 files changed, 0 insertions, 399 deletions
diff --git a/SNPSonificator.sc b/SNPSonificator.sc
deleted file mode 100644
index a86a750..0000000
--- a/SNPSonificator.sc
+++ /dev/null
@@ -1,399 +0,0 @@
-SNPSonificator {
- var <>numChannels;//number of channels to use
- var <snpSynths;
- 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 <keys;//Array storing normalized settings for each chromosome
- var <keyToFrq;//Dictionary with normalized frequency ranges for 8 different chromosome lengths
- var <isPlaying = false;//boolean indicating the state of playing
- var <currentStep = 0.0;//storage for the position up to which sonification should take place
- var <lastStep = 0.0;//storage for the last played step (SNP position) aka. current position playing
- var <lengthOfSNP = 1.0;//distance between two SNPs in ms
- var <speakerSetup;//Array holding the chromosome numbers for each speaker
- var <synthGroup;//Group for the Synths
- var <fxGroup;//Group for effects
- var <compressionGroup;//Group for compression Synths
- var <recordingGroup;//Group for recording Synths
- var <sonBus;//Bus for Synth->compression
- var <fxBus;//Bus for chromosome based effects
- var <recBus;//Bus for compression->recording/out
- var <record =false;//boolean indicating wether to record or not (default off)
- var <>recPath;//String representing directory to use for recording
- var <recordingBuffer;//the recording buffer to use, wehen recording
- var <baseTone = #[110.00, 65.4, 98.00, 73.42];//the fundamentals from which 8 octaves will be calculated: A (A2), C (C2), G (G2), T (D2)
- var <gui; //TODO: set in constructor
-
- *new{
- arg snpDict, numChannels = 2, playTime, includeUnknown = false, ignoreSNPs, setRecord = false, recordPath;
- ^super.new.sonificatorInit(snpDict, numChannels, playTime, includeUnknown, ignoreSNPs, setRecord, recordPath);
- }
-
- sonificatorInit{
- arg snpDict, numChannels, playTime, includeUnknown, ignoreSNPs, setRecord, recordPath;
- this.snpDict = snpDict;
- this.numChannels_(numChannels);
- this.playTime = playTime;
- lengthOfSNP = this.calcSNPTime(playTime);
- this.includeUnknown = includeUnknown;
- if(ignoreSNPs.notNil && ignoreSNPs.isArray,{
- this.ignoreSNPs = ignoreSNPs;
- });
- this.initKeyRange.value;
- this.setupSpeakers(numChannels, true);
- this.setupGroups(numChannels);
- this.setupBusses(numChannels);
- this.addSNPSynths.value;
- this.addCompressionSynths;
- // TODO: add effects Synths based on chromosome areas
- if(setRecord,{//if recording should be set up
- if(recordPath.notNil && recordPath.isString,{//first check if recordingPath is set
- if(recordPath[recordPath.size-1]!="/",{//compensate for missing trailing slash
- recPath = (recordPath++"/");
- },{
- recPath = recordPath;
- });
- if(File.exists(recPath),{//if path exists, init recording to file
- recPath = recordPath;
- record = setRecord;
- this.setupRecording(numChannels);
- },{
- ("Path does not exist: "++recPath.asString).postln;
- ("Update recPath!")
- });
- },{
- ("Recording path invalid: "++recPath.asString).postln;
- });
- });
- }
-
- setupBusses{//setup the busses for compression and recording
- arg channels;
- sonBus = Bus.audio(Server.local, channels);
- recBus = Bus.audio(Server.local, channels);
- }
-
- setupGroups{//setup Groups (for Synths, compression and recording)
- arg channels;
- synthGroup = Group.new;
-// fxGroup = Group.after(synthGroup);
- compressionGroup = Group.after(synthGroup);
- recordingGroup = Group.after(compressionGroup);
- NodeWatcher.register(synthGroup);
-// NodeWatcher.register(fxGroup);
- NodeWatcher.register(compressionGroup);
- NodeWatcher.register(recordingGroup);
- }
-
- setupRecording{//create a buffer and a recording SynthDef, leaving file open for writing
- arg channels;
- ("Setting up recording to file.").postln;
- recordingBuffer = Buffer.alloc(Server.local, 262144, channels);
- recordingBuffer.write(recPath++"SNPSonification-"++(Date.seed).asString++"_("++channels.asString++"_chan).aiff".standardizePath, "aiff", "float32", 0, 0, true);
- SynthDef(\recordSNP,{
- arg buffer;
- DiskOut.ar(buffer, In.ar(recBus, channels));
- }).add;
- }
-
- setupSpeakers{//setup speakers for stereo and circular multichannel
- arg channels, printOuts = false;
- switch(channels.asInt,
- 2,{speakerSetup = [[8,16,24,6,14,22,4,12,20,2,10,18],[7,15,23,1,9,17,3,11,19,5,11,21]];},
- 4,{speakerSetup = [[3,7,11,15,19,23],[4,8,12,16,20,24],[2,6,10,14,18,22],[1,5,9,13,17,21]];},
- 6,{speakerSetup = [[5,11,17,23],[6,12,18,24],[4,10,16,22],[2,8,14,20],[1,7,13,19],[3,9,15,21]];},
- 8,{speakerSetup = [[7,15,23],[8,16,24],[6,14,22],[4,12,20],[2,10,18],[1,9,17],[3,11,19],[5,13,21]];},
- 12,{speakerSetup = [[11,23],[12,24],[10,22],[8,20],[6,18],[4,16],[2,14],[1,13],[3,15],[5,17],[7,19],[9,21]];},
- {"Invalid number of speakers set! Fix this by calling setupSpeakers(nSpeakers) on this object or this will break. Seriously!".postln;}
- );
- if(printOuts,{//print the speaker setup
- speakerSetup.do({
- arg item, i;
- ("Speaker "++(i+1).asString++" has chromosomes: ").post;
- item.do({
- arg chromosome;
- (chromosome.asString++" ("++keys[chromosome-1].asString++") ").post;
- });
- "".postln;
- });
- });
- }
-
- initKeyRange{//init 8 octave spanning frequency set, map SNPs to frequencies
- keys = round(SNPInfo.chromosomesFactor[0..SNPInfo.chromosomesFactor.size-2].normalizeSum*10, 0.125);
- keys.add(0.0);
- keyToFrq = Dictionary.new(8);
- 8.do({//setup for 8 octaves
- arg item, i;
- switch(i,
- 0, {keyToFrq.put(0.000, this.calcFrqCombination(baseTone));},
- 1, {keyToFrq.put(0.125, this.calcFrqCombination(baseTone*2.pow(i)));},
- 2, {keyToFrq.put(0.250, this.calcFrqCombination(baseTone*2.pow(i)));},
- 3, {keyToFrq.put(0.375, this.calcFrqCombination(baseTone*2.pow(i)));},
- 4, {keyToFrq.put(0.500, this.calcFrqCombination(baseTone*2.pow(i)));},
- 5, {keyToFrq.put(0.625, this.calcFrqCombination(baseTone*2.pow(i)));},
- 6, {keyToFrq.put(0.750, this.calcFrqCombination(baseTone*2.pow(i)));},
- 7, {keyToFrq.put(0.875, this.calcFrqCombination(baseTone*2.pow(i)));}
- );
- });
- }
-
- calcFrqCombination{//calculate tones for bases and their combinations for a given set of notes from the same octave
- arg baseTones;
- ^Dictionary.newFrom(List[
- SNPInfo.a, baseTones[0],
- SNPInfo.c, baseTones[1],
- SNPInfo.g, baseTones[2],
- SNPInfo.t, baseTones[3],
- SNPInfo.a-SNPInfo.c, (baseTones[0]+baseTones[1])/2,
- SNPInfo.a-SNPInfo.g, (baseTones[0]+baseTones[2])/2,
- SNPInfo.a-SNPInfo.t, (baseTones[0]+baseTones[3])/2,
- SNPInfo.c-SNPInfo.g, (baseTones[1]+baseTones[2])/2,
- SNPInfo.c-SNPInfo.t, (baseTones[1]+baseTones[3])/2,
- SNPInfo.g-SNPInfo.t, (baseTones[2]+baseTones[3])/2]
- );
- }
-
- addSNPSynths{//Synthdefs for base pairs, single bases and the MT SNPs
- "Adding SynthDef for base pairs -> \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.positions<fromPosition),{//if playing from start (or out of bounds), calculate start time for the first SNP
- startTime = lengthOfSNP*snpDict.distanceToNextPosition(fromPosition.asFloat);
- currentStep = fromPosition;//set start position
- },{//else start at once
- currentStep = fromPosition;
- });
- if((toPosition>snpDict.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);
- }
-}