Synthesizer 1.2.0
dotnet add package Synthesizer --version 1.2.0
NuGet\Install-Package Synthesizer -Version 1.2.0
<PackageReference Include="Synthesizer" Version="1.2.0" />
paket add Synthesizer --version 1.2.0
#r "nuget: Synthesizer, 1.2.0"
// Install Synthesizer as a Cake Addin
#addin nuget:?package=Synthesizer&version=1.2.0
// Install Synthesizer as a Cake Tool
#tool nuget:?package=Synthesizer&version=1.2.0
ALGOSUP_2022_Project_3_A | Sound Synthesizer
Project:
The project given by Algosup and Robert Pickering was to create a Sound Synthesizer able to open, modify, create and save sounds.
Getting Started
<br>
Project members
Ivan Molnar <br> Clement Caton <br> Louis de Choulot <br> Théo Diancourt <br> Mathieu Chaput <br> Léo Chartier
Project documentation
Prerequisites
- Download .Net 6.0 or newer
<br>
.Net CLI
dotnet add package Synthesizer --version 1.1.0
<br>
Windows
Install-Package Synthesizer -Version 1.1.0
<br>
Package Reference
<PackageReference Include="Synthesizer" Version="1.1.0" />
<br>
Installation
Basic structure
To interract with the library you'll have to mainly interract with two objects.
The Synth
object which is the actual sound synthesizer and the Filter
object which contains a list of function that will allow you to modify the created sounds.
Reading files
Reading wav files
You can extract data from a wav file in the default /Output/
folder using Synth.ReadFromWav (fileName:string)
.
You can open it from your own path using Synth.readFromWavWithPath (filePath:string)
.
These functions return a tuple containing the soundData:list<list<float>>
, duration:float
, sampleRate:int
and the bitsPerSample:int
.
Example:
let inOutputData, inOutputDuration, inOutputSampleRate, inOutputBPSampleRate = synth.ReadFromWav "yourFileName.wav" // get everything from a file in the Output folder
let fromPathData, _, fromPathSampleRate, _ = Synth.readFromWavWithPath "/yourPath/yourFileName.wav" // get only the sound data and the samplerate from a predefined path
Reading mp3 files
<span style="color: red;">WIP</span>
Writing to files / Saving
Writing wav files
You can save files by writing data into them with the function Synth.WriteToWav name music
. This function will put files in the folder "./Output".
Example :
Synth.WriteToWavWithPath "name.wav" sound// This will save the sound in the file from the path "./Output/name.wav".
You can also save files by writing data into them with the function Synth.WriteToWavWithPath path fileName music
. This function will put files in "path/fileName".
Example :
Synth.WriteToWavWithPath "./folder/" "name.wav" sound // This will save the sound in the file from the path "./folder/name.wav".
Writing mp3 files
<span style="color: red;">WIP</span>
Playing music
Your Os is automatically detected to use either SFML on windows or afplay on Mac, this function does not support Linux yet.
You can play music from the code Synth.PlayWav offset data
.
Example :
Synth.PlayWav 0. data // This will play the sound in the variable data with an offset of 0 second.
You can also play music from a file with Synth.PlayWavFromPath offset (filePath:string)
Example :
Synth.PlayWavFromPath 0. "./Output/name.wav" // This will play the sound in the file from the path "./Output/name.wav" with an offset of 0 second.
Each sound will be played one by one. For the next sound to be played (or to end the program if there aren't any more sounds) you need to press the enter key.
Dealing with stereo
<span style="color: red;">WIP</span>
Creating audio data
You can create some basic audio using Synth.Sound (frequency:float) (duration:Duration) (waveType:BaseWaves)
Example:
let synth = Synth() // Init
let newSound = synth.Sound 440. (Seconds 1.) Sin // Create a 1 second sinwave with a frequence of 440.
let newSound2 synth.Sound (synth.getNoteFreq 3 Note.F) Half Triangular // Create a triangular F3 half note.
Alternatively, it is possible to directly create a note with the synth.Note (duration:Duration) (mNote:Note) (octave:int)
.
Example:
let synth = Synth() // Init
let newNote = synth.Note Quarter Note.D 5 // Create a D5 quarter note.
Creating audio data with an envelope
In order to create a sound with an enveloppe you need to use Synth.SoundWithEnveloppe (frequency:float) (duration:Duration) (waveType:BaseWaves) (sustain:float) (attack:float) (hold:float) (decay:float) (release:float)
.
We are using a basic AHDSR envelope:
Example:
let synth = Synth() // Init
let sound = synth.SoundWithEnveloppe 440. (Seconds 3.) Sin 0.5 0.5 0.5 0.5 0.5 // Create sound with envelope
The above example creats the following sound:
<sup>* Please note: when we create a new sound with this methode the release adds data at the end of the normal data.</sup>
Creating audio data with a custom envelope
<span style="color: red;">WIP</span>
Finding frequencies from notes and octaves
A more simplified way to find the sound you are looking for is trought musical octaves[^1] and notes[^2].
To call on this form of notation you'll have to use the Synth.getNoteFreq (octav:int) (note:Note)
function to get the right frequency.
Example:
let Note = Synth.GetNoteFreq Note.C 4 // This returns the frequency of the C4 note
Alternatively, you could directly create a SinWave using the Synth.note (duration:Duration) (note:Note) (octav:int)
.
Example:
let Note = Synth.Note Half Note.C 4 // This returns the frequency a half duration of the C4 note
Finding notes with a custom default frequency
In most cases, the frequency of a note is calculated from a default frequency (mostly, 440Hz for the A4 note).
However, in some cases, you might need to find a note from a different starting frequency.
This can be done using the Synth.getNoteFreqOffset (octav:int) (note:Note) (aFourFreq:Float)
Example:
let Note = Synth.GetNoteFreqOffset Note.C 4 444. // This returns the frequency of the C4 note calculated from the starting point 444Hz at the A4 note
Creating silence
Creating silence is as simple as calling the Synth.silence (duration:Duration)
function.
let Silence = Synth.Silence (Seconds 2) // Returns 2 seconds of silence
Cutting audio
Cutting audio is simple. You can use the following functions
Synth.cutStart (sampleRate:float) (time:float) (data:List<float>)
: Cuts the start of the audio data returning the end partSynth.cutEnd (sampleRate:float) (time:float) (data:List<float>)
: Cuts the end of the audio data returning the first partSynth.cutMiddle (sampleRate:float) (timeStart:float) (timeEnd:float) (data:List<float>)
: Cuts out the middle of the audio data and returns the edges merged togetherSynth.cutEdge (sampleRate:float) (timeStart:float) (timeEnd:float) (data:List<float>)
: Cuts of both ends of the audio data and returns the middle part
Example:
let a = Synth.note (Seconds 1) Note.A 4
let b = Synth.note (Seconds 1) Note.B 4
let c = Synth.note (Seconds 1) Note.C 4
let d = Synth.note (Seconds 1) Note.D 4
let full = Synth.compose 0 [a; b; c; d;] // Complete sound, takes 4 second and plays 4 different notes
let lastThree = Synth.cutStart 44100. 1. full // Cuts first note, leaving last 3
let firstThree = Synth.cutEnd 44100. 1. full // Cuts last note, leaving first 3
let edges = Synth.cutMiddle 44100. 1. 1. full // Cuts out the 2 middle notes, leaving the first and the last ones
let second = Synth.cutMiddle 44100. 1. 2. full // Cuts the first and the last 2 notes, leaving the second one
Additioning audio data
<span style="color: red;">WIP</span>
Additioning audio with a predefined ratio
<span style="color: red;">WIP</span>
Composing
One thing you have to be aware of is the cutCorners
function.
When we first created the compose function we encounterd a strange, small sound between easch end every note.
This sound was caused by the notes ending on a not-zero amplitude.
The solution was to add in a filter that gradually lowers the amplitude of the notes start and end to 0.
| Before cutCorne | After cutCorner | |:------------------------------------:|:-----------------------------------:| | | | <sup>* for the shake of the example, the filter has been exagerated</sup>
Therefore; theSynth.compose (sounds:List<float>)
function has a default cutCorner value of 100 (this means it cuts away from the first and last 100 bytes from each note).
Example:
let C4 = Synth.Note Half Note.C 4 // init
let D4 = Synth.Note Half Note.D 4 //
let Silence = Synth.Nilence Quarter //
let B5 = Synth.Note Half Note.B 5 //
let Music = Synth.Compose [ // Returns a single, large sound composed of the smaller sounds given to it
C4;
C4;
D4;
Silence;
B5;
]
In certain cases, one might need to set a custom value to the cutCorner function.
This can be done with the Synth.ComposeCutCorner (Corner:int) (Sounds:List<float>)
let Music = Synth.ComposeCutCorner 1000 [
C4;
C4;
D4;
Silence;
B5;
]
Alternatively, one might want to compose without the cutCorners filter.
This can be done either by giving it a 0 value or by using the Synth.composeNoCutCorner (corner:int) (sounds:List<float>)
function.
With zero value:
let Music = Synth.ComposeCutCorner 0 [
C4;
C4;
D4;
Silence;
B5;
]
Or with composeNoCutCorner
:
let Music = Synth.ComposeNoCutCorner [
C4;
C4;
D4;
Silence;
B5;
]
These two are equivalents.
Preview
Its possible to create a preview of ant audio loaded into the filter using the Synth.preview (title:string) (sound:List<float>)
function.
Example:
let basic = Synth.note Whole Note.A 2 // reating a basic note
let cut = Utility.cutCorners 5000 basic // Making it look a bit more interresting
Synth.preview "Example" cut |> ignore // Launch preview
The above example automatically opens the browser with the following image:
Tools to zoom/zoom out are also present on the page.
Frequency analysis
<span style="color: red;">WIP</span>
Filters
Usable Filters
To complement your sounds you can add some filters :
Flanger
Echo
Reverb
Envelope
LFO AM
LFO FM
Low Pass
High Pass
Apply multiple filters at once
You can use this function to apply multi filters at once :
member x.ApplyFilters filters data =
Filter.ApplyFilters filters data
Like so :
let x = Synth()
let MusicWithFilters = x.ApplyFilters [
Filter.ChangeAmplitude 0.5;
Filter.LowPass 44100. 400.;
Filter.Echo 4 0.7 1.5 44100.] Music
Changing amplitude
<span style="color: red;">WIP</span>
Custom repeater filter
The repeater filter does exatly what it says on the tin. It repeats the inputed data with an offset and readds to the original sound. This filter is the basis on which we built the Reverb and Echo filters.
The function looks like this: Filter.Repeater (nbEcho:int) (decay:float) (delay:float) (sampleRate:float) (dryData:List<float>)
The variables inputed are:
- nbEcho: The number of times the original sound gets repeated.
- decay: Each time the sound is repeated we jusge the amplitude of the sound using this value
- delay: The offset added to the echo (multiplies accordingly to the echo ex.: echo 1 will have 1x this value, echo 2 will have 2x this value, etc..)
- sampleRate: The sampleRate of the sound
- dryData: The original sound
Example:
let synth = Synth() // Init
let basicSound = synth.SoundWithEnveloppe 440. (Seconds 3.) Sin 0.5 0.5 0.5 0.5 0.5 // Creating a basic sound with an envelope to make it interresting
let repeated1 = Filter.Repeater 5 0.6 1.5 44100. basicSound
let repeated2 = Filter.Repeater 10 0.9 4. 44100. basicSound
Reverb
<span style="color: red;">WIP</span>
Echo
<span style="color: red;">WIP</span>
Frequency analysis
<span style="color: red;">WIP</span>
Frequency analysis
<span style="color: red;">Wip</span>
Flanger
<span style="color: red;">WIP</span>
Envelope
<span style="color: red;">WIP</span>
Custom envelope
<span style="color: red;">WIP</span>
Low frequency oscillation
<span style="color: red;">WIP</span>
AM
<span style="color: red;">WIP</span>
FM
<span style="color: red;">WIP</span>
LowPass / HighPass / BandPass / RejectBand filters
<span style="color: red;">WIP</span>
Footnotes
Usable notes
The musical notes available are:
C
,Cs / Db
,D
,Ds / Eb
,E
,F
,Fs / Gb
,G
,Gs / Ab
,A
,As / Bb
,B
Possible Waves
The wave types available are:
Sin
,Square
,Triangular
,Saw
,Silence
,CustomInstrument
- The
CustomInstrument
value has a value of(float -> float -> float -> float -> float -> float)
. This is because the wave functions need to be written as:
let waveFunc (frequency:float) (amplitude:float) (verticalShift:float) (phaseShift:float) (timeLength:float)
Duration of elements
The note durations available are:
Whole
,Half
,Quarter
,Eighth
,Sixteenth
,Custom
,Seconds
- The Seconds value takes a float as argument.
- The Custom value takes a float as its argument. This translates using the formula
value *4.* 60. / bpm
. - The tickspead of the durations can be changed by changing the value
Synth.bpm
(default 90).
Unit Test
The tests can be found in the Synthesizer.Test project. To run them you'll have to be located in the project folder and run the dotnet test command.
see also
Info on .mp3 files<br> Info on .Wav files<br> Link to our Trello<br> Link to our Functional Specifications<br> Link to our Technical Specifications<br> Link to our Software Architecture Design Choices
Definitions
[^1]: Octaves: A series of eight notes occupying the interval between (and including) two notes, one having twice or half the frequency of vibration of the other.
[^2]: Notes: A note is a symbol denoting a musical sound.
[^3]: Wave functions:
[^4]: Musical durations:
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net6.0
- FSharp.Core (>= 6.0.1)
- sfml.audio (>= 2.5.0)
- XPlot.Plotly (>= 4.0.6)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|
add Filters