Jump to content

Custom Midio128 for driving SAMS


John_W._Couvillon
 Share

Recommended Posts

Hello Forum Members:

Question for you programmers in assembly or C:

Would it be possible to re-configure midio128 for a dedicated setup (core and DOUT with ULN Drivers)  such that  the core programming  responds to incoming noteon/off messages, produces a corresponding output on each pin of the DOUT, but applies a user configurable time out ( set in the ini file) after which it turns off the output.  In otherwords,  the output pin stays high for a adjustable time, regardless of how long it takes for the note off message to be received. Time out to be 10 seconds  to 1 minute, or so.

The custom programmed core and DOUT would be dedicated to driving SAMS magnets on the organ console which could be many more then 128. The output would be essentially a pulse which would cause the SAM to respond, but would prevent burning up the coil by prolonged activation.  If This could be done leaving the input features of the midio128 intact so much the better.  If however, the number of outputs can be increased beyond 128 by eliminating the 128 inputs, then that would be good, as it takes two outputs per SAM, so an organ with 100 SAMS would require 200 outputs.  256 outputs would be great.

Johnc

Link to comment
Share on other sites

Stryd_one,

Well my asm is non existant.  I was hoping that one of you super programmer guys would jump in. Anybody out there interested?  I know that there are several who have  commented on asm questions and issues who probably have need for this application.

As all may or may not know,  There is a solution to the SAMS issue with jOrgan, however, for older SAMS that stick, or don't always function, this application will protect the magnets from burn out by providing a pulse rather then a continuous output.  More info is available on the jOrgan Forum.

Johnc

Link to comment
Share on other sites

  • 1 month later...

I would be very interested in this SAM's driver project.  I am not a programmer.  I have used MidiBox to Midify an organ for use with Miditzer.  I would love to extend the MidiBox to drive SAM's.  As mentioned above, 200+ would be the minimum required.

Link to comment
Share on other sites

  • 1 year later...
  • 3 weeks later...
  • 1 month later...

Hey Johnh,

I have been away from the forum for some time, but am still very interested in your progress on the subject of this thread. Please email me so we can catch up.

Johnc

I think I've been away even longer. I am still interested in this project but at this point am not able to even think about it again until the New Year. I'll check back in.

Link to comment
Share on other sites

  • 1 month later...

If anyone is interested, I threw together a little java app today that will handle SAMs from jOrgan. It's not MIOS-based of course, but it should do the trick until a better solution is found. It's set up to handle 64 SAMs on channel 10 (0-based); 0-63 are the ON magnets, and 64-127 are the off magnets.

Here's an example:

Stop #1

Activated: 155 0 127

Deactivated: 155 0 0

Stop #2

Activated 155 1 127

Deactivated 155 1 0

Stop #3

etc....

When Stop #1 is Activated, the app receives 155 0 127 (note 0 on, channel 10). The app then outputs 155 0 127, waits 333ms, then outputs 155 0 0.

When Stop #1 is Deactivated, the app receives 155 0 0 (note 0 off, channel 10). The app then outputs 155 63 127, waits 333ms, then outputs 155 63 0.

If anyone ends up building this from source, you'll have to change the two device name strings to the names of your input and output devices. Also you can change the delay time to fit your SAMs. I'm using a slightly longer time, because I'm using the original electro-pneumatic combination action. Eventually I'll make a GUI for this.

SAMs.java


import	javax.sound.midi.Transmitter;

import	javax.sound.midi.Receiver;

import	javax.sound.midi.MidiUnavailableException;

import	javax.sound.midi.MidiDevice;

import	javax.sound.midi.MidiSystem;



public class SAMs {



	private static boolean		DEBUG = false;


	public static void main(String[] args)


 {

		/* The device name to listen to.*/

		String	strDeviceName = null;

		DEBUG = true;


		strDeviceName = "In From MIDI Yoke:  2";

		if (DEBUG) { /*out("MidiInDump.main(): device name: " + strDeviceName);*/ }


		if (strDeviceName == null) {

			//out("device name not specified!");

			System.exit(0);

		}


		MidiDevice.Info	info = getMidiDeviceInfo(strDeviceName);

		if (info == null) {

			//out("no device info found for name " + strDeviceName);

			System.exit(1);

		}

		MidiDevice	inputDevice = null;


		try {

			inputDevice = MidiSystem.getMidiDevice(info);

			inputDevice.open();

		} catch (MidiUnavailableException e) {

			if (DEBUG) {  }			

		}


		if (inputDevice == null) {

			//out("wasn't able to retrieve MidiDevice");

			System.exit(1);

		} 


		Receiver	r = new InReceiver();



		try {

			Transmitter	t = inputDevice.getTransmitter();

			t.setReceiver(r);

		} catch (MidiUnavailableException e) {

			if (DEBUG) { out(e); }

		}



		/*	Now, we're entering an endless loop. Otherwise,

			the program would exit and we won't have a chance

			to see any results.

		*/

		while (true) {

			try {

				Thread.sleep(1000);

			} catch (InterruptedException e) {

				if (DEBUG) { out(e); }

			}

		}

	}






	/*

	 *	This method tries to return a MidiDevice.Info whose name

	 *	matches the passed name. If no matching MidiDevice.Info is

	 *	found, null is returned.

	 */


	private static MidiDevice.Info getMidiDeviceInfo(String strDeviceName)


 {

		MidiDevice.Info[]	aInfos = MidiSystem.getMidiDeviceInfo();

		for (int i = 0; i < aInfos.length; i++)

		{

			if (aInfos[i].getName().equals(strDeviceName))

			{

				return aInfos[i];

			}

		}

		return null;

	}

}

InReceiver.java

import javax.sound.midi.MidiDevice;

import javax.sound.midi.MidiSystem;

import javax.sound.midi.InvalidMidiDataException;

import javax.sound.midi.MidiUnavailableException;

import javax.sound.midi.MidiMessage;

import javax.sound.midi.ShortMessage;

import javax.sound.midi.Receiver;


public class InReceiver implements Receiver 

{

	static Receiver rout;

	public InReceiver()

	{  

		try

		{

			MidiDevice outputDevice = null;

			String outputDev = "Out To MIDI Yoke:  1";

			MidiDevice.Info	info = getMidiDeviceInfo(outputDev);

			outputDevice = MidiSystem.getMidiDevice(info);

			outputDevice.open();

			rout = outputDevice.getReceiver();

		}

		catch (MidiUnavailableException e) 

		{

	          System.out.println(e);

		}

	}

	public void close()

	{ 


	}

	private static MidiDevice.Info getMidiDeviceInfo(String strDeviceName)


	 {

			MidiDevice.Info[]	aInfos = MidiSystem.getMidiDeviceInfo();

			for (int i = 0; i < aInfos.length; i++)

			{

				if (aInfos[i].getName().equals(strDeviceName))

				{

					return aInfos[i];

				}

			}

			return null;

		}

	public void send(MidiMessage message, long lTimeStamp)

	{

		int evnt0 = ((ShortMessage) message).getStatus();

		int evnt1 = ((ShortMessage) message).getData1();

		int evnt2 = ((ShortMessage) message).getData2();

		if (message instanceof ShortMessage) 

		{

			if(evnt0 == 155)

				new SetSAM(evnt1,evnt2,rout).start();

		} 

	}	

}

class SetSAM extends Thread

{

	int i;

	int pinnum;

	Receiver rec;

	SetSAM(int evnt1, int evnt2, Receiver r)

	{

		rec = r;

		if(evnt2>0)

		{

			pinnum=evnt1;

		}

		if(evnt2==0)

		{

			pinnum=evnt1+64;

		}

	}

	public void run()

	{

		ShortMessage on = new ShortMessage();

		ShortMessage off = new ShortMessage();

		try {

			//turn magnet on

			on.setMessage(155,pinnum,127);

			rec.send(on, -1);

		} catch (InvalidMidiDataException e1) {

			e1.printStackTrace();

		}

		try {

			sleep(333);

		} catch (InterruptedException e) {

		e.printStackTrace();

		}

		try {

			//turn magnet off

			off.setMessage(155,pinnum,0);

			rec.send(off, -1);

		} catch (InvalidMidiDataException e1) {

			e1.printStackTrace();

		}

	}

}

Link to comment
Share on other sites

  • 4 weeks later...

If anyone is interested, I threw together a little java app today that will handle SAMs from jOrgan. It's not MIOS-based of course, but it should do the trick until a better solution is found. It's set up to handle 64 SAMs on channel 10 (0-based); 0-63 are the ON magnets, and 64-127 are the off magnets.

Hi Trevor, Thanks for posting this. What type of SAMs are you using? Are you thinking of adding any code to check and make sure that the SAM acutally moved?

I see that the Classic Drawknob Controller system is now on their website: Drawknob Controller They have a PDF showing the wiring of all the different drawknobs on the market. It's worth visiting the site just to download that!

One feature of interest is this: "Calibrates power for each draw knob individually". It will be interesting to see if any information on how this is done comes to light!

Link to comment
Share on other sites

This has other applications. If you have tuned percussions, such as chimes, a xylophone or chrysoglott, you need a similar function. Untuned traps, such as drums, cymbals, etc. also need a driver like this.

Link to comment
Share on other sites

  • 3 weeks later...

johnh,

I'm using the original Wurlitzer "on and off machine". I ended up using a 200ms delay; 333ms was a bit long. I'm going to leave the code as it is for now, since jOrgan has SAM control now.

xpa,

Percussions don't need anything like this. They just need the standard note on/off from the keyboard/piston because they're only active as long as the piston or key is active.

Link to comment
Share on other sites

  • 6 months later...

Trevor,

Since your development is not mios based, what hardware is required to run the Java, a core running mios128, plus DINs and DOUTS? Can this additional core be daisy chained with encoders for keyboards, pedal, pistons, etc.

This looks good!

Johnc

If anyone is interested, I threw together a little java app today that will handle SAMs from jOrgan. It's not MIOS-based of course, but it should do the trick until a better solution is found. It's set up to handle 64 SAMs on channel 10 (0-based); 0-63 are the ON magnets, and 64-127 are the off magnets.

Here's an example:

Stop #1

Activated: 155 0 127

Deactivated: 155 0 0

Stop #2

Activated 155 1 127

Deactivated 155 1 0

Stop #3

etc....

When Stop #1 is Activated, the app receives 155 0 127 (note 0 on, channel 10). The app then outputs 155 0 127, waits 333ms, then outputs 155 0 0.

When Stop #1 is Deactivated, the app receives 155 0 0 (note 0 off, channel 10). The app then outputs 155 63 127, waits 333ms, then outputs 155 63 0.

If anyone ends up building this from source, you'll have to change the two device name strings to the names of your input and output devices. Also you can change the delay time to fit your SAMs. I'm using a slightly longer time, because I'm using the original electro-pneumatic combination action. Eventually I'll make a GUI for this.

SAMs.java


import	javax.sound.midi.Transmitter;

import	javax.sound.midi.Receiver;

import	javax.sound.midi.MidiUnavailableException;

import	javax.sound.midi.MidiDevice;

import	javax.sound.midi.MidiSystem;



public class SAMs {



	private static boolean		DEBUG = false;


	public static void main(String[] args)


 {

		/* The device name to listen to.*/

		String	strDeviceName = null;

		DEBUG = true;


		strDeviceName = "In From MIDI Yoke:  2";

		if (DEBUG) { /*out("MidiInDump.main(): device name: " + strDeviceName);*/ }


		if (strDeviceName == null) {

			//out("device name not specified!");

			System.exit(0);

		}


		MidiDevice.Info	info = getMidiDeviceInfo(strDeviceName);

		if (info == null) {

			//out("no device info found for name " + strDeviceName);

			System.exit(1);

		}

		MidiDevice	inputDevice = null;


		try {

			inputDevice = MidiSystem.getMidiDevice(info);

			inputDevice.open();

		} catch (MidiUnavailableException e) {

			if (DEBUG) {  }			

		}


		if (inputDevice == null) {

			//out("wasn't able to retrieve MidiDevice");

			System.exit(1);

		} 


		Receiver	r = new InReceiver();



		try {

			Transmitter	t = inputDevice.getTransmitter();

			t.setReceiver(r);

		} catch (MidiUnavailableException e) {

			if (DEBUG) { out(e); }

		}



		/*	Now, we're entering an endless loop. Otherwise,

			the program would exit and we won't have a chance

			to see any results.

		*/

		while (true) {

			try {

				Thread.sleep(1000);

			} catch (InterruptedException e) {

				if (DEBUG) { out(e); }

			}

		}

	}






	/*

	 *	This method tries to return a MidiDevice.Info whose name

	 *	matches the passed name. If no matching MidiDevice.Info is

	 *	found, null is returned.

	 */


	private static MidiDevice.Info getMidiDeviceInfo(String strDeviceName)


 {

		MidiDevice.Info[]	aInfos = MidiSystem.getMidiDeviceInfo();

		for (int i = 0; i < aInfos.length; i++)

		{

			if (aInfos[i].getName().equals(strDeviceName))

			{

				return aInfos[i];

			}

		}

		return null;

	}

}

InReceiver.java

import javax.sound.midi.MidiDevice;

import javax.sound.midi.MidiSystem;

import javax.sound.midi.InvalidMidiDataException;

import javax.sound.midi.MidiUnavailableException;

import javax.sound.midi.MidiMessage;

import javax.sound.midi.ShortMessage;

import javax.sound.midi.Receiver;


public class InReceiver implements Receiver 

{

	static Receiver rout;

	public InReceiver()

	{  

		try

		{

			MidiDevice outputDevice = null;

			String outputDev = "Out To MIDI Yoke:  1";

			MidiDevice.Info	info = getMidiDeviceInfo(outputDev);

			outputDevice = MidiSystem.getMidiDevice(info);

			outputDevice.open();

			rout = outputDevice.getReceiver();

		}

		catch (MidiUnavailableException e) 

		{

	          System.out.println(e);

		}

	}

	public void close()

	{ 


	}

	private static MidiDevice.Info getMidiDeviceInfo(String strDeviceName)


	 {

			MidiDevice.Info[]	aInfos = MidiSystem.getMidiDeviceInfo();

			for (int i = 0; i < aInfos.length; i++)

			{

				if (aInfos[i].getName().equals(strDeviceName))

				{

					return aInfos[i];

				}

			}

			return null;

		}

	public void send(MidiMessage message, long lTimeStamp)

	{

		int evnt0 = ((ShortMessage) message).getStatus();

		int evnt1 = ((ShortMessage) message).getData1();

		int evnt2 = ((ShortMessage) message).getData2();

		if (message instanceof ShortMessage) 

		{

			if(evnt0 == 155)

				new SetSAM(evnt1,evnt2,rout).start();

		} 

	}	

}

class SetSAM extends Thread

{

	int i;

	int pinnum;

	Receiver rec;

	SetSAM(int evnt1, int evnt2, Receiver r)

	{

		rec = r;

		if(evnt2>0)

		{

			pinnum=evnt1;

		}

		if(evnt2==0)

		{

			pinnum=evnt1+64;

		}

	}

	public void run()

	{

		ShortMessage on = new ShortMessage();

		ShortMessage off = new ShortMessage();

		try {

			//turn magnet on

			on.setMessage(155,pinnum,127);

			rec.send(on, -1);

		} catch (InvalidMidiDataException e1) {

			e1.printStackTrace();

		}

		try {

			sleep(333);

		} catch (InterruptedException e) {

		e.printStackTrace();

		}

		try {

			//turn magnet off

			off.setMessage(155,pinnum,0);

			rec.send(off, -1);

		} catch (InvalidMidiDataException e1) {

			e1.printStackTrace();

		}

	}

}

Link to comment
Share on other sites

  • 2 weeks later...

ok Trevor

Yes some stupidty showing, the Java app is for jOrgan.

Can this be added on top of jOrgan, or does it go in one of the jorgan folders?

Help me out here - how do i get from the printed text you posted to an app to load?

Thanks,

Johnc

Trevor,

Since your development is not mios based, what hardware is required to run the Java, a core running mios128, plus DINs and DOUTS? Can this additional core be daisy chained with encoders for keyboards, pedal, pistons, etc.

This looks good!

Johnc

Link to comment
Share on other sites

  • 5 months later...

Johnc,

Sorry I've been away from the forum for a while! The Java app runs completely independently from jOrgan. I just use Eclipse to run it in the background. Just create a project in your favorite IDC using the two .java files. SAMs.java is the main file. Some parts of the code will still have to be modified a bit to fit your project.

Trevor

Link to comment
Share on other sites

  • 2 weeks later...

Hello all, I too am doing a Pipe organ and needed the SAMS to be controlled via midibox and I think I have came up with exactly what the OP John_C was asking for (as well as others).

I modified the ain64_din128_dout128_v2c example application in C to flip the Dout pins off after 500ms AND I added CC81/80 functions so my SAM system would be compatible with Johnh's scheme, I believe Trevor is using that scheme as well.

Here is how it works;

Everything is on midi Channel 1

SAM Drivers (Dout's)

Pin 1 is for Stop#1 ON, Pin 65 is for Stop#1 Off, 2&66 are Stop 2, 3&67 are Stop 3, etc.

Send "Note 1 on" and pin 1 will go high for 500ms, if you send a "note 1 off" before the 500ms is up it will lower the pin early.

Notes 1-128 correspond to pins 1-128 which is pretty straight forward. 1-64 are Stop on's, 65-128 are Stop off's (Hauptwerk Scheme)

Now you can also send a Controller CC81 and data value of 1 and get the same pin 1 to go high for 500ms (Stop 1 on)

Send CC80, Data value 1 and pin 64 will go high for 500ms (Stop 1 off) Data Values of 1-64 correspond to Stops 1-64 (Johnh's Scheme)

Switch Inputs (Din's)

I pretty much did the reverse for the switches.

by toggling a Din high it will send a "Note on" (0x90/Pin#/Vel 0x7f) AND a CC81 w/pin# as the value.

When the same Din toggles back Low a "Note off" (0x90/Pin#/Vel 0x00) AND a CC80 w/pin# as the value.

Also when a Din goes low a "Note on" is sent 64 notes higher to create a SAM off

Note on's and note off's between the natural note and the note 64 higher are handled with reverse polarity.

So when Din 1 goes high a "note 1 on" is sent and a "note 65 off" is sent as well as the CC described above

Likewise when Din 1 goes low a "note 1 off" is sent and a "note 65 on" is sent.

Basically my program does both schemes of operation (note on's and CC81/80) at the same time so you can send or receive either and your SAMS will operate :) If you connect midi out to midi in on the same midibox you will see the Din's pins operate the correct Dout pins as described above.

All the fun stuff is in main.c, if you need to change the channel or enable/disable some of the functions you can do it there. I tried to comment everything well and actually my code is not very long, most of it is still original. My skills at C are not very good either so I am sure the routines can be further optimized and of course there may be bugs but I hope not ;)

Oh, Did I mention that the 8 analog inputs are still available and active, great for Swell pedals!

The File package has a HEX that is ready for midi-box upload as well as my modified main.c

I am also including JohnH's CC81/80 stop list for a reference to follow, Trevor please confirm if you are using the same list.

Hope this helps someone!

Jmayes

JM8180-Final1.zip

Link to comment
Share on other sites

  • 4 weeks later...

Forum,

If you are a user of jOrgan virtual organ software as the front end relay for midification of a physical console, using MIDIBOX cores,DINS,DOUTS as encoders and decoders, you can now interface jOrgan (ver. 3.13, beta 7)with SAMS using midio128, core, 4 DOUTS with ULN drivers and the new SAMS Extension feature in jOrgan. The attached partial schematic shows the key hardware and interconnections.

More information is available on www.jorgan.sf.net, and the jOrgan forum.

johnc

post-3665-000692200 1303944571_thumb.jpg

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

×
×
  • Create New...