Forum rss-feed

Forum

Software: Setting a custom scale upon receiving MIDI input?

Most Recent

written by: keyman

Hi Hodari,

If you are referring to using the MIDI IN and MIDI implemantation, yes its a nice feature. And with workbench you can extend this way beyond (just an example, changing sounds - AU1 to Cello or Sampler 2)

http://www.eigenlabs.com/wiki/2.0/Midi_Implementation_Chart/

written by: benjamind2008

Thu, 3 May 2012 21:18:34 +0100 BST

I'm currently using Synfire Pro. I wanted to do the following:

When clicking on a chord in the chord progression or chord palette, if you set it to just play chords Synfire will output a chord to a specified MIDI channel.

What I want to do is take this chord, analyze it to work out what the chord is, whether it's major/minor/dim/aug/sus, etc, have a list of custom scales that can be selected on the fly that have the intervals of the chord, and set the tonic to the root tonic of that chord.

Eg. Major would be 0,4,7 and Minor would be 0,3,7...etc and when the MIDI processor works out the chord it just talks to Belcanto to set the scale for that chord, and tells Belcanto to set the tonic to the root note of that chord.

This way I can select a chord in Synfire and then just jam on my Pico, and play harmonies to the chord with ease.

I think this would be very important to a budding musician like myself and I've always been very keen to work out how this can be done. I'm sure it can be done, I am just not sure how to go about it.

I think maybe a Java window, with custom code to handle the MIDI input, and to talk to Belcanto to set up the custom scale for each of the chords.

Anyone have any ideas how this can be done? I'm looking into Java coding myself, so have a fair bit of learning, but would love someone else's input.


written by: john

Thu, 3 May 2012 22:14:20 +0100 BST

That's a bit more complicated problem than you might think, on several levels. It's also interesting, so please don't let anyone (including me) put you off having a go at it. It's like the inverse of auto accompaniment and is of course pretty much what all improvisers do in their heads as they play, with varying degrees of success. Automating some of this, particularly as a learning tool, could have some very positive results.

The easy bit is getting EigenD to change the scales and tonics from another program. There is a simple way to do this - in the normal Factory setups a MIDI input is set up connected to a Talker that says the appropriate Belcanto phrases depending on the incoming note. You can read the MIDI mapping chart here. Using workbench you can edit the talker phrases associated with each note to change the selection you want. If you want more scales there is no reason you can't add them as well.

Once you have that set up then any program that you write with a MIDI in and out will enable you to play with your ideas. This is pretty much language independent and has nothing to do with EigenD. I personally wouldn't use Java, I don't like it (and we don't use it in EigenD either) but you certainly could. A better bet for speed would be C/C++ or for ease of coding (particularly for prototyping something quickly and if you are new to coding in general) I'd probably knock something up in Python, which is one of the primary languages we use in writing EigenD. If it turns out to be great, you can always rewrite it in something faster later, if you ever need to.

The rather more difficult and interesting issue is figuring out what scale and tonic you want fro an incoming chord in your external program. This might seem straightforward on a first glance, but when you think about it it's not so obvious. The first problem is that there a LOT of possible scales and modes, 80 basic ones shipped with EigenD, so you're going to get multiple hits and you'll need some kind of way of choosing which one. The second problem is that this also depends on what tonic you pick. If you assume that the chord always has the tonic at it's root then you're fine, but an awful lot of musically interesting chords don't and as soon as that's the case you have a very expanded set of possible keys you might be in. Some of the most interesting harmonic stuff comes from some of the ambiguities, many of which are quite real and audible and not just a product of theory. In writing a program like this though you'll need to really think about how to map a (potentially large) set of scale and tonic choices into what can be a very uncertain harmony. The way that great human players do this is also highly time dependent - they often have a unifying idea, theme or result they're developing and this informs their choices in real time. In a program these decisions must be made automatically, which is interesting but also quite hard.

There may well be a body of theoretical work already done in this area, it would be very worthwhile you doing a bit of paper research as well - this is the kind of thing that fascinates academics, for good reason, and it's quite possible that it's already a well understood problem with, perhaps, some well understood solutions.

And please, keep us posted here if you experiment with this stuff. There's a great developer community connected with the Eigenharps and EigenD and although they won't want to be teaching anyone to program from scratch (as there are endless online resources for that already) for anything specific to this kind of problem I'm sure they'd be very helpful.

John


written by: benjamind2008

Fri, 4 May 2012 10:29:12 +0100 BST

Hi John,
I wasn't suggesting to work out the scale. Just simply using the notes (intervals) of a chosen chord as a custom scale, so that one can play several octaves of the chord on the Pico. So if you choose C Major in SynfirePro, my app will interpret the MIDI IN, will work out that it's tonic is C and the chord is Major, and will then talk to Belcanto to make a custom scale of 0,4,7 and then tell Belcanto to set the scale to that, and then set the tonic to C.

The result of this, on a Pico, would be, from left to right, breathpipe at the left:

EGCECEGC
CEGCGCEG

Something like that.

Of course, the notes here change, depending on the chord chosen. For a C Major 7 it would be:

CEGACEGA
CEGACEGA

Which looks simpler, but the Pico key layout happens to be aligned in sets of 4, so it's symmetrical unlike the above layout with the triad.

I hope this makes more sense. I wasn't intending to select a scale for the chosen chord as Synfire already does that to a good extent, it also selects chords for a chosen scale, but Synfire can't talk directly to Belcanto, so I'd have to code an intermediary program that will accept MIDI IN and then talk to Belcanto through it's own code.

How to talk to Belcanto from another program? Not sure, please elaborate, I have no idea how that works. I'm looking into using Visual Basic Express 2010, and it should be easy as I'm used to using VB, but I could do it in C if I really had to.

It doesn't need to be fast, just to set a custom scale and set the tonic that matches the chord I choose in Synfire. It doesn't matter if it takes a second or 2 seconds to change the chord, as I'm doing this to just play ad lib anyway, but I can certainly code it to be as fast as possible, and C would be the best way to achieve speed.

Ben


written by: 0beron

Fri, 4 May 2012 10:58:56 +0100 BST

I think what john is suggesting is that if you can write a program of your own to take a MIDI chord and convert that into a single MIDI note out (doesn't matter which note, you won't hear it, you're just using it to send a message to a talker inside eigenD), then you can put this between synfire and eigenD as a translator of sorts, and means that the internals are under your control. Then inside eigenD you can setup a MIDI controlled talker to fire off the right belcanto phrases.

For example you might write a program to analyse the chord, then output a pair of midi notes, one for the tonic note and another for the type of chord. The midi talker could then set the tonic and scale appropriately.


written by: john

Fri, 4 May 2012 11:58:03 +0100 BST

Hi Ben

That is a considerably simpler idea although it's currently difficult to implement as defining scales on the fly is not possible in Belcanto. You could do it but you'd need to write an Agent, which is rather a stretch for a less experienced programmer.

Having said that, Jim has wanted to add that support into the Scaler for some time and is going to have a look at it this afternoon - it's possible it will prove straightforward. The main complexity is that Belcanto itself needs some modifiction to make it deal nicely with lists of numbers, which it currently doesn't support. We'll keep you posted if this happens.

If this gets changed then you can invoke Belcanto commands very easily from a Python program using XMLrpc's to the Stage server agent. We added support for this in the 1.3 series, there's a forum post about it here. It's not documented, but people have been using it without trouble. You could also use this to change tonic, should you wish, so you could just feed the MIDI out from Synfire into your program then make rpc calls to set up EigenD the way you want.

I'd stay away from VB, by the way, if you can. It's not what one would call a modern programming language and it's continued survival is an astonishment to many of us. For working with EigenD, Python is likely your best bet as it's well supported by the community and if you've done some C in the past you should find it very straightforward. Its an interpreted rather than compiled language so the development environment is trivial (a text editor will suffice) and the Python XMLrpc interface to EigenD has also had a lot of use and seems robust. That code snippet in the forum post should start your metronome when run just as is.


John


written by: jim

Fri, 4 May 2012 16:55:03 +0100 BST


In the upcoming 2.0.48 release, I've added the ability to set scales on-the-fly via belcanto.

You can say:


main keygroup hey scale to 0 , 2 , 4.5 , 7, 8 set


More importantly, this also works:


import xmlrpclib
s=xmlrpclib.Server('http://localhost:55553')
s.execBelcanto('synth rig scaler hey scale to 1 , 1.1 , 2 , 2.2 , 3 , 3.3 , 4 set')


You do need the spaces around the commas. I'm filing that as a bug.

Remember that in our big setups, scalers get their scales from the keygroup. If you want to set the scales in the scalers themselves, you need to set the scaler override flag.

jim


written by: benjamind2008

Sat, 5 May 2012 01:52:16 +0100 BST

Python is far too complicated for me. I just tried to work out how to include the RTMIDI-PYTHON and for some reason it just doesn't seem to understand what I want.

I think I'll stick to DevC, which works on Windows, and just use the RTMIDI and do it from there. It should be a lot easier, since I know C.


written by: benjamind2008

Sat, 5 May 2012 01:57:57 +0100 BST

Alright, I'll have to use python...but I just can't see to wrap my head around it. It's really strange. I'm a bit dumb but I'm sure it's possible.

I tried this:

python setup.py install

Guess what? No cigar! Won't install RTMIDI, and I don't even know how to get into the directory!


written by: benjamind2008

Sat, 5 May 2012 03:11:41 +0100 BST

Righto! Success!

I managed to get it working, found out I needed to install the Visual Studio 2008 for C++ to install the RTMIDI...for the vcvarsall.bat...damn that file!

I will need to learn a bit more python, as I will need to write a MIDI handler to determine the root and the chord, which is easy.

Just read the note numbers, put them in an array, and just test case the lowest of the notes that are input, which will be the root of the chord, then I'd add 1 to make it easier to work with, starting with 0 is fine, but some people like to begin at 1 not 0, so whatever works for them is fine.

test case Note number,

1,12,24,36,48,60,72,84,96,108,120 would be tonic C for example. We repeat this with the other 11 tonics, which should cover the range.

Add the notes that are input, into an array, which is up to 10 items, Notes(10) just for the heck of it. If Tonic C was 48, and the chord was Major, we'd see 48 in Notes(1), 52 in Notes(2), and 55 in Notes(3) for example.

There will be a wait state timer, so that each time a MIDI input is received it will check this timer flag, which resets every specified time and resets the array element position back to 1 (the timer is 1 second, or 500ms, or 250ms)...if the timer has been reset the array will begin filling from the first element as opposed to the next element, so there will be a window of time where a chord can be detected. When the timer is reset the chord will be recalculated and if there is a change to the chord then Belcanto will be called.

Something along these lines. It won't be an entirely trivial task, but should be fairly straightforward.


written by: benjamind2008

Sat, 5 May 2012 11:28:08 +0100 BST

Got the RTMIDI to work, but had to work some issue out, so I will get back to you when I'm able to find out how to flush the queue. So far it looks like it's a success story, but the queue is backing up with old messages each time I restart my test MIDI polling program, so it's something I may be doing wrong. Here is my python code:

-

import rtmidi_python as rtmidi
import sched, time, unittest
import math

prog_condition = True
old_time_count = 0 # main initial time counter
time_count = 0 # main time counter

message = 0

midi_port_count = 0 #define the port count integer

midi_in = None
midi_in = rtmidi.MidiIn()
for port_name in midi_in.ports:
print port_name, midi_port_count
midi_port_count = midi_port_count + 1

time.sleep(0.5)

old_time_count = time.time()

stored_time = time.time() #we set the stored time to the current time

print ("opening MIDI port")
midi_in.open_port(2) # we just use (2) for now
stored_time = time.time()

while (prog_condition == True):
time_count = time.time() - old_time_count
current_time = time.time()

message, delta_time = midi_in.get_message()
if (time_count > 10):
prog_condition = False
print ("program stops after 10 seconds")
midi_in.close_port() # close the port
midi_in = None
midi_out = None

exit
if message:
print message, delta_time
current_time = time.time()

---

The program was designed to end after 10 seconds had elapsed. This was by design, as I wanted a read-out of the MIDI messages that had occurred within those 10 seconds. Trouble is, the queue backs up and old messages get re-iterated. Not good, needs to be fixed before I can consider moving on.


written by: benjamind2008

Sat, 5 May 2012 22:02:02 +0100 BST

I decided to try out the callback function that RTMIDI has, so that it might help. Not sure. I will have to see. I had a problem with the polling feature, so the callback feature might solve the problem.


written by: Hodari

Sat, 22 Dec 2012 01:31:58 +0000 GMT

Can this "incoming note changing current scale/tonic" now be achieved easier/faster with workbench?


written by: Hodari

Sat, 22 Dec 2012 06:08:53 +0000 GMT

! i just realized you dont need to do anything fancy. all you have to do is send notes AT the eigenharp! amazing you can plan progressions and modulations. changing scales or octaves while you play! I am a very happy camper right now.


written by: keyman

Sat, 22 Dec 2012 12:13:16 +0000 GMT

Hi Hodari,

If you are referring to using the MIDI IN and MIDI implemantation, yes its a nice feature. And with workbench you can extend this way beyond (just an example, changing sounds - AU1 to Cello or Sampler 2)

http://www.eigenlabs.com/wiki/2.0/Midi_Implementation_Chart/



Please log in to join the discussions