2016-05-19 06:13:01 +00:00
|
|
|
### Amuse
|
2016-05-02 21:52:27 +00:00
|
|
|
|
|
|
|
**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
|
2016-05-08 07:33:47 +00:00
|
|
|
found in PC/N64/GCN/GBA games using the *MusyX* audio engine; providing an
|
2016-05-02 21:52:27 +00:00
|
|
|
alternate runtime library to use for sequencing these games' audio libraries.
|
|
|
|
|
2016-05-29 21:43:26 +00:00
|
|
|
#### Command-Line Player
|
|
|
|
|
|
|
|
[Download](https://github.com/AxioDL/amuse/releases)
|
|
|
|
|
|
|
|
A simple command-line program for loading and playing AudioGroups out of
|
|
|
|
game archives or raw (`.proj`,`.pool`,`.sdir`,`.samp`) files is provided.
|
|
|
|
|
|
|
|
```sh
|
|
|
|
[jacko@ghor ~]$ amuseplay test.proj
|
|
|
|
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
|
|
|
|
░░░ ████ ████ ┃ ████ ████ ████ ┃ ████ ████ ░░░
|
|
|
|
░░░ ████ ████ ┃ ████ ████ ████ ┃ ████ ████ ░░░
|
|
|
|
░░░ ▌W▐█ ▌E▐█ ┃ ▌T▐█ ▌Y▐█ ▌U▐█ ┃ ▌O▐█ ▌P▐█ ░░░
|
|
|
|
░░░ │ │ ┃ │ │ │ ┃ │ │ ░░░
|
|
|
|
░░░ A │ S │ D ┃ F │ G │ H │ J ┃ K │ L │ ; ░░░
|
|
|
|
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
|
2016-05-31 05:15:20 +00:00
|
|
|
<left/right>: cycle MIDI setup, <up/down>: volume, <space>: PANIC
|
2016-05-29 21:43:26 +00:00
|
|
|
<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.
|
|
|
|
|
2016-05-02 21:52:27 +00:00
|
|
|
#### 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.
|
2016-05-03 06:38:14 +00:00
|
|
|
`amuse::IBackendVoiceAllocator` is the pure-virtual interface to implement
|
2016-05-08 07:33:47 +00:00
|
|
|
for this. Alternatively, if [Boo](https://github.com/AxioDL/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.
|
2016-05-02 21:52:27 +00:00
|
|
|
|
|
|
|
Here's an example usage:
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
#include <amuse/amuse.hpp>
|
|
|
|
#include "MyVoiceAllocator.hpp"
|
2016-05-02 21:54:23 +00:00
|
|
|
#include "MyAudioGroupLoader.hpp"
|
2016-05-02 21:52:27 +00:00
|
|
|
|
|
|
|
int main(int argc, char* argv[])
|
|
|
|
{
|
|
|
|
/* Up to the client to implement voice allocation and mixing */
|
2016-05-03 01:16:26 +00:00
|
|
|
std::unique_ptr<amuse::IBackendVoiceAllocator> voxAlloc = MakeMyVoiceAllocator();
|
2016-05-02 21:52:27 +00:00
|
|
|
|
|
|
|
/* 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
|
|
|
|
*/
|
2016-05-15 21:56:23 +00:00
|
|
|
amuse::IntrusiveAudioGroupData data = LoadMyAudioGroup();
|
|
|
|
snd.addAudioGroup(data);
|
2016-05-02 21:52:27 +00:00
|
|
|
|
|
|
|
/* Starting a SoundMacro playing is accomplished like so: */
|
|
|
|
int sfxId = 0x1337;
|
|
|
|
float vol = 1.0f;
|
|
|
|
float pan = 0.0f;
|
2016-05-21 21:40:03 +00:00
|
|
|
std::shared_ptr<amuse::Voice> voice = snd.fxStart(sfxId, vol, pan);
|
2016-05-02 21:52:27 +00:00
|
|
|
|
|
|
|
/* Play for ~5 sec */
|
|
|
|
int passedFrames = 0;
|
|
|
|
while (passedFrames < 300)
|
|
|
|
{
|
|
|
|
snd.pumpEngine();
|
|
|
|
++passedFrames;
|
|
|
|
WaitForVSync();
|
|
|
|
}
|
|
|
|
|
2016-05-03 05:16:37 +00:00
|
|
|
/* Stopping a SoundMacro is accomplished by sending a
|
2016-05-02 21:52:27 +00:00
|
|
|
* MIDI-style 'KeyOff' message for the voice
|
|
|
|
*/
|
2016-05-03 06:40:17 +00:00
|
|
|
voice->keyOff();
|
2016-05-02 21:52:27 +00:00
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
```
|