Gunnar Wolf: Objects and signals
So far, Ruby is the only language I have actually liked that imposes a mindset on you. I love Perl's approach of letting you do things your way, whatever you define by that - Ruby forces you to extensively use OOP. But, actually, it is so well implemented that it even makes sense. It is even fun! Of course, that paired to an excellent introspection ability leaves enough room to make the cleverest (and, yes, most obfuscated) code you can think of.
Well... But there are limits to everything, and I think I found a spot where all the nice separation and cleanness ends abruptely: When interacting to the always nasty outside world.
It might also, of course, have some relation to the fact that I'm too new also for writing GUIs - this is the first nontrivial one I do. And it shows, as it took me some time to properly understand the pairing between the nice Glade elements, how to make a decently modular system, how to properly handle UI (and internal) events... But I've been progressing quite nicely, and I hope to be able to show off my little app to a wider audience soon. At the very least, I hope to be able to show it to my boss by next week, as he is getting impatient ;-)
Ok, but where does it all break, according to me? One of the things I must monitor with this app is that a couple of processes spawned by it work happily in the background while I only show a nice interface to my users. Now, how is the best way to do this? Why, by trapping the SIGCHLD signal, of course! Whenever any of the processes in the pipeline die, the parent (controlling) process gets a nice CHLD signal. I trap it, restart the processes, and no harm done. And in Ruby, it looks quite natural:
How nice, how neat... How buggy :-/
It took me quite a few hours to get this right. And it should be obvious, of course... No matter where you declare a signal handler, there is no reason for you to believe it is tied to a particular instance, or for that matter, to a class. A signal handler breaks and jumps in the execution in the ugliest old-school way. Yes, if your signal handler consists of:
you will note that your good friend self is nothing but an Object.
Once I realized that, yes, things became reworkable, and I now think I am actually better off even OOP-aly than some hours ago - Some of the classes badly needed to adhere to the Singleton pattern and now work with less worries and ugliness. But, hey, it took me quite a while.
Anyway, lets see which new challenges Ruby+Glade2 still have for me. I am sure there will be plenty. And I haven't even started playing with GStreamer!
Well... But there are limits to everything, and I think I found a spot where all the nice separation and cleanness ends abruptely: When interacting to the always nasty outside world.
It might also, of course, have some relation to the fact that I'm too new also for writing GUIs - this is the first nontrivial one I do. And it shows, as it took me some time to properly understand the pairing between the nice Glade elements, how to make a decently modular system, how to properly handle UI (and internal) events... But I've been progressing quite nicely, and I hope to be able to show off my little app to a wider audience soon. At the very least, I hope to be able to show it to my boss by next week, as he is getting impatient ;-)
Ok, but where does it all break, according to me? One of the things I must monitor with this app is that a couple of processes spawned by it work happily in the background while I only show a nice interface to my users. Now, how is the best way to do this? Why, by trapping the SIGCHLD signal, of course! Whenever any of the processes in the pipeline die, the parent (controlling) process gets a nice CHLD signal. I trap it, restart the processes, and no harm done. And in Ruby, it looks quite natural:
Signal.trap(:CHLD) do
@processes.each { p p.stop if p.active?; sleep 1; p.start}
done
@processes.each { p p.stop if p.active?; sleep 1; p.start}
done
It took me quite a few hours to get this right. And it should be obvious, of course... No matter where you declare a signal handler, there is no reason for you to believe it is tied to a particular instance, or for that matter, to a class. A signal handler breaks and jumps in the execution in the ugliest old-school way. Yes, if your signal handler consists of:
Signal.trap(:CHLD) do { puts self.class }
Once I realized that, yes, things became reworkable, and I now think I am actually better off even OOP-aly than some hours ago - Some of the classes badly needed to adhere to the Singleton pattern and now work with less worries and ugliness. But, hey, it took me quite a while.
Anyway, lets see which new challenges Ruby+Glade2 still have for me. I am sure there will be plenty. And I haven't even started playing with GStreamer!
They represent exactly the same thing, yet someone who knows music
needs a split second to decode the below but a few seconds for the above
(if they understand lilypond's syntaxis). In fact, at first I thought
that I had done something wrong in invoking lilypond-book to
produce that snippet, because I had misparsed the code above (which,
incidentally, is one bar of some actual music that I have in my
~/data/audio/lilypond directory)
The plain text interface certainly does have some
advantages, but IMO the downsides by far outweigh the benefits. In
general, lilypond is not well suited as a way to actually write
music, as opposed to simply typesetting already existing music. I did
actually follow a course on harmonics (although I never finished it due
to lack of time); when writing some new piece, I find that it often far
easier to do the actual writing on a piece of paper and then enter that
in lilypond syntaxis, rather than getting distracted over the lilypond
syntaxis while trying to concentrate on what chords I can and/or want to
use. It is unnatural, and would look like a Japanese person being forced
to read and write texts like 'gaka ga e o kaita' which then get
postprocesssed into something like ' ' (look ma,
Unicode!). Or, in other words: why isn't there just an input method to
write music? There are unicode characters for musical notes,
you know...
When comparing lilypond to finale, it is not hard to understand that
entering music in a graphical environment is just so much easier. When I
last used it, Finale had four input methods: one with keyboard and mouse
(use the numeric keys on the keyboard to enter the desired note length
and the mouse to enter the pitch); one with keyboard only (use abcdefg
etc. to choose the pitch, and the same numeric keys to enter the desired
length); one with keyboard and MIDI keyboard (use the numeric keys to
enter a desired note length, and just press a note on the MIDI keyboard
to choose it); and finally, it can also quantisise music as you play it
(which is the fastest, but least accurate, method to enter music).
Lilypond only allows entering music with the keyboard directly, and then
only displays notes after 'compiling' them, so that you cannot see your
mistakes and typos until much later. I'm disregarding midi2ly, which
converts MIDI files to lilypond input files in a reasonably good way;
but Finale has MIDI import functionality as well, I do not consider that
to be an 'Input Method' as such.
After having entered the music, a musician will want to do something
with it. Have the computer play it, for instance, or print it out so
that he or she can rehearse it and eventually play it themselves.
Lilypond will do neither by itself; however, it can produce postscript,
PDF, and DVI files which one can use to print, and/or MIDI files which
one can have the computer play. The printouts are great, as I've said
before; but playing the MIDI files is another matter entirely.
As I've explained earlier, playing MIDI used to be done through
hardware. When I still had a working SB16-compatible card, I could play
MIDI files on my computer perfectly fine by just using the driver for
that sound card. Since I currently depend mostly on ESS1371-compatible
cards, that do not havve any hardware MIDI synthesizer, however, that
doesn't work. So I have to use software sequencing instead. On Windows,
software sequencing is done by the sound card's driver. On Linux, there
is no software sequencing being done by any driver, so it all has to be
done in userland. In theory, that's just fine. Unfortunately, the
implementation sucks.
The only software MIDI synthesizer available on Debian is