Discussion:
How to send manual midi commands to fluidsynth from another program?
(too old to reply)
John O'Hagan
2008-10-12 12:50:52 UTC
Permalink
Hi,

I'm writing an algorithmic music program which generates lists of numbers
representing notes and durations. The results can be printed as scores and
played as midi files using lilypond, and to play the results as they are
generated (i.e., bar by bar), I'm using the sox synth.

That's pretty limited, however, so I thought that fluidsynth might be the way
forward.

The simplest solution would be to translate my number lists into noteon
commands, etc, and pipe them to fluidsynth.

But I need a little help understanding the fluidsynth shell.

When that is active, I can type commands in, but I cant figure out how to pipe
them from my program. I tried sending a file object to stdout but it seemed
to just disappear. Also, when I try to run fluidsynth with the -i switch, (no
shell), it seems to start up, then immediately exit.

I can get a result by translating my data into a text-to-midi program, then
piping that to, say, pmidi, which plays via fluidsynth, but that seems very
roundabout.

Any advice?

Regards,

John O'Hagan
Pedro Lopez-Cabanillas
2008-10-12 13:33:54 UTC
Permalink
Post by John O'Hagan
Hi,
I'm writing an algorithmic music program which generates lists of numbers
representing notes and durations. The results can be printed as scores and
played as midi files using lilypond, and to play the results as they are
generated (i.e., bar by bar), I'm using the sox synth.
That's pretty limited, however, so I thought that fluidsynth might be the
way forward.
The simplest solution would be to translate my number lists into noteon
commands, etc, and pipe them to fluidsynth.
But I need a little help understanding the fluidsynth shell.
When that is active, I can type commands in, but I cant figure out how to
pipe them from my program. I tried sending a file object to stdout but it
seemed to just disappear. Also, when I try to run fluidsynth with the -i
switch, (no shell), it seems to start up, then immediately exit.
I can get a result by translating my data into a text-to-midi program,
then piping that to, say, pmidi, which plays via fluidsynth, but that seems
very roundabout.
Any advice?
Use the TCP/IP shell server mode. QSynth enables it in Linux, or you can
enable it in the command line client with the argument "-s, --server". By
default, the shell port is 9800/tcp, but you can change the number with the
setting "shell.port", for instance:

$ fluidsynth -i -s -o "shell.port=9988" ...

To send commads to the shell server, use the telnet protocol:

$ telnet localhost 9988
noteon 1 66 100
noteoff 1 66
...

Using the bash shell, or a bash script:
$ echo "noteon 1 60 100" > /dev/tcp/localhost/9988
$ echo "noteoff 1 60" > /dev/tcp/localhost/9988
...

Hope this helps.

Regards,
Pedro
John O'Hagan
2008-10-13 05:31:06 UTC
Permalink
Post by Pedro Lopez-Cabanillas
Post by John O'Hagan
Hi,
I'm writing an algorithmic music program which generates lists of numbers
representing notes and durations. The results can be printed as scores
and played as midi files using lilypond, and to play the results as they
are generated (i.e., bar by bar), I'm using the sox synth.
That's pretty limited, however, so I thought that fluidsynth might be the
way forward.
The simplest solution would be to translate my number lists into noteon
commands, etc, and pipe them to fluidsynth.
But I need a little help understanding the fluidsynth shell.
[...]
Post by Pedro Lopez-Cabanillas
Use the TCP/IP shell server mode. QSynth enables it in Linux, or you can
enable it in the command line client with the argument "-s, --server". By
default, the shell port is 9800/tcp, but you can change the number with the
$ fluidsynth -i -s -o "shell.port=9988" ...
$ telnet localhost 9988
noteon 1 66 100
noteoff 1 66
Great! I'm using Python, and this is how I did it in my program (Python code
follows):

from telnetlib import Telnet
fluid = Telnet("localhost","9800")

fluid.write("noteon 1 46 64 \n noteon 1 49 64 \n noteon 1 53 64 \n")

It's as simple as that. As an added bonus, it's easy to do chords (as in the
above example) or other simultaneous messages with a single command.
Post by Pedro Lopez-Cabanillas
...
$ echo "noteon 1 60 100" > /dev/tcp/localhost/9988
$ echo "noteoff 1 60" > /dev/tcp/localhost/9988
I don't seem to have those directories in /dev, and I have to be root to
create them. Even when I do, the commands above (or their Python equivalents)
don't produce a response from Fluidsynth. Given that I don't know the telnet
protocol from a hole in the ground, my ignorance on the subject is
undoubtedly the issue here.

Anyway, I'm very happy with the above solution.
Post by Pedro Lopez-Cabanillas
Hope this helps.
Sure does!

Regards,

John
Pedro Lopez-Cabanillas
2008-10-13 18:29:57 UTC
Permalink
Post by John O'Hagan
Great! I'm using Python, and this is how I did it in my program (Python
from telnetlib import Telnet
fluid = Telnet("localhost","9800")
fluid.write("noteon 1 46 64 \n noteon 1 49 64 \n noteon 1 53 64 \n")
Note that FluidSynth doesn't follow strictly the telnet protocol, so you can
use something simpler. The command line utility netcat(1) (or 'nc') is
perfect for this purpose:

[~]$ netcat localhost 9800
noteon 1 66 100
noteoff 1 66
quit
cheers!
[~]$

What I mean is that you can use simple TCP/IP sockets and text streams,
instead of the telnet class.

#!/usr/bin/python
import sys
import time
from socket import *
serverHost = "localhost"
serverPort = 9800
s = socket(AF_INET, SOCK_STREAM)
s.connect((serverHost, serverPort))
s.send("noteon 1 66 100\n")
time.sleep(1)
s.send("noteoff 1 66\n")
s.send("quit\n")
data = s.recv(1024)
print data
Post by John O'Hagan
Post by Pedro Lopez-Cabanillas
...
$ echo "noteon 1 60 100" > /dev/tcp/localhost/9988
$ echo "noteoff 1 60" > /dev/tcp/localhost/9988
I don't seem to have those directories in /dev, and I have to be root to
create them. Even when I do, the commands above (or their Python
equivalents) don't produce a response from Fluidsynth. Given that I don't
know the telnet protocol from a hole in the ground, my ignorance on the
subject is undoubtedly the issue here.
These aren't real directories, but special Bash redirections.
http://www.gnu.org/software/bash/manual/bashref.html#Redirections

It only works in Bash, and only if this feature was enabled when Bash was
configured && compiled.

Regards,
Pedro
John O'Hagan
2008-10-14 05:27:36 UTC
Permalink
Post by Pedro Lopez-Cabanillas
Post by John O'Hagan
Great! I'm using Python, and this is how I did it in my program (Python
from telnetlib import Telnet
fluid = Telnet("localhost","9800")
fluid.write("noteon 1 46 64 \n noteon 1 49 64 \n noteon 1 53 64 \n")
Note that FluidSynth doesn't follow strictly the telnet protocol, so you
can use something simpler. The command line utility netcat(1) (or 'nc') is
[...]
Post by Pedro Lopez-Cabanillas
What I mean is that you can use simple TCP/IP sockets and text streams,
instead of the telnet class.
#!/usr/bin/python
import sys
import time
from socket import *
serverHost = "localhost"
serverPort = 9800
s = socket(AF_INET, SOCK_STREAM)
s.connect((serverHost, serverPort))
s.send("noteon 1 66 100\n")
time.sleep(1)
s.send("noteoff 1 66\n")
s.send("quit\n")
data = s.recv(1024)
print data
[...]

Thanks for the suggestion, Pablo: simpler is better, after all.

I tried the socket approach, and while it works, multiple connections break
the pipe, whereas Telnet() seems to handle this gracefully, so I put it back
in, as I want to be able to send several streams of midi messages to one
instance of fluidsynth.

Or is this possible with sockets too? If it is, I missed it.

Regards,

John
John O'Hagan
2008-10-14 05:27:36 UTC
Permalink
Post by Pedro Lopez-Cabanillas
Post by John O'Hagan
Great! I'm using Python, and this is how I did it in my program (Python
from telnetlib import Telnet
fluid = Telnet("localhost","9800")
fluid.write("noteon 1 46 64 \n noteon 1 49 64 \n noteon 1 53 64 \n")
Note that FluidSynth doesn't follow strictly the telnet protocol, so you
can use something simpler. The command line utility netcat(1) (or 'nc') is
[...]
Post by Pedro Lopez-Cabanillas
What I mean is that you can use simple TCP/IP sockets and text streams,
instead of the telnet class.
#!/usr/bin/python
import sys
import time
from socket import *
serverHost = "localhost"
serverPort = 9800
s = socket(AF_INET, SOCK_STREAM)
s.connect((serverHost, serverPort))
s.send("noteon 1 66 100\n")
time.sleep(1)
s.send("noteoff 1 66\n")
s.send("quit\n")
data = s.recv(1024)
print data
[...]

Thanks for the suggestion, Pablo: simpler is better, after all.

I tried the socket approach, and while it works, multiple connections break
the pipe, whereas Telnet() seems to handle this gracefully, so I put it back
in, as I want to be able to send several streams of midi messages to one
instance of fluidsynth.

Or is this possible with sockets too? If it is, I missed it.

Regards,

John
Josh Green
2008-10-12 23:13:28 UTC
Permalink
Hello,

As Pedro suggested, you could control FluidSynth via TCP/IP. If you
want finer grained control over FluidSynth and don't mind writing C
code, then you could use FluidSynth as a shared library. This is how
Swami and QSynth use FluidSynth.

Best regards,
Josh
Post by John O'Hagan
Hi,
I'm writing an algorithmic music program which generates lists of numbers
representing notes and durations. The results can be printed as scores and
played as midi files using lilypond, and to play the results as they are
generated (i.e., bar by bar), I'm using the sox synth.
That's pretty limited, however, so I thought that fluidsynth might be the way
forward.
The simplest solution would be to translate my number lists into noteon
commands, etc, and pipe them to fluidsynth.
But I need a little help understanding the fluidsynth shell.
When that is active, I can type commands in, but I cant figure out how to pipe
them from my program. I tried sending a file object to stdout but it seemed
to just disappear. Also, when I try to run fluidsynth with the -i switch, (no
shell), it seems to start up, then immediately exit.
I can get a result by translating my data into a text-to-midi program, then
piping that to, say, pmidi, which plays via fluidsynth, but that seems very
roundabout.
Any advice?
Regards,
John O'Hagan
_______________________________________________
fluid-dev mailing list
http://lists.nongnu.org/mailman/listinfo/fluid-dev
John O'Hagan
2008-10-13 06:34:59 UTC
Permalink
Post by Josh Green
Hello,
As Pedro suggested, you could control FluidSynth via TCP/IP. If you
want finer grained control over FluidSynth and don't mind writing C
code, then you could use FluidSynth as a shared library. This is how
Swami and QSynth use FluidSynth.
Best regards,
Josh
Hi,

Thanks for the suggestion, but as I mentioned in my other reply, my program is
in Python and I'm not quite ready for C yet :). Python has a builtin telnet
interface which makes the TCP/IP approach very easy, too.

Cheers,

John
Post by Josh Green
Post by John O'Hagan
Hi,
I'm writing an algorithmic music program which generates lists of numbers
representing notes and durations. The results can be printed as scores
and played as midi files using lilypond, and to play the results as they
are generated (i.e., bar by bar), I'm using the sox synth.
That's pretty limited, however, so I thought that fluidsynth might be the
way forward.
The simplest solution would be to translate my number lists into noteon
commands, etc, and pipe them to fluidsynth.
But I need a little help understanding the fluidsynth shell.
When that is active, I can type commands in, but I cant figure out how to
pipe them from my program. I tried sending a file object to stdout but it
seemed to just disappear. Also, when I try to run fluidsynth with the -i
switch, (no shell), it seems to start up, then immediately exit.
I can get a result by translating my data into a text-to-midi program,
then piping that to, say, pmidi, which plays via fluidsynth, but that
seems very roundabout.
Any advice?
Regards,
John O'Hagan
_______________________________________________
fluid-dev mailing list
http://lists.nongnu.org/mailman/listinfo/fluid-dev
John O'Hagan
2008-10-14 06:16:12 UTC
Permalink
[...]
Post by John O'Hagan
Post by Pedro Lopez-Cabanillas
Note that FluidSynth doesn't follow strictly the telnet protocol, so you
can use something simpler. The command line utility netcat(1) (or 'nc')
is
[...]
Post by Pedro Lopez-Cabanillas
What I mean is that you can use simple TCP/IP sockets and text streams,
instead of the telnet class.
#!/usr/bin/python
import sys
import time
from socket import *
serverHost = "localhost"
serverPort = 9800
s = socket(AF_INET, SOCK_STREAM)
s.connect((serverHost, serverPort))
s.send("noteon 1 66 100\n")
time.sleep(1)
s.send("noteoff 1 66\n")
s.send("quit\n")
data = s.recv(1024)
print data
[...]
Thanks for the suggestion, Pablo: simpler is better, after all.
I tried the socket approach, and while it works, multiple connections break
the pipe, whereas Telnet() seems to handle this gracefully, so I put it
back in, as I want to be able to send several streams of midi messages to
one instance of fluidsynth.
Or is this possible with sockets too? If it is, I missed it.
I sure did: that last part of my post was untrue, the pipe-breaking was an
unrelated issue.

John

Loading...