pcspkrplay icon indicating copy to clipboard operation
pcspkrplay copied to clipboard

Play music through the PC speaker in Linux

PC Speaker Player - pcspkrplay

Introduction

This program will play PC speaker music in Linux using the Linux input devices API. Currently loosely based on Megazeux style play statements, but might break on some less compliant play strings.

If you were looking to play PCM sound and music through the PC speaker, this isn't what you want. Look in to the ALSA driver snd-pcsp for that. It'll make your PC speaker in to a plain old ALSA "card" for programs to output audio to.

Compiling

Executing: make

should build it for you. This doesn't depend on anything special that wouldn't come with linux.

Usage

Options: --decompile / -d After compiling, decompile back to music string. (Currently disabled)

--device / -e device Select event device, default is /dev/input/by-path/platform-pcspkr-event-spkr.

--filename / -f filename Read from filename instead of standard input.

--quiet / -q Don't play, only compile (and optionally decompile) then quit.

--display / -s Display playback status.

--help / -h Print quick help/usage.

--debug Enable debug mode. Prints information on program state after each command is executed.

You will need full read/write access to the event device you wish to use. Look up the chmod command for information on setting that up.

Music String Format

Mostly based on Megazeux's play statement format, but extended for more features.

C, D, E, F, G, A, B Play a note.

0, 1, 2, 3, 4, 5, 6 Select octave, default is 3.

#, $ Placed after a note, moves the note up or down a semitone. B# is accepted and becomes C on the next octave except for 6B#, E becomes F, C$ becomes B on the previous octave except for 0C$.

Z, T, S, I, Q, H, W Select note duration, 64th, 32nd, 16th, 8th, quarter, half, whole. Default is 32nd.

+, - Increase or decrease octave by 1, clips at 0 and 6.

. Change duration of folloing notes by 150%. Can be unset with another '.', can override '!'.

! Change duration of following notes by 1/3. Can be unset with another '!', can override '.'.

&string& Ignores string. Normally used to play a sample in Megazeux, but for this program, you can use it for comments.

  • Extended command bb Change BPM. (see VM COMMANDS for argument format)

    db Change to custom note division. (see VM COMMANDS for argument format)

    VM COMMANDS

      VM commands follow the same format as Extended commands, but
    

    provide much more robust control and program flow.

    Numbers: A number entered in a command can be from 0 to 16777215. Since this language doesn't really require spaces, termination is done after 8 digits have been read in, or a nondigit (start of a new command) is reached. If the next command is an octave change command, you will have to terminate the number with a ^.

    Examples *b123cdefg - Set BPM to 123, then play CDEFG. *b60^2cdefg - Set BPM to 60, set octave to 2, then play CDEFG.

    Registers: The language includes 26 registers, represented by the letters a through z. o, d, b and l have special meanings for octave, divisor, BPM and duration. The previous commands used to modify these values also modify these registers, but in a more limited way. The rest are special purpose and can be used freely. Any special purpose registers brought out of range will be set to a more sane value.

    Commands: Commands consist of a letter and possible arguments following. An argument can either be a numerical value or a register, specified by a n or an r, or b if it can take both. Currently there are no instructions that only take a numerical value.

    nb Play a note from 1(C) to 12(B), or 0 to play a rest.

    mrb Move a value or register (b) in to register (r).

    arb Add a value or register (b) to register (r).

    srb Subtract a value or register (b) from register (r).

    crb Compare a value or register (b) with register (r). Used for conditional jumping to specify the items to be compared.

    ib Jump to command position in value or register (b) if comparison is inequal.

    eb Jump to command position in value or register (b) if comparison is equal.

    gb Jump to command position in value or register (b) if second item in comparison is greater.

    lb Jump to command position in value or register (b) if second item in comparison is less.

    jb Jump to command position in value or register unconditionally.

    b Branch to a subroutine which can return to the command directly after this one.

    r Return from a subroutine.

    f Clear flags after a comparison. It's important that this is done after a comparison in most situations.

    : Create a label.

    h Halt program execution.

    Labels: The argument to any of the jump commands, as well as branch can be preceded with a : (eg: *j:0) which will say to jump to position at label 0. Labels are created with the *: command. They are automatically assigned valuessequentially. The first *: will be label 0, the next will be label 1, then 2 and so on.

| Doesn't do anything and isn't detected by the engine in any way, but this will always be reserved to be used as a bar/separator.

Unknown or malformed commands are ignored.

Examples

echo "cdefgab+c" | ./pcspkrplay Play C major scale at octave 3 with 32nd notes.

echo "q2cdefgab+c" | ./pcspkrplay Play C major scale at octave 2 with quarter notes.

./pcspkrplay -f song.txt Play song.txt.

./pcspkrplay -f song.txt -q --decompile >song_optimized.txt Compile then decompile song, size-optimizing it, but don't play it.

Troubleshooting

open: No such file or directory Make sure the file exists, and if it's a different name, provide it to pcspkrplay using the -e argument. You might also need to load the PC speaker driver, pcspkr with: modprobe pcspkr

open: Operation not permitted Make sure you have adequate permission to read and write to the pc speaker event device. If you don't you can use something like this as root: chmod a+rw /dev/input/by-path/platform-pcspkr-event-spkr NOTE: Running pcspkrplay as root will work but you shouldn't run anything as root unless you absolutely cannot avoid it.

ioctl: Inappropriate ioctl for device The device attempted to use isn't a Linux input device.

Device X does not support sound. The input device attempted to use doesn't expose a beeper speaker interface.

Segmentation fault/Floating point exception/Arithmetic exception/*** glibc detected: ... ***/etc. The program has crashed due to a bug. Please post a bug report and the song which failed on the github page at http://github.com/paulguy/pcspkerplay and I will see about fixing it.

VM EXCEPTION: ... If not in debug mode, this can mean either a problem with your song, or a bug in the program. If you feel your song is written correctly and that a bug in the program is at fault, please post a bug report. If it reports DEVICE_ERROR, it could more likely be a bug unrelated to your song at all.

Credits

Design and Program - Paul "paulguy" Makefile and some help teaching me GIT - Mike Swanson "Chungy" Example Song - Original: DJ Shadow, PC Speaker cover: "neffy"