MIDI and SFX sequencer, designed for compatibility with MusyX audio groups
Go to file
Luke Street fe04c9a137 devkitA64 compilation fixes 2020-10-21 00:30:37 -04:00
AudioUnit Update fmtlib 2020-04-11 12:49:30 -10:00
Editor Make audio overload types float-only, initial boo2 switchover 2020-09-28 10:42:51 -10:00
VST Update fmtlib 2020-04-11 12:49:30 -10:00
driver Make audio overload types float-only, initial boo2 switchover 2020-09-28 10:42:51 -10:00
include Make audio overload types float-only, initial boo2 switchover 2020-09-28 10:42:51 -10:00
lib devkitA64 compilation fixes 2020-10-21 00:30:37 -04:00
.clang-format New code style refactor 2018-12-07 19:20:09 -10:00
.gitignore Initial Amuse AudioUnit frontend architecture 2016-05-24 16:00:22 -10:00
CMakeLists.txt Make audio overload types float-only, initial boo2 switchover 2020-09-28 10:42:51 -10:00
Doxyfile Add Doxyfile 2016-05-18 19:55:10 -10:00
LICENSE Fixes for Windows 2018-08-19 10:05:39 -10:00
README.md Update README.md 2018-09-30 23:13:59 -07:00
standalone_bootstrap.bat Add standalone bootstrap script 2016-07-18 13:18:15 -10:00
standalone_bootstrap.sh Add standalone bootstrap script 2016-07-18 07:52:17 -10:00

README.md

Amuse

Amuse is a real-time MIDI and SFX sequencer, with basic effects, 3D positional audio and surround-output capabilities.

The project is designed for compatibility with Audio Groups and Song data found in PC/N64/GCN/GBA games using the MusyX audio engine; providing an alternate runtime library to use for sequencing these games' audio libraries.

Command-Line Player

Download

A simple command-line program for loading and playing AudioGroups out of game archives or raw (.proj,.pool,.sdir,.samp) files is provided.

[jacko@ghor ~]$ amuseplay test.proj
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
░░░   ████ ████  ┃  ████ ████ ████   ┃   ████ ████  ░░░
░░░   ████ ████  ┃  ████ ████ ████   ┃   ████ ████  ░░░
░░░   ▌W▐█ ▌E▐█  ┃  ▌T▐█ ▌Y▐█ ▌U▐█   ┃   ▌O▐█ ▌P▐█  ░░░
░░░    │    │    ┃    │    │    │    ┃    │    │    ░░░
░░░ A  │ S  │ D  ┃ F  │ G  │ H  │ J  ┃ K  │ L  │ ;  ░░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
<left/right>: cycle MIDI setup, <up/down>: volume, <space>: PANIC
<tab>: sustain pedal, <window-Y>: pitch wheel, <window-X>: mod wheel
<Z/X>: octave, <C/V>: velocity, <B/N>: channel, <,/.>: program, <Q>: quit
  0 Setup 0, Chan 0, Prog 0, Octave: 4, Vel: 64, VOL: 80%

The command-line program requires a windowing environment and will open a small 100x100 window alongside your terminal/cmd. This window must be frontmost, since it listens to full keyboard events through it.

If a MIDI keyboard is connected and recognized by your OS before amuseplay is launched, you may directly control the sequencer using physical input.

On OS X and Linux, amuseplay will advertise a virtual MIDI-IN port for other audio applications to route their MIDI messages to. This enables tracker, drum machine, and DAW applications to produce sampled audio using Amuse directly.

Converter Usage

amuseconv <in-path> <out-path> [gcn|n64|pc]

Note: amuseconv currently only supports SNG-to-MIDI conversion and vice-versa. To batch-extract MIDIs from one of the game files listed below, run amuseconv <data-file> <destination-dir>

Player Usage

amuseplay <data-file> [<songs-file>]or — Drag-n-drop data file on amuseplay executable (Windows and many freedesktop file managers support this)

Song Renderer Usage

amuserender <data-file> [<songs-file>] [-r <sample-rate-out>] [-v <volume 0.0-1.0>]or — Drag-n-drop data file on amuseplay executable (Windows and many freedesktop file managers support this)

Note: .wav file will be emitted at <group-name>-<song-name>.wav. If -r option is not specified, rate will default to 32KHz

Currently Supported Game Containers

  • Indiana Jones and the Infernal Machine (N64) N64 ROM file
  • Metroid Prime (GCN) AudioGrp.pak MidiData.pak
    • Pass AudioGrp.pak MidiData.pak for listening to SongGroup 53 (sequenced ship sounds)
    • Pass AudioGrp.pak for listening to any SFXGroup
  • Metroid Prime 2: Echoes (GCN) AudioGrp.pak
  • Paper Mario: The Thousand Year Door (GCN) pmario.proj pmario.slib
    • Pass pmario.proj pmario.slib for listening to SongGroups (sequenced SFX events)
    • Pass pmario.proj for listening to any SFXGroup
  • Star Fox Adventures (GCN) starfoxm.pro starfoxs.pro midi.wad
    • Pass starfoxm.pro midi.wad for listening to SongGroup 0 songs only (music)
    • Pass starfoxs.pro midi.wad for listening to other SongGroups (sequenced ambience)
    • Pass starfoxs.pro for listening to any SFXGroup
  • Star Wars Episode I: Battle for Naboo (N64) N64 ROM file
  • Star Wars: Rogue Squadron (N64) N64 ROM file (PC) data.dat
  • Star Wars Rogue Squadron II: Rogue Leader (GCN) data.dat
  • Star Wars Rogue Squadron III: Rebel Strike (GCN) data.dat
  • Any other game with raw .proj .pool .sdir .samp files
    • Pass any one of them to Amuse, all in the same directory

Windows 7 Compatibility

Installing the MSVC++ 2015 runtime may be required if you haven't already installed/updated it: https://www.microsoft.com/en-us/download/details.aspx?id=48145

Library

The Amuse API exposes full interactivity between a client application (game engine) and the sequencer engine. Unlike the interrupt-driven nature of the original console implementations (where the audio chip 'requests' more audio as needed), Amuse is entirely synchronous. This means the client must periodically pump the audio engine (typically once per video frame) to keep the OS' audio system fed.

The client must provide the implementation for allocating and mixing audio voices, since this may drastically differ from target to target. amuse::IBackendVoiceAllocator is the pure-virtual interface to implement for this. Alternatively, if Boo is present in the CMake project tree, Amuse will be compiled with a backend supporting multiple popular low-level audio APIs. Windows, OS X, and Linux all have excellent support this way.

Here's an example usage:

#include <amuse/amuse.hpp>
#include "MyVoiceAllocator.hpp"
#include "MyAudioGroupLoader.hpp"

int main(int argc, char* argv[])
{
    /* Up to the client to implement voice allocation and mixing */
    std::unique_ptr<amuse::IBackendVoiceAllocator> voxAlloc = MakeMyVoiceAllocator();

    /* Application just needs one per audio output (not per channel) */
    amuse::Engine snd(*voxAlloc);

    /* An 'AudioGroup' is an atomically-loadable unit within Amuse. 
     * A client-assigned integer serves as the handle to the group once loaded
     */
    amuse::IntrusiveAudioGroupData data = LoadMyAudioGroup();
    snd.addAudioGroup(data);

    /* Starting a SoundMacro playing is accomplished like so: */
    int sfxId = 0x1337;
    float vol = 1.0f;
    float pan = 0.0f;
    std::shared_ptr<amuse::Voice> voice = snd.fxStart(sfxId, vol, pan);

    /* Play for ~5 sec */
    int passedFrames = 0;
    while (passedFrames < 300)
    {
        snd.pumpEngine();
        ++passedFrames;
        WaitForVSync();
    }

    /* Stopping a SoundMacro is accomplished by sending a
     * MIDI-style 'KeyOff' message for the voice
     */
    voice->keyOff();
    
    /* Play for 2 more seconds to allow the macro to gracefully fade-out */
    passedFrames = 0;
    while (passedFrames < 120)
    {
        snd.pumpEngine();
        ++passedFrames;
        WaitForVSync();
    }

    /* Clean up and exit */
    return 0;
}