gasman / mahlerproject

The code powering the 2014 MHS Oxford performance of Mahler's 1st Symphony on 12 networked ZX Spectrums

Home Page:https://www.youtube.com/watch?v=LxPXLIALJJI

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

The Mahler Project - source code
================================

Ingredients
-----------

1) A UNIX server at static IP address 192.168.48.1, running tnfsd
2) A local network of Spectrums with Spectranet interfaces, at static IP addresses 192.168.48.100 onward, configured to boot from tnfs://192.168.48.1
3) A converter script (converter/readmidi.py) to convert MIDI files to numbered *.bip files containing Spectrum BEEP data
4) A player executable (player/*)
5) 'conductor' scripts to provide the time source (conductor/*)


The converter script
--------------------
This requires Python and the 'mido' MIDI library <http://mido.readthedocs.org/en/latest/>.

To convert a MIDI file to *.bip files, run:

	python ./readmidi.py path/to/midifile.mid

In the middle of the readmidi.py script, we set the variable 'channel_velocities'. This indicates the relative volume levels that the Spectrums will be mixed at, on a scale from 0 to 127. The script will generate as many *.bip files (numbered 100.bip onward) as there are entries in this list, and will attempt to allocate MIDI notes to the Spectrum most closely matching the note's velocity. When you run the script, it will display the distribution of note velocities in the MIDI file, to help you decide on a suitable allocation of volumes.

To have the script generate a rendition of the music as a WAV file, uncomment the last line of the file:

	render.to_wave(note_data, sys.argv[2], freq=11025)

and run:

	python ./readmidi.py path/to/midifile.mid output.wav


The .bip file format consists of a sequence of (duration, pitch) byte pairs, where duration is measured in units of 1/50s, and pitch is equal to the BEEP pitch parameter plus 128. A pitch value of 0 indicates a rest, and a duration value of 0 indicates the end of the file.


The player
----------
Run 'make' within the 'player' directory. This requires Pasmo and zmakebas, and will generate the files run.zx and player.zx. Place the files under the TNFS root as follows:

boot.zx
chopin/
    run.zx
    player.zx
    100.bip
    101.bip
    ...

boot.zx simply consists of 10 %cd "chopin" / 20 %load "run.zx" . (The plan was to have a bunch of boot files pointing to different directories, but due to lack of time I just used the one and renamed the directories to 'chopin' as required :-) )


The conductor scripts
---------------------
These work by broadcasting little-endian 2-byte values as UDP packets on port 1860:

* reset.py sends 0xffff, to tell the player to reload boot.zx
* metronome.py sends an incrementing timestamp every 1/50s, starting from 0x0000

About

The code powering the 2014 MHS Oxford performance of Mahler's 1st Symphony on 12 networked ZX Spectrums

https://www.youtube.com/watch?v=LxPXLIALJJI


Languages

Language:Assembly 62.0%Language:Python 34.0%Language:BASIC 3.1%Language:Makefile 0.9%