annotate src/samer/midi/MidiSynth.java @ 3:15b93db27c04

Get StreamSource to compile, update args for demo
author samer
date Fri, 05 Apr 2019 17:00:18 +0100
parents 74cc9e431818
children
rev   line source
samer@0 1 /*
samer@0 2 * Copyright (c) 2000, Samer Abdallah, King's College London.
samer@0 3 * All rights reserved.
samer@0 4 *
samer@0 5 * This software is provided AS iS and WITHOUT ANY WARRANTY;
samer@0 6 * without even the implied warranty of MERCHANTABILITY or
samer@0 7 * FITNESS FOR A PARTICULAR PURPOSE.
samer@0 8 */
samer@0 9
samer@0 10 package samer.midi;
samer@0 11 import samer.core.*;
samer@0 12 import samer.core.types.*;
samer@0 13 import samer.core.util.*;
samer@0 14 import samer.tools.*;
samer@0 15 import samer.maths.*;
samer@0 16 import java.util.*;
samer@0 17 import java.io.*;
samer@0 18 import javax.sound.midi.*;
samer@0 19
samer@0 20
samer@0 21 /**
samer@0 22 A class which generates midi events from the
samer@0 23 values of an input vector. Each element of the vector
samer@0 24 corresponds to a certain midi note number. The loudness
samer@0 25 of a note depends on the value of the corresponding
samer@0 26 vector element.
samer@0 27
samer@0 28 Parameters:
samer@0 29 trigger note on events.
samer@0 30
samer@0 31 offset is added to the vector element number to get a
samer@0 32 midi note number.
samer@0 33
samer@0 34 pedal control whether or not note off events are generated
samer@0 35 */
samer@0 36
samer@0 37 public class MidiSynth extends Viewable implements Agent, Task, Saveable
samer@0 38 {
samer@2 39 VVector in;
samer@2 40 Synthesizer synthesizer=null;
samer@2 41
samer@0 42 protected int n;
samer@0 43 protected double [] x;
samer@0 44 protected int [] nnums;
samer@0 45 protected int [] chans;
samer@0 46 protected MidiChannel [] cc;
samer@0 47
samer@0 48 protected VDouble factor;
samer@0 49 protected VInteger offset;
samer@0 50 protected VBoolean pedal;
samer@0 51
samer@2 52 public MidiSynth(VVector input)
samer@0 53 {
samer@0 54 super("midisynth");
samer@0 55
samer@0 56 Shell.push(node);
samer@0 57 factor = new VDouble("factor",128,0);
samer@0 58 offset = new VInteger("offset",0,0);
samer@0 59 pedal = new VBoolean("pedal",false,0);
samer@0 60 setAgent(this);
samer@0 61 addAgent(new Saver(this));
samer@0 62 Shell.pop();
samer@0 63
samer@2 64 in = input;
samer@2 65 n = in.size();
samer@2 66 x = in.array();
samer@0 67
samer@0 68 nnums = new int[n];
samer@0 69 chans = new int[n];
samer@0 70 for (int i=0; i<n; i++) { nnums[i]=i; chans[i]=0; }
samer@0 71
samer@0 72 try { getAgent().execute("load", Shell.env()); open(); }
samer@0 73 catch (Exception ex) { ex.printStackTrace(); }
samer@0 74 }
samer@0 75
samer@0 76 public Viewer getViewer() {
samer@0 77 return new BaseViewer(this) {
samer@0 78 {
samer@0 79 panel().setLayout( new StackLayout(3));
samer@0 80 add(factor);
samer@0 81 add(offset);
samer@0 82 add(pedal);
samer@0 83 add(Shell.createButtonsFor(MidiSynth.this));
samer@0 84 }
samer@0 85 };
samer@0 86 }
samer@0 87
samer@2 88 public void open() throws Exception {
samer@2 89 if (synthesizer!=null) { Shell.print("already open"); return; }
samer@2 90 if ((synthesizer = MidiSystem.getSynthesizer()) == null) {
samer@2 91 throw new Exception("getSynthesizer() failed");
samer@2 92 }
samer@2 93 Shell.print("opening synthesizer");
samer@2 94 synthesizer.open();
samer@2 95
samer@2 96 cc = synthesizer.getChannels();
samer@2 97 Shell.print("got synth and channel:"+synthesizer+cc);
samer@2 98 }
samer@2 99
samer@2 100 public void close() {
samer@2 101 if (synthesizer != null) {
samer@2 102 Shell.print("closing synthesiser");
samer@2 103 synthesizer.close();
samer@2 104 synthesizer = null;
samer@2 105 }
samer@2 106 }
samer@2 107
samer@0 108 public void dispose() {
samer@0 109 close();
samer@0 110 factor.dispose();
samer@0 111 offset.dispose();
samer@0 112 pedal.dispose();
samer@0 113 super.dispose();
samer@0 114 }
samer@0 115
samer@0 116 public void silence() {
samer@0 117 for (int i=0; i<n; i++) {
samer@0 118 cc[chans[i]].noteOff(nnums[i]+offset.value, 0);
samer@0 119 }
samer@0 120 }
samer@0 121
samer@0 122 public void starting() {}
samer@0 123 public void stopping() {}
samer@0 124 public void run()
samer@0 125 {
samer@2 126 if (synthesizer==null) return;
samer@2 127
samer@0 128 for (int i=0; i<n; i++) {
samer@0 129 if (x[i]>0) {
samer@0 130 cc[chans[i]].noteOn(nnums[i]+offset.value,mapVelocity(x[i]));
samer@0 131 } else if (x[i]<0 && !pedal.value) {
samer@0 132 cc[chans[i]].noteOff(nnums[i]+offset.value, 0);
samer@0 133 }
samer@0 134 }
samer@0 135 }
samer@0 136
samer@0 137 public void getCommands(Agent.Registry r) {
samer@0 138 r.add("open").add("close").add("silence").add("edit");
samer@0 139 }
samer@0 140
samer@0 141 public void execute(String cmd, Environment env) throws Exception
samer@0 142 {
samer@0 143 if (cmd.equals("open")) open();
samer@0 144 else if (cmd.equals("close")) close();
samer@0 145 else if (cmd.equals("silence")) silence();
samer@0 146 else if (cmd.equals("edit"))
samer@0 147 Shell.expose( new Editor(),"MidiSynthEditor");
samer@0 148 }
samer@0 149
samer@0 150 public void save(OutputStream s) throws Exception {
samer@0 151 ObjectOutputStream o=new ObjectOutputStream(s);
samer@0 152 o.writeObject(nnums);
samer@0 153 o.writeObject(chans);
samer@0 154 o.flush();
samer@0 155 }
samer@0 156
samer@0 157 public void load(InputStream s) throws Exception {
samer@0 158 ObjectInputStream o=new ObjectInputStream(s);
samer@0 159 int [] newnotes = (int [])o.readObject();
samer@0 160 int [] newchans = (int [])o.readObject();
samer@0 161 safecopy( newnotes, nnums);
samer@0 162 safecopy( newchans,chans);
samer@0 163 }
samer@0 164
samer@0 165 public void read(Reader r) throws Exception { throw new Exception("unsupported"); }
samer@0 166 public void write(Writer w) throws Exception { throw new Exception("unsupported"); }
samer@0 167
samer@0 168 private static void safecopy( int [] src, int [] dest) {
samer@0 169 int n=src.length; if (dest.length<n) n=dest.length;
samer@0 170 System.arraycopy( src, 0, dest, 0, n);
samer@0 171 }
samer@0 172
samer@0 173 public int mapVelocity(double x) {
samer@0 174 int vel=(int)(factor.value*x);
samer@0 175 if (vel>127) vel=127;
samer@0 176 return vel;
samer@0 177 }
samer@0 178
samer@0 179 class Editor extends BaseViewer
samer@0 180 {
samer@0 181 VInteger i=new VInteger("input number",0,Variable.NOINIT);
samer@0 182 VInteger n=new VInteger("note number",nnums[0],Variable.NOINIT);
samer@0 183 VInteger c=new VInteger("channel number",chans[0],Variable.NOINIT);
samer@0 184 VInteger p=new VInteger("program",0,0);
samer@0 185 VBoolean l1=new VBoolean("lock note",false,Variable.NOINIT);
samer@0 186 VBoolean l2=new VBoolean("lock channel",false,Variable.NOINIT);
samer@0 187
samer@0 188 public Editor() {
samer@0 189 super(MidiSynth.this);
samer@0 190
samer@0 191 i.setRange(0,nnums.length-1);
samer@0 192 n.setRange(0,127);
samer@0 193 c.setRange(0,15);
samer@0 194 n.setRange(0,127);
samer@0 195 p.setRange(0,127);
samer@0 196 setLayout( new StackLayout());
samer@0 197 add(i); add(n); add(c);
samer@0 198 add(p); add(l1); add(l2);
samer@0 199 i.addObserver(this);
samer@0 200 n.addObserver(this);
samer@0 201 c.addObserver(this);
samer@0 202 p.addObserver(this);
samer@0 203 }
samer@0 204
samer@0 205 public void update(Observable o, Object arg)
samer@0 206 {
samer@0 207 disposeFilter(o,arg);
samer@0 208 if (arg==this) return; // &&&
samer@0 209 if (o==i) {
samer@0 210 if (l1.value) { nnums[i.value]=n.value; }
samer@0 211 else { n.value = nnums[i.value]; n.changed(this); }
samer@0 212
samer@0 213 if (l2.value) { chans[i.value]=c.value; }
samer@0 214 else { c.value = chans[i.value]; c.changed(this); }
samer@0 215
samer@0 216 p.value = cc[c.value].getProgram();
samer@0 217 p.changed(this);
samer@0 218 } else if (o==n) {
samer@0 219 nnums[i.value]=n.value;
samer@0 220 } else if (o==c) {
samer@0 221 chans[i.value]=c.value;
samer@0 222 } else if (o==p) {
samer@0 223 cc[c.value].programChange(p.value);
samer@0 224 }
samer@0 225 }
samer@0 226 }
samer@0 227 }