Skip to content
This repository has been archived by the owner on Oct 11, 2020. It is now read-only.

Commit

Permalink
Merge branch 'bfxr-params'
Browse files Browse the repository at this point in the history
  • Loading branch information
zeh committed Jul 13, 2014
2 parents f8f34ed + a655c5a commit eb354bd
Show file tree
Hide file tree
Showing 25 changed files with 2,698 additions and 962 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
_temp
_assets
_todo.txt
_*.bat
samples/main/Assets/AssetStoreTools
samples/main/Assets/AssetStoreTools.*
29 changes: 20 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
usfxr
=====

usfxr is a C# library used to generate game-like procedural audio effects inside Unity. With usfxr, one can easily synthesize sound in real time for actions such as item pickups, jumps, lasers, hits, explosions, and more.
usfxr is a C# library used to generate and play game-like procedural audio effects inside Unity. With usfxr, one can easily synthesize original sound in real time for actions such as item pickups, jumps, lasers, hits, explosions, and more, without ever leaving the Unity editor.

usfxr is a port of Thomas Vian's [as3sfxr](https://code.google.com/p/as3sfxr/), which itself is an ActionScript 3 port of Tomas Pettersson's [sfxr](http://www.drpetter.se/project_sfxr.html).
usfxr comes with code that allows for real-time audio synthesizing in games, and an in-editor interface for creating and testing effects before you use them in your code.

[This video](https://vimeo.com/15769163) explains the ideas behind as3sfxr, and the ideas that I want to support with usfxr.
usfxr is a port of Thomas Vian's [as3sfxr](https://code.google.com/p/as3sfxr/), which itself is an ActionScript 3 port of Tomas Pettersson's [sfxr](http://www.drpetter.se/project_sfxr.html). And as if the acronym collection is not enough, it also supports additional features first introduced by [BFXR](http://www.bfxr.net/) such as new waveform types and filters.

Despite my name not being Thomas or a variant of it, I found myself wishing for a (free) library to procedurally generate audio inside Unity in real time, and usfxr is the result. Since it is a Unity project, usfxr also includes an in-editor window to easily generate and test sounds without leaving the Unity.
[This video](https://vimeo.com/15769163) explains the ideas behind as3sfxr, and the ideas supported by usfxr.


Introduction
Expand All @@ -20,7 +20,7 @@ However, by using a runtime library like usfxr, you can generate the same audio
* Audio is generated in real time; there's no storage of audio files as assets necessary, making compiled project sizes smaller
* Easily play variations of every sound you play; adds more flavor to the gameplay experience

I make no claims in regards to the source code or interface, since it was simply adapted from Thomas Vian's own code and (elegant) interface. As such, usfxr contains the same features offered by as3sfxr, such as caching of generated audio and ability to play sounds with variations. But because it is adapted to work on a different platform, however, it has advantages of its own:
I make no claims in regards to the source code or interface, since it was simply adapted from Thomas Vian's own code and (elegant) as3sfxr interface, as well as Stephen Lavelle's BFXR additional features. As such, usfxr contains the same features offered by these two ports, such as caching of generated audio and ability to play sounds with variations. But because the code is adapted to work on a different platform (Unity), it has advantages of its own:

* Fast audio synthesis
* Ability to cache sounds the first time they're played
Expand All @@ -31,7 +31,9 @@ I make no claims in regards to the source code or interface, since it was simply
Installation
------------

Download the latest "usfxr" zip file from the "/build" folder of the GitHub repository and extract the contents of this file into the "Scripts" (or equivalent) folder of your Unity project. After doing that, you should have the usfxr interface available inside Unity, as well as being able to instantiate and play SfxrSyth objects inside your project.
Download the latest "usfxr" zip file from the "/build" folder of the GitHub repository and extract the contents of this file into the "Scripts" (or equivalent) folder of your Unity project. Alternatively, you can also download and install usfxr [from the asset store](https://www.assetstore.unity3d.com/en/#!/content/18619).

After doing that, you should have the usfxr interface available inside Unity, as well as being able to instantiate and play SfxrSyth objects inside your project.


Usage
Expand Down Expand Up @@ -138,7 +140,6 @@ To-do/ideas
* Show final duration in GUI
* Undo/Redo
* Add option to "lock" GUI items like BFXR's interface
* Implement BFXR's new parameters (new waveforms, new filters)


Acknowledgments
Expand All @@ -147,12 +148,22 @@ Acknowledgments
* Tomas Pettersson created the original [sfxr](http://www.drpetter.se/project_sfxr.html), where all the concepts for usfxr come from.
* Thomas Vian created [as3sfxr](https://code.google.com/p/as3sfxr/), the original code that was ported to C# for usfxr.
* [Tiaan Geldenhuys](http://tiaan.com/) contributed to usfxr by cleaning the code and creating the original version of the in-editor window that I bastardized later.

* [Stephen Lavelle](http://www.increpare.com/) created [BFXR](http://www.bfxr.net/), an AS3 port of SFXR with several new features of its own, many of which have been adopted by usfxr.

Changelog
---------

#### 2014-06-10
#### 2014-07-12

* Added support for BFXR's new filters: compression, harmonics, and bitcrusher
* Added support for BFXR's expanded pitch jump effects
* Added support for BFXR's parameter strings (standard SFXR parameter strings still work)

#### 2014-07-08

* Added support for BFXR's new waveform types: triangle, breaker, tan, whistle, and pink noise

#### 2014-06-10 ([1.1](https://github.com/zeh/usfxr/releases/tag/v2014-06-10))

* Small internal optimizations: generates audio samples in about 9% less time

Expand Down
64 changes: 45 additions & 19 deletions samples/SpaceGame/Assets/Scripts/usfxr/Editor/SfxrGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,16 @@ public class SfxrGenerator : EditorWindow {
/// </summary>

// Enums
enum WaveType : uint {
public enum WaveType : uint {
Square = 0,
Sawtooth = 1,
Sine = 2,
Noise = 3
Noise = 3,
Triangle = 4,
PinkNoise = 5,
Tan = 6,
Whistle = 7,
Breaker = 8
}

// Properties
Expand Down Expand Up @@ -146,6 +151,9 @@ public bool RenderLeftColumn(SfxrParams parameters) {

GUILayout.Space(30);

if (GUILayout.Button("COPY (OLD)")) {
EditorGUIUtility.systemCopyBuffer = parameters.GetSettingsStringLegacy();
}
if (GUILayout.Button("COPY")) {
EditorGUIUtility.systemCopyBuffer = parameters.GetSettingsString();
}
Expand Down Expand Up @@ -203,15 +211,17 @@ public bool RenderSettingsColumn(SfxrParams parameters) {
public bool RenderParameters(SfxrParams parameters) {
bool mustPlaySound = false;

GUIStyle waveTypeStyle = EditorStyles.popup;
waveTypeStyle.fontSize = 12;
waveTypeStyle.fixedHeight = 22;

EditorGUI.BeginChangeCheck();
try {
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
parameters.waveType = (uint)GUILayout.Toolbar((int)parameters.waveType, new string[] { "Squarewave", "Sawtooth", "Sinewave", "Noise" }, GUILayout.MinWidth(300), GUILayout.MaxWidth(400), GUILayout.Height(24), GUILayout.ExpandWidth(true));
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
WaveType waveTypeAsEnum = (WaveType)parameters.waveType;
waveTypeAsEnum = (WaveType)EditorGUILayout.EnumPopup(new GUIContent("Wave Type", "Shape of the wave"), waveTypeAsEnum, waveTypeStyle);
parameters.waveType = (uint)waveTypeAsEnum;
GUILayout.Space(12);

//RenderToolbar(new string[] { "Square Wave", "Sawtooth", "Sine wave", "Noise" }, (value => parameters.waveType = ((uint)value)), new GUIContent("Wave Type", "Shape of the wave"));
//RenderPopup(waveTypeOptions, ((int)(parameters.waveType)), (value => parameters.waveType = ((uint)(value))), new GUIContent("Wave Type", "Shape of the wave"));
bool isSquareWaveType = (parameters.waveType == 0);
RenderSlider(+0, +1, parameters.masterVolume, (value => parameters.masterVolume = value), new GUIContent("Volume", "Overall volume of the sound (0 to 1)"));
Expand All @@ -222,6 +232,9 @@ public bool RenderParameters(SfxrParams parameters) {
RenderSlider(+0, +1, parameters.sustainPunch, (value => parameters.sustainPunch = value), new GUIContent("Sustain Punch", "Tilts the sustain envelope for more 'pop' (0 to 1)"));
RenderSlider(+0, +1, parameters.decayTime, (value => parameters.decayTime = value), new GUIContent("Decay Time", "Length of the volume envelope decay (yes, I know it's called release) (0 to 1)"));

// BFXR
RenderSlider(+0, +1, parameters.compressionAmount, (value => parameters.compressionAmount = value), new GUIContent("Compression", "Pushes amplitudes together into a narrower range to make them stand out more. Very good for sound effects, where you want them to stick out against background music (0 to 1)"));

RenderHeading("Frequency");
RenderSlider(+0, +1, parameters.startFrequency, (value => parameters.startFrequency = value), new GUIContent("Start Frequency", "Base note of the sound (0 to 1)"));
RenderSlider(+0, +1, parameters.minFrequency, (value => parameters.minFrequency = value), new GUIContent("Minimum Frequency", "If sliding, the sound will stop at this frequency, to prevent really low notes (0 to 1)"));
Expand All @@ -230,9 +243,20 @@ public bool RenderParameters(SfxrParams parameters) {
RenderSlider(+0, +1, parameters.vibratoDepth, (value => parameters.vibratoDepth = value), new GUIContent("Vibrato Depth", "Strength of the vibrato effect (0 to 1)"));
RenderSlider(+0, +1, parameters.vibratoSpeed, (value => parameters.vibratoSpeed = value), new GUIContent("Vibrato Speed", "Speed of the vibrato effect (i.e. frequency) (0 to 1)"));

RenderHeading("Tone Change");
RenderSlider(-1, +1, parameters.changeAmount, (value => parameters.changeAmount = value), new GUIContent("Change Amount", "Shift in note, either up or down (-1 to 1)"));
RenderSlider(+0, +1, parameters.changeSpeed, (value => parameters.changeSpeed = value), new GUIContent("Change Speed", "How fast the note shift happens (only happens once) (0 to 1)"));
// BFXR
RenderSlider(+0, +1, parameters.overtones, (value => parameters.overtones = value), new GUIContent("Harmonics", "Overlays copies of the waveform with copies and multiples of its frequency. Good for bulking out or otherwise enriching the texture of the sounds (warning: this is the number 1 cause of usfxr slowdown!) (0 to 1)"));
RenderSlider(+0, +1, parameters.overtoneFalloff, (value => parameters.overtoneFalloff = value), new GUIContent("Harmonics falloff", "The rate at which higher overtones should decay (0 to 1)"));

RenderHeading("Tone Change/Pitch Jump");
// BFXR
RenderSlider(+0, +1, parameters.changeRepeat, (value => parameters.changeRepeat = value), new GUIContent("Change Repeat Speed", "Larger Values means more pitch jumps, which can be useful for arpeggiation (0 to 1)"));

RenderSlider(-1, +1, parameters.changeAmount, (value => parameters.changeAmount = value), new GUIContent("Change Amount 1", "Shift in note, either up or down (-1 to 1)"));
RenderSlider(+0, +1, parameters.changeSpeed, (value => parameters.changeSpeed = value), new GUIContent("Change Speed 1", "How fast the note shift happens (only happens once) (0 to 1)"));

// BFXR
RenderSlider(-1, +1, parameters.changeAmount2, (value => parameters.changeAmount2 = value), new GUIContent("Change Amount 2", "Shift in note, either up or down (-1 to 1)"));
RenderSlider(+0, +1, parameters.changeSpeed2, (value => parameters.changeSpeed2 = value), new GUIContent("Change Speed 2", "How fast the note shift happens (only happens once) (0 to 1)"));

RenderHeading("Square Waves");
RenderSlider(+0, +1, parameters.squareDuty, (value => parameters.squareDuty = value), new GUIContent("Square Duty", "Controls the ratio between the up and down states of the square wave, changing the tibre (0 to 1)"), isSquareWaveType);
Expand All @@ -251,11 +275,14 @@ public bool RenderParameters(SfxrParams parameters) {
RenderSlider(+0, +1, parameters.lpFilterResonance, (value => parameters.lpFilterResonance = value), new GUIContent("Low-Pass Resonance", "Changes the attenuation rate for the low-pass filter, changing the timbre (0 to 1)"));
RenderSlider(+0, +1, parameters.hpFilterCutoff, (value => parameters.hpFilterCutoff = value), new GUIContent("High-Pass Cutoff", "Frequency at which the high-pass filter starts attenuating lower frequencies (0 to 1)"));
RenderSlider(-1, +1, parameters.hpFilterCutoffSweep, (value => parameters.hpFilterCutoffSweep = value), new GUIContent("High-Pass Cutoff Sweep", "Sweeps the high-pass cutoff up or down (-1 to 1)"));
}
finally
{
if (EditorGUI.EndChangeCheck())
{

RenderHeading("Bit Crushing");

// BFXR
RenderSlider(+0, +1, parameters.bitCrush, (value => parameters.bitCrush = value), new GUIContent("Bit Crush", "Resamples the audio at a lower frequency (0 to 1)"));
RenderSlider(-1, +1, parameters.bitCrushSweep, (value => parameters.bitCrushSweep = value), new GUIContent("Bit Crush Sweep", "Sweeps the Bit Crush filter up or down (-1 to 1)"));
} finally {
if (EditorGUI.EndChangeCheck()) {
parameters.paramsDirty = true;
mustPlaySound = true;
}
Expand All @@ -264,8 +291,7 @@ public bool RenderParameters(SfxrParams parameters) {
return mustPlaySound;
}

protected static void RenderHeading(string heading)
{
protected static void RenderHeading(string heading) {
EditorGUILayout.LabelField(heading, EditorStyles.boldLabel);
}

Expand All @@ -274,7 +300,7 @@ protected static bool RenderButton(
Action valueChangeAction = null,
bool? isEnabled = null,
params GUILayoutOption[] options)
{
{
if (content == null)
{
content = GUIContent.none;
Expand Down
10 changes: 5 additions & 5 deletions samples/SpaceGame/Assets/Scripts/usfxr/SfxrAudioPlayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class SfxrAudioPlayer : MonoBehaviour {
/**
* SfxrAudioPlayer
* This is the (internal) behavior script responsible for streaming audio to the engine
*
*
* @author Zeh Fernando
*/

Expand All @@ -38,11 +38,11 @@ public class SfxrAudioPlayer : MonoBehaviour {

// Instances
private SfxrSynth sfxrSynth; // SfxrSynth instance that will generate the audio samples used by this


// ================================================================================================================
// INTERNAL INTERFACE ---------------------------------------------------------------------------------------------

void Start() {
// Creates an empty audio source so this GameObject can receive audio events
AudioSource soundSource = gameObject.AddComponent<AudioSource>();
Expand All @@ -65,7 +65,7 @@ void OnAudioFilterRead(float[] __data, int __channels) {

if (!isDestroyed && !needsToDestroy && sfxrSynth != null) {
bool hasMoreSamples = sfxrSynth.GenerateAudioFilterData(__data, __channels);

// If no more samples are needed, there's no more need for this GameObject so schedule a destruction (cannot do this in this thread)
if (!hasMoreSamples) {
needsToDestroy = true;
Expand All @@ -78,7 +78,7 @@ void OnAudioFilterRead(float[] __data, int __channels) {
}
}
}


// ================================================================================================================
// PUBLIC INTERFACE -----------------------------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class SfxrCacheSurrogate : MonoBehaviour {
/**
* SfxrCacheSurrogate
* This is the (internal) behavior script responsible for calling Coroutines for asynchronous audio generation
*
*
* @author Zeh Fernando
*/

Expand Down
Loading

0 comments on commit eb354bd

Please sign in to comment.