view src/samer/midi/MidiSynth.java @ 5:b67a33c44de7

Remove some crap, etc
author samer
date Fri, 05 Apr 2019 21:34:25 +0100
parents 74cc9e431818
children
line wrap: on
line source
/*
 *	Copyright (c) 2000, Samer Abdallah, King's College London.
 *	All rights reserved.
 *
 *	This software is provided AS iS and WITHOUT ANY WARRANTY;
 *	without even the implied warranty of MERCHANTABILITY or
 *	FITNESS FOR A PARTICULAR PURPOSE.
 */

package samer.midi;
import samer.core.*;
import samer.core.types.*;
import samer.core.util.*;
import samer.tools.*;
import samer.maths.*;
import java.util.*;
import java.io.*;
import javax.sound.midi.*;


/**
	A class which generates midi events from the
	values of an input vector. Each element of the vector
	corresponds to a certain midi note number. The loudness
	of a note depends on the value of the corresponding
	vector element.

	Parameters:
		trigger note on events.

		offset is added to the vector element number to get a
		midi note number.

		pedal control whether or not note off events are generated
  */

public class MidiSynth extends Viewable implements Agent, Task, Saveable
{
	VVector			in;
	Synthesizer		synthesizer=null;

	protected int			n;
	protected double		[] x;
	protected int			[] nnums;
	protected int			[] chans;
	protected MidiChannel	[] cc;

	protected VDouble		factor;
	protected VInteger	offset;
	protected VBoolean	pedal;

	public MidiSynth(VVector input)
	{
		super("midisynth");

		Shell.push(node);
		factor = new VDouble("factor",128,0);
		offset = new VInteger("offset",0,0);
		pedal  = new VBoolean("pedal",false,0);
		setAgent(this);
		addAgent(new Saver(this));
		Shell.pop();

		in = input;
		n = in.size();
		x = in.array();

		nnums = new int[n];
		chans = new int[n];
		for (int i=0; i<n; i++) { nnums[i]=i; chans[i]=0; }

		try { getAgent().execute("load", Shell.env()); open(); }
		catch (Exception ex) { ex.printStackTrace(); }
	}

	public Viewer getViewer() {
		return new BaseViewer(this) {
			{
				panel().setLayout( new StackLayout(3));
				add(factor);
				add(offset);
				add(pedal);
				add(Shell.createButtonsFor(MidiSynth.this));
			}
		};
	}

	public void open() throws Exception {
		if (synthesizer!=null) { Shell.print("already open"); return; }
		if ((synthesizer = MidiSystem.getSynthesizer()) == null) {
			throw new Exception("getSynthesizer() failed");
		}
		Shell.print("opening synthesizer");
		synthesizer.open();

		cc = synthesizer.getChannels();
		Shell.print("got synth and channel:"+synthesizer+cc);
	}

	public void close() {
		if (synthesizer != null) {
			Shell.print("closing synthesiser");
			synthesizer.close();
			synthesizer = null;
		}
	}

	public void dispose() {
		close();
		factor.dispose();
		offset.dispose();
		pedal.dispose();
		super.dispose();
	}

	public void silence() {
		for (int i=0; i<n; i++) {
			cc[chans[i]].noteOff(nnums[i]+offset.value, 0);
		}
	}

	public void starting() {}
	public void stopping() {}
	public void run()
	{
		if (synthesizer==null) return;

		for (int i=0; i<n; i++) {
			if (x[i]>0) {
				cc[chans[i]].noteOn(nnums[i]+offset.value,mapVelocity(x[i]));
			} else if (x[i]<0 && !pedal.value) {
				cc[chans[i]].noteOff(nnums[i]+offset.value, 0);
			}
		}
	}

	public void getCommands(Agent.Registry r) {
		r.add("open").add("close").add("silence").add("edit");
	}

	public void execute(String cmd, Environment env) throws Exception
	{
		if (cmd.equals("open")) open();
		else if (cmd.equals("close"))	close();
		else if (cmd.equals("silence"))	silence();
		else if (cmd.equals("edit"))
			Shell.expose( new Editor(),"MidiSynthEditor");
	}

	public void save(OutputStream s) throws Exception 	{
		ObjectOutputStream	o=new ObjectOutputStream(s);
		o.writeObject(nnums);
		o.writeObject(chans);
		o.flush();
	}

	public void load(InputStream s)  throws Exception {
		ObjectInputStream	o=new ObjectInputStream(s);
		int [] newnotes = (int [])o.readObject();
		int [] newchans = (int [])o.readObject();
		safecopy( newnotes, nnums);
		safecopy( newchans,chans);
	}

	public void read(Reader r) throws Exception { throw new Exception("unsupported"); }
	public void write(Writer w) throws Exception { throw new Exception("unsupported"); }

	private static void safecopy( int [] src, int [] dest) 	{
		int n=src.length; if (dest.length<n) n=dest.length;
		System.arraycopy( src, 0, dest, 0, n);
	}

	public int mapVelocity(double x) {
		int vel=(int)(factor.value*x);
		if (vel>127) vel=127;
		return vel;
	}

	class Editor extends BaseViewer
	{
		VInteger	i=new VInteger("input number",0,Variable.NOINIT);
		VInteger	n=new VInteger("note number",nnums[0],Variable.NOINIT);
		VInteger	c=new VInteger("channel number",chans[0],Variable.NOINIT);
		VInteger    p=new VInteger("program",0,0);
		VBoolean	l1=new VBoolean("lock note",false,Variable.NOINIT);
		VBoolean	l2=new VBoolean("lock channel",false,Variable.NOINIT);

		public Editor() {
			super(MidiSynth.this);

			i.setRange(0,nnums.length-1);
			n.setRange(0,127);
			c.setRange(0,15);
			n.setRange(0,127);
			p.setRange(0,127);
			setLayout( new StackLayout());
			add(i);	add(n); 	add(c);
			add(p);	add(l1); 	add(l2);
			i.addObserver(this);
			n.addObserver(this);
			c.addObserver(this);
			p.addObserver(this);
		}

		public void update(Observable o, Object arg)
		{
			disposeFilter(o,arg);
			if (arg==this) return; // &&&
			if (o==i) {
				if (l1.value) { nnums[i.value]=n.value; }
				else { n.value = nnums[i.value]; n.changed(this); }

				if (l2.value) { chans[i.value]=c.value; }
				else { c.value = chans[i.value]; c.changed(this); }

				p.value = cc[c.value].getProgram();
				p.changed(this);
			} else if (o==n) {
				nnums[i.value]=n.value;
			} else if (o==c) {
				chans[i.value]=c.value;
			} else if (o==p) {
				cc[c.value].programChange(p.value);
			}
		}
	}
}