[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[sc-dev] SF.net SVN: quarks:[2678] JITLibExtensions
- To: sc-dev@xxxxxxxxxxxxxxxx
- Subject: [sc-dev] SF.net SVN: quarks:[2678] JITLibExtensions
- From: decampo@xxxxxxxxxxxxxxxxxxxxx
- Date: Sat, 28 Dec 2013 22:05:02 +0000
- Dkim-signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:Content-Type:Subject:To:From:MIME-Version:Date; bh=znrLLJMrmCavaw/yhe/H+WJYoNneAzqTBv161M43cEs=; b=Y6ZZhqHefohURjDNERpT1kaYlU2AYV4kVFiL3RSM5Bcp0LYIuoaeAAWpmf3KuLEswNXZu4YxgIZpK9RaZ9R/ux+53RaqKIyV94paKxf6AO3CGrrWAJi6Zh/cMo+OPfcWaLsGN1HVobgo719QLWV6zq9GvwP4qDIqzE58g0gDccM=;
- Dkim-signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x; h=Content-Transfer-Encoding:Content-Type:Subject:To:From:MIME-Version:Date; bh=znrLLJMrmCavaw/yhe/H+WJYoNneAzqTBv161M43cEs=; b=XZQEgk5mg3jf67CWut3OB20gRSJ9qqAPJtIWuqSRxRFWLdgMICf+ADgmf0rZ/9PSSadDzBkzxYa30w7uea7UDaQf7XBG3XUgcpev61qiBdSN7y853rKL8egfOiCL7LjUaN3qN5bsHReKGr/6neA+yiFDX7NdHgpSqzPfYRiG4t8=;
- List-id: SuperCollider developers mailing list <sc-devel.create.ucsb.edu>
- Reply-to: sc-dev@xxxxxxxxxxxxxxxx
- Sender: owner-sc-dev@xxxxxxxxxxxxxxxx
Revision: 2678
http://sourceforge.net/p/quarks/code/2678
Author: decampo
Date: 2013-12-28 22:05:02 +0000 (Sat, 28 Dec 2013)
Log Message:
-----------
added NPVoicer2 with voice stealing + help file.
Modified Paths:
--------------
JITLibExtensions/classes/NPVoicer.sc
Added Paths:
-----------
JITLibExtensions/HelpSource/Classes/NPVoicer2.schelp
JITLibExtensions/classes/NPVoicer2.sc
Added: JITLibExtensions/HelpSource/Classes/NPVoicer2.schelp
===================================================================
--- JITLibExtensions/HelpSource/Classes/NPVoicer2.schelp (rev 0)
+++ JITLibExtensions/HelpSource/Classes/NPVoicer2.schelp 2013-12-28 22:05:02 UTC (rev 2678)
@@ -0,0 +1,108 @@
+TITLE:: NPVoicer2
+summary:: a voicer with stealing
+categories:: Libraries/JITLib
+related:: Classes/NPVoicer, Classes/Ndef
+
+DESCRIPTION::
+A voicer that can limit the maximum number of playing voices.
+Also, it can handle voices with fixed-duration synths reasonably well.
+
+Mainly code examples and tests for now:
+
+code::
+
+s.boot; s.latency = nil;
+
+ // make an NPVoicer with an Ndef in it
+ // prime it to play the \default synthdef
+(
+g = NPVoicer2(Ndef(\piano));
+g.prime(\default);
+g.hasGate;
+g.play;
+)
+ // play 4 notes in it, and post voiceHistory
+(
+g.maxVoices = 4;
+g.put(36, [\freq, 36.midicps, \amp, 0.2]); g.postHist;
+g.put(46, [\freq, 46.midicps, \amp, 0.15]); g.postHist;
+g.put(55, [\freq, 55.midicps, \amp, 0.12]); g.postHist;
+g.put(63, [\freq, 63.midicps]); g.postHist;
+)
+ // try releasing a note
+g.release(46); g.postHist;
+g.releaseAll; g.postHist;
+
+ // repeat notes individually
+ // - the previous instance of that note goes away
+g.put(46, [\freq, 46.midicps, \amp, 0.15]);g.postHist;
+g.put(55, [\freq, 55.midicps, \amp, 0.12]);g.postHist;
+g.put(36, [\freq, 36.midicps, \amp, 0.2]);g.postHist;
+g.put(63, [\freq, 63.midicps]);g.postHist;
+
+ // try the steal modes:
+g.stealMode = \oldest; g.checkLimit; g.postHist;
+g.put(74, [\freq, 74.midicps, \amp, 0.1]);g.postHist;
+
+g.stealMode = \lowest; g.checkLimit; g.postHist;
+g.put(38, [\freq, 38.midicps, \amp, 0.1]);g.postHist;
+
+g.stealMode = \softest; g.checkLimit; g.postHist;
+g.put(84, [\freq, 84.midicps, \amp, 0.05]);g.postHist;
+
+
+ // test self-ending voices with fixed durations:
+ // the NPVoicer2 tries to find out when the note will end,
+ // and removes it from the list and the proxy.
+(
+SynthDef(\prring, { |out, freq = (60.midicps), amp = 0.1, pan, sustain = 1.234|
+ Out.ar(out,
+ Pan2.ar(
+ Formant.ar(freq, freq * 2, freq * 5),
+ pan,
+ XLine.kr(amp, amp * 0.001, sustain)
+ )
+ );
+}).add;
+)
+
+g.prime(\prring);
+g.hasGate;
+
+g.put(64, [\freq, 64.midicps]);g.postHist;
+g.put(64, [\freq, 64.midicps, \sustain, 10]);g.postHist;
+fork { 10.do { |i| 1.wait; (" " + i + ": ").post; g.postHist; } };
+::
+
+
+CLASSMETHODS::
+
+
+INSTANCEMETHODS::
+
+METHOD:: maxVoices
+get and set the maximum number of voices
+
+METHOD:: limitVoices
+get and set flag whether to limit maximum number of voices
+
+METHOD:: stealMode
+get and set mode of voice stealing. Can be \oldest, \lowest, \softest.
+
+METHOD:: defParamValues
+the default parameter values of the current synthdef.
+
+METHOD:: voiceHistory
+the current history of sounding voices
+
+METHOD:: postHist
+prettypost the current history of sounding voices
+
+METHOD:: prime, put, release, releaseAll
+see NPVoicer
+
+private:: cmdPeriod, trackVoice, checkLimit, removeVoiceAt, findSoftestIndex
+
+EXAMPLES::
+
+To do ...
Modified: JITLibExtensions/classes/NPVoicer.sc
===================================================================
--- JITLibExtensions/classes/NPVoicer.sc 2013-12-28 22:02:18 UTC (rev 2677)
+++ JITLibExtensions/classes/NPVoicer.sc 2013-12-28 22:05:02 UTC (rev 2678)
@@ -2,6 +2,7 @@
NPVoicer {
var <proxy, <indivParams, <synCtl, <usesSpawn = false;
+ var <synthDesc, <hasGate;
*new { | proxy, indivParams |
^super.newCopyArgs(proxy, indivParams ? []);
@@ -13,6 +14,9 @@
usesSpawn = useSpawn ? usesSpawn;
proxy.awake_(usesSpawn.not);
if (usesSpawn.not) { proxy.put(0, nil) };
+ synthDesc = SynthDescLib.global[synCtl.source];
+ // know whether sounds will end by themselves
+ hasGate = synthDesc.hasGate;
}
put { | key, args |
@@ -35,7 +39,6 @@
playingKeys { ^proxy.objects.indices }
// the most basic messages for the proxy
- // don't play the source, just the monitor
play { | out, numChannels, group, multi=false, vol, fadeTime, addAction |
proxy.play(out, numChannels, group, multi, vol, fadeTime, addAction)
}
@@ -52,16 +55,38 @@
resume { proxy.resume }
+ filterIndivPairs { |argList|
+ if (indivParams.size > 0) {
+ argList = argList.clump(2).select { |pair|
+ indivParams.every(_ != pair[0]);
+ }.flatten(1);
+ };
+ ^argList
+ }
+
// set global params: key, val, key, val, ...
- set { |...args| proxy.set(*args); }
- unset { |...keys| proxy.unset(*keys); }
+ set { |...args|
+ args = this.filterIndivPairs(args);
+ proxy.set(*args);
+ }
- map { |...args| proxy.map(*args); }
- unmap { |...keys| proxy.map(*keys); }
+ unset { |...keys|
+ keys = keys.removeAll(indivParams);
+ proxy.unset(*keys);
+ }
- // set params individually per node
+ map { |...args|
+ args = this.filterIndivPairs(args);
+ proxy.map(*args);
+ }
+
+ unmap { |...keys|
+ keys = keys.removeAll(indivParams);
+ proxy.map(*keys);
+ }
+
+ // set params individually per node
setAt { |key ... args| proxy.setAt(key, *args); }
unsetAt { |key ... keys| proxy.setAt(key, *keys); }
-}
-
+}
\ No newline at end of file
Added: JITLibExtensions/classes/NPVoicer2.sc
===================================================================
--- JITLibExtensions/classes/NPVoicer2.sc (rev 0)
+++ JITLibExtensions/classes/NPVoicer2.sc 2013-12-28 22:05:02 UTC (rev 2678)
@@ -0,0 +1,105 @@
+
+NPVoicer2 : NPVoicer {
+ var <>limitVoices = true, <>maxVoices = 16, <voiceHistory, <>stealMode = \oldest;
+ var <defParamValues;
+
+ // in NPVoicer:prime, check whether synthdef hasGate or not;
+ // if not, schedule removal of by sustain
+ // if yes, release hould remove it
+
+ prime { |obj, useSpawn|
+ super.prime(obj, useSpawn);
+ defParamValues = ();
+ synthDesc.controlDict.keysValuesDo { |parName, control|
+ defParamValues.put(parName, control.defaultValue);
+ };
+ voiceHistory = List[];
+ }
+
+ put { |key, args|
+ super.put(key, args);
+ this.removeVoiceAt(key); // super releases earlier voice under that key
+ this.checkLimit(key, args);
+ this.trackVoice(key, args);
+ }
+
+ release {|key|
+ super.release(key);
+ this.removeVoiceAt(key);
+ }
+
+ removeVoiceAt { |key|
+ var voiceHistIndex;
+ voiceHistIndex = voiceHistory.detectIndex { |ev| ev[0] == key };
+ voiceHistIndex !? { voiceHistory.removeAt(voiceHistIndex); };
+ }
+
+ releaseAll {
+ super.releaseAll;
+ voiceHistory.clear;
+ }
+
+ cmdPeriod { voiceHistory.clear.postln; }
+
+ postHist { voiceHistory.printAll; }
+
+ trackVoice {|key, args|
+ voiceHistory.add([key, args]);
+ // why use a voicer when notes end by themselves?
+ // maybe ask proxy who is still playing every now and then
+ if (hasGate.not) {
+ // figure how to estimate time synth will live
+ var susDefault = defParamValues[\sustain];
+ var susArgIndex = args.indexOf(\sustain);
+ var susFromArg = susArgIndex !? { args[susArgIndex + 1] };
+ var soundingTime = susFromArg ? susDefault ? 1;
+ defer ({ this.release(key) }, soundingTime);
+ };
+ }
+
+ findSoftestIndex {
+ var minAmp = 1000, minIndex = nil;
+ var defAmp = defParamValues[\amp];
+
+ if (defAmp.isNil) { ^nil };
+
+ voiceHistory.do { |ev, evi|
+ var ampSymi, ampVali, ampVal = defAmp;
+ ampSymi = ev[1].indexOf(\amp);
+
+ if (ampSymi.notNil) {
+ ampVali = ampSymi + 1;
+ ampVal = ev[1][ampVali]
+ };
+ if (ampVal < minAmp) {
+ minAmp = ampVal;
+ minIndex = evi
+ };
+ };
+ "findSoftest: minAmp: %, minIndex: %\n".postf(minAmp, minIndex);
+
+ ^minIndex
+ }
+
+ checkLimit {
+ // check before adding the new voice,
+ // so it can never be killed
+ if (proxy.objects.size <= maxVoices) { ^this };
+
+ stealMode.switch(
+ \oldest, { this.release(voiceHistory[0][0]) },
+ \lowest, { this.release(proxy.objects.indices[0]) },
+ // maybe top and bottom voices will be less dispensable?
+ \middle, {
+ var keys = proxy.objects.indices;
+ var key = keys[keys.size div: 2];
+ this.release(key);
+ },
+ \softest, {
+ var index = this.findSoftestIndex ? 0;
+ this.release(voiceHistory[index][0]);
+ },
+ { this.release(voiceHistory[0][0]) }
+ );
+ }
+}
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
_______________________________________________
sc-dev mailing list
info (subscription, etc.): http://www.beast.bham.ac.uk/research/sc_mailing_lists.shtml
archive: https://listarc.bham.ac.uk/marchives/sc-dev/
search: https://listarc.bham.ac.uk/lists/sc-dev/search/