Skip to content

A Unity3D MIDI player with instruments defined in sfz format, using sfizz as the underlying sampler.

License

Notifications You must be signed in to change notification settings

f1yingbanana/sfizz-unity

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🎹 sfizz-unity

openupm Twitter Follow

Sfizz for Unity is a wrapper around sfizz - an open source audio synthesizer capable of loading virutal instruments in sfz files and generating audio with them live in Unity.

This Unity wrapper takes advantage of the exported C APIs in sfizz.h, and hides the details of making function calls to C++. In addition, this package also comes with a simple audio player which interacts with the audio synthesizer. This player takes care of feeding in audio instructions (either generated by the UI or from a MIDI file) to the native library, then converting the returned buffers to a streaming AudioClip.

As this is a wrapper for sfizz, users need to obtain their own sfizz library (see section below). Note each target platform will require a specific library built on that platform, and once placed in Unity, the library must be configured accordingly (see plugins).

🎼 System requirements

Unity 2018.4.0 or later versions. Works on:

  • Windows
  • macOS
  • Linux
  • iOS

🎛️ Installation

The package is available on the openupm registry.

openupm add dev.f1yingbanana.sfizz-unity

You can also install this via Unity Package Manager with the following git url:

https://github.com/f1yingbanana/sfizz-unity.git#upm

An Asset Store package is in the works.

🎶 Getting Started

🎤 Getting sfizz

The sfizz library must be built on each of the Unity project's target platform. On Windows, we are looking for the sfizz.dll file. On iOS/macOS, we are looking for sfizz.dylib. On Linux, sfizz.so. Currently their releases on GitHub do not contain library files we need, so we can either build it ourselves (locally or cloning then using GitHub CI), or ask in their Discord channel (they are very nice and helpful 😇).

See this fork for an example of building it on GitHub for Windows (x86 and x64).

🪗 Importing sfizz

Once we obtained the library files, import them into Unity and set them up following this guide. sfizz-unity is a native plugin, by the way.

🎻 Getting virtual instruments

There are plenty of free samples online, notably the Salamander Grand Piano, a copy of which is included in this package's piano sample scene. For an in-depth discussion of where to place them, see this section below.

🥁 Walkthrough

The class SfizzPlayer takes care of a lot of boilerplate code. It keeps an instance of Sfizz and converts audio output from it on Update and fills an AudioClip for the AudioSource to play. It also takes care of keeping and resizing buffers for data and latency elimination.

To use it, simply add it as a component to a GameObject in the scene. We now need to create a script to tell it to load an instrument and also what to play.

using F1yingBanana.SfizzUnity;
using UnityEngine;

public class MusicController : MonoBehaviour {
  // Don't forget to link the reference to the SfizzPlayer in the scene!
  public SfizzPlayer player;
  public string sfzPath;
  
  private void Start() {
    player.Sfizz.Load(sfzPath);
  }
  
  private void Update() {
    player.Sfizz.SendNoteOn(/* delay= */ 0, /* noteNumber= */ 60, /* velocity= */ 64);
  }
}

Add the MusicController component to a GameObject in the scene and link the sfzzPlayer. For sfzPath, enter the absolute path to your downloaded sfz file for now (more on this below).

Press play, and you should hear the middle C being triggered repeatedly.

For a more sophisticated setup, import the piano sample scene in the Package Manager and look at the PianoController.

🎸 Under the hood

At a high level, the sfizz engine tracks audio events - when a note has started or stopped. It then processes these events in batch to produce a buffer of audio data, and clears all the events. The cycle then repeats. There are some subtle differences between the C++ implementation and the C# wrapper, however. These are listed below.

🎷 The path problem

sfizz expects a directory system when loading instrument audio from files, but in builds, Unity packs all used assets tightly together into bundles. This means while everything works in the Unity editor, on any standalone player it is no longer possible for sfizz to find the audio samples. Depending on your needs, there are two solutions.

My sfz files should be bundled in my application

Use the StreamingAssets folder. Put your sfz file in Assets/StreamingAssets/.../instrument.sfz. In your controller script, pass in a global path.

string path = Path.GetFullPath(Path.Combine(Application.streamingAssetsPath, ".../instrument.sfz"));
sfizzPlayer.Sfizz.Load(path);

My sfz files are downloaded

Use the persistent data path. At runtime, extract your files to the persistent data path, create your own directories, then pass in the global path.

🪕 FAQs

Can I use this on Android?

No. You can try to build the source code for Sfizz with NDK in this guide. StreamingAssets folder also doesn't work for Android, so you will need a system to extract the audio files to persistentDataPath instead.

I'm getting an EntryPointNotFoundException, what do I do?

You likely have an incompatible sfizz library. Currently this wrapper requires a minimum version of Sfizz 1.2, and if your library is a lower version, you might get this exception. See section to obtain the latest version.

I want to use a function in sfizz.h, but it's not in the wrapper

This is likely because porting the function to C# is difficult. Almost all functions in the interface present in Sfizz 1.2 are in the wrapper, but if one that should be in the wrapper is missing, file a feature request.

About

A Unity3D MIDI player with instruments defined in sfz format, using sfizz as the underlying sampler.

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published

Languages