Last week I posted possibly the most tedious Basic type-in listing ever to World Of Spectrum:

5 BEEP 0.212765, 20; 10 BEEP 0.106383,19...
(continues for approx 1500 more lines)

Anyone typing it in in its entirety would be rewarded with this:

Download midibeep_minute_waltz.mp3

Not bad for an evening’s work. Mind you, I did take an ever so teeny shortcut, by writing a Ruby program to convert a MIDI file to BEEP format. (Any .mid file will do, although ones with a single instrument will survive the rather primitive selective-note-butchering process better. Oh, and anything much longer than this one will exceed the 48K Spectrum memory…) And now you can try it out too:

Update 2010-05-26: Karl McNeil has adapted Midibeep into a variant called Mid2ASM, which outputs an assembler listing rather than Basic – this enables the data to be packed much more efficiently, paving the way for altogether longer pieces of music. Download Mid2ASM (453K, Windows EXE included)

Update 2010-06-02: Another update from Karl, featuring a Windows GUI, more space-saving tweaks, and embedding the output in a Basic REM statement. Download Mid2ASM v2 (3.4Mb)

Update 2011-04-09: Karl McNeil has released the last version of Mid2ASM for a while, version 3.2 – featuring primitive importing from .sid .psg and .wav, and the choice of Basic or assembly output. The source archive also contains the command-line version, midibeep2.

14 Responses to “Midibeep”

  1. MattyThorne says:

    That is awsome!
    You know what would also be awesome? Give the listing to someone to type in and when they were done tell them about Midibeep!
    No, that’s just just plain mean actually, I don’t mean it ;)

  2. Megus says:

    Gasman, you’re crazy! Really loved it :)

  3. MISTER BEEP says:

    Oh, shoot.
    And that’s still one audible channel!
    You’re a dangerous man.
    And actually the music has some weird charm in it.

    But does it merge many channels into one automatically or the musician has to do that?

  4. KLP2 says:

    Wouldn’t using DATA statments instead lower the memory usage?

  5. matt says:

    KLP2: A bit, yes. You’d still have the numbers eating up space in both ASCII and floating-point form, which you could condense further with VAL (or the nasty trick of putting a 0 there in the ASCII form but poking the real floating-point value – which would eliminate any pretense of it being type-in-able, of course). Better still – and departing even further from pure Basic – would be to come up with an efficient packed byte encoding for the data, to be read via PEEK. But that’s the point at which I decided that I’d spent too long on this already :-)

  6. Emlyn Hughes says:

    Amazing! Everything sounds better in a spectrum.

  7. Karl McNeil says:

    Iv just emailed you a new version of your tool, renamed Mid2ASM… Thats right, it now spits out Assembly instead of BASIC… It still sounds the same, using the BEEPER, but saves space by cutting out the BASIC listing and converting the beep data into integers… If you think it is worthy of attention, then Id be honoured to see it hosted on your site…

  8. Karl McNeil says:

    Mid2ASM GUI version emailed to Gasman… Now also compiles the ASM, pumps it through bin2Rem and generates autorunning TAP files…

    Optimizations for speed and memory also made…
    Gui allows you to preview midi music files prior converting
    outputed Assembly now more compatible with other assemblers

    Once again, Id be honoured to see this hosted on Gasmans page!…

  9. Karl McNeil says:

    Mid2ASM v2.3 sent to Gasman & WOS…
    - Some minor assembly optimization added (some math is precalc’ed)
    - Beeper tune now plays via PC beeper after compiling for preview
    - BugFIX: Menu entry now reflects whether music playing or not (STOP added)

    NB: The original commandline version is in the source zip file (Its main improvements are the optimized assembly edits)

  10. Karl McNeil says:

    Mid2ASM v3.0 sent to Gasman & WOS… Once again, the commandline version is in the source package (precompiled), and now allows parameters to adjust the fraction that determines the note lengths, and add an offset that alters the tempo.

    eg: default is -M:51(0)

    ..where 51 is the mininote value from which all note durations are multiples and (0) is the tempo offset added during playing…

    The GUI version, allows you to alter these settings via a GUI slider (if you untick the default settings in the menu first), and allows you to adjust the tempo while you listen to the PC beeper preview realtime. Hitting compile then allows you to set this tempo to output the obligatory .TAP file…

    …plus the usual bugfixes… etc, etc…

    This may be the end of development of this project…

    ..for now…

    ..unless I find time to reintegrate output back to BASIC using DATA statements… we’ll see… ;)

  11. Karl McNeil says:

    Just uploaded Mid2ASM v3.2 to WOS and emailed a copy to you Id be honoured if you would add it to your site!… Its actually an old update, dating from Aug 19/2010, but thought Id put it out there for preservation reasons, as the project is practically dead and might not see light of day otherwise…

    As before: It comes in two flavours:

    GUI Version (Mid2ASM):
    - Allows primitive importing of .sid, .psg, .wav prior conversion to midi

    CMD Version (midibeep2 found in Mid2ASM_SRC.zip):
    - Allows you to shift the music up/down semitones to put within pitch range

    BOTH Versions:
    - Both now spit out BASIC output as well as Assembly
    - Both will autocorrect notes imported if out of ZX pitch range
    - Both will allow alternative formatting of either assembly (as HEX data) or for BASIC (compressing data to a REM statement)…(This is EXPERIMENTAL only!!! – Tends to fail on large listings!)…

    NB: The simplify note option on the GUI version is redundant, but may be used in a future version for something.. a placeholder only… Oh, and aside from only allowing small pieces (cos squeezed onto single REM line), but experiemental compact mode for BASIC listing also pauses for some time prior playing, as it pokes all the data into memory prior playing it for speed…


  12. garvalf says:

    It seems the newest version of ruby doesn’t handle the old code:

    /var/lib/gems/1.9.1/gems/generator-0.0.1/lib/generator/generator.rb:16:in `initialize’: undefined method `[]‘ for # (NoMethodError)
    from midibeep.rb:43:in `new’
    from midibeep.rb:43:in `add’
    from midibeep.rb:76:in `block (2 levels) in ‘

    now let’s have a look at this mid2asm… :)

  13. matt says:

    @garvalf: Yes – it seems that Ruby dropped ‘generator’ from its standard library in 1.9, and didn’t offer any upgrade path, which seems like a spectacularly rubbish thing for a programming language to do. (As I recall, the ‘generator’ gem is something entirely unrelated.)

    I’ve not touched Ruby coding for several years now, and I don’t particularly fancy re-learning it just to fix this project (especially if Ruby is going to carry on being a moving target and break it again in a year or two), so I can only suggest installing Ruby 1.8. (You may find the ‘rvm’ utility useful, which lets you install multiple Ruby versions side by side.)

  14. sdalu says:

    ruby 2.x

    class IteratorMerger
    include Enumerable

    def initialize
    @streams = []

    def add(enumerable)
    # convert enumerable object to an iterator responding to end?, current and next
    @streams << enumerable.to_enum

    def each
    until @streams.all?{|stream|
    rescue StopIteration
    # while there are still some objects in the stream,
    # pick the stream whose next object is first in order
    next_stream = @streams.reject{|stream|
    rescue StopIteration
    a.current b.current
    yield next_stream.next

Leave a Reply