package jmslexamples.jsyn2; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import com.softsynth.jmsl.JMSL; import com.softsynth.jmsl.MusicShape; import com.softsynth.jmsl.jsyn2.JSynMusicDevice; import com.softsynth.jmsl.jsyn2.JSynUnitVoiceInstrument; import com.softsynth.jmsl.jsyn2.unitvoices.BandPassUnitSink; import com.softsynth.jmsl.jsyn2.unitvoices.FilteredSawtoothBL; import com.softsynth.jmsl.score.*; import com.softsynth.jmsl.util.*; /** * Signal Processing JMSL Score example * * Instrument on second staff processes the signal from the instrument on top staff * * Play a rich resonant drone in staff 1 * Band Pass filter in staff 2 * Notice that pitches of bandpass "melody" are fractional, and are mapped onto the frequency of the filter * * @author Nick Didkovsky, nick@didkovsky.com * Upgrade to JSyn2 Dec 2016 * * */ public class SignalProcessingScore2 { Score score; ScoreFrame scoreFrame; JSynUnitVoiceInstrument dryIns; JSynUnitVoiceInstrument signalProcessingIns; public void build() { JSynMusicDevice.instance().open(); buildInstruments(); initScore(); buildOrchestra(); buildScore(); } private void buildInstruments() { dryIns = new JSynUnitVoiceInstrument(8, FilteredSawtoothBL.class.getName()); dryIns.setName("Drone Cluster"); // BandPassSynthNote maps frequency input port to filter frequency, so a "melody" contour will reflect the filter's frequency contour signalProcessingIns = new JSynUnitVoiceInstrument(8, BandPassUnitSink.class.getName()); signalProcessingIns.setName("BandPass Filter"); } private void buildOrchestra() { Orchestra orch = new Orchestra(); orch.addInstrument(dryIns); orch.addInstrument(signalProcessingIns); // bus signal sources to signal processor // no need to do this explicitly, orch patch below will connect source to processor // signalProcessingIns.addSignalSource(dryIns.getOutput()); // Add this patch to the orchestra's patch list. This way it will // save/load to a score xml file orch.addOrchPatch(new Patch(0, 1)); orch.patchInstruments(); score.setOrchestra(orch); } private void buildScore() { buildSignalSourceMaterial(); buildSignalProcessingMaterial(); } private void buildSignalSourceMaterial() { score.rewind(); score.setCurrentStaffNumber(0); score.getMeasure(0).getStaff(0).setClef(Clef.BASS_CLEF); double rootPitch = 30; double[] data = MusicShape.getDefaultArray(dryIns.getDimensionNameSpace()); data[0] = 4.0; // dur data[1] = rootPitch; // pitch data[2] = 0.15; // amp data[3] = 4.0; // hold // make a rich resonance drone int dimensionOfResonance = dryIns.getDimensionNameSpace().getDimension("resonance"); data[dimensionOfResonance] = 0.1; int dimensionOfCutoff = dryIns.getDimensionNameSpace().getDimension("cutoff"); data[dimensionOfCutoff] = 3000; // whole note tied to a whole note Note n = score.addNote(dryIns.getDimensionNameSpace(), data); n.setTiedOut(true); // add overtones addOvertones(rootPitch, n, true); n = score.addNote(dryIns.getDimensionNameSpace(), data); addOvertones(rootPitch, n, false); } private void addOvertones(double rootPitch, Note n, boolean tieOut) { for (int i=1; i<=6; i++) { Note interval = n.addInterval(rootPitch + HarmonicComplexity.harmComplexArr[i] ); interval.setTiedOut(tieOut); } } private void buildSignalProcessingMaterial() { score.rewind(); score.setCurrentStaffNumber(1); int numElements = 64; int dimensionOfQ = signalProcessingIns.getDimensionNameSpace().getDimension("Q"); double minQ = signalProcessingIns.getDimensionNameSpace().getLowLimit(dimensionOfQ); double maxQ = signalProcessingIns.getDimensionNameSpace().getHighLimit(dimensionOfQ); double minPitch = 48; double maxPitch = 100; LinearInterpolator linearInterp = new LinearInterpolator(0, minQ, numElements, maxQ); HalfCosineInterpolator pitchInterpolator = new HalfCosineInterpolator(0, minPitch, numElements, maxPitch); double duration = 0.125; double[] data = MusicShape.getDefaultArray(signalProcessingIns.getDimensionNameSpace()); for (int i = 0; i < numElements; i++) { data[0] = duration; data[1] = pitchInterpolator.interp(i); data[4] = linearInterp.interp(i); Note n = score.addNote(signalProcessingIns.getDimensionNameSpace(), data); if (i % 8 != 7) n.setBeamedOut(true); } } private void initScore() { score = new Score(2, 800, 600); score.addMeasure(4, 4); score.setName("Signal Processing Score Example 2: Drone with bandpass filter"); } public void showScore() { scoreFrame = new ScoreFrame(); scoreFrame.addScore(score); scoreFrame.pack(); scoreFrame.setVisible(true); scoreFrame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { JMSL.closeMusicDevices(); System.exit(0); } }); } public static void main(String[] args) { JMSL.clock.setAdvance(0.3); SignalProcessingScore2 algoScore = new SignalProcessingScore2(); algoScore.build(); algoScore.showScore(); } }