Skip to content

Commit

Permalink
Fix: SongPlayer working properly for the first time after the last bi…
Browse files Browse the repository at this point in the history
…g refactor.
  • Loading branch information
macabrett committed May 31, 2020
1 parent 00a1266 commit a883de8
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 28 deletions.
42 changes: 24 additions & 18 deletions Examples/SynthTest/SynthGame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ protected override void Initialize() {
base.Initialize();

this._graphics.IsFullScreen = false;
this._graphics.PreferredBackBufferHeight = 768;
this._graphics.PreferredBackBufferWidth = 1024;
this._graphics.PreferredBackBufferHeight = 1080;
this._graphics.PreferredBackBufferWidth = 1920;
this._graphics.ApplyChanges();
this.IsMouseVisible = true;
}
Expand Down Expand Up @@ -62,27 +62,33 @@ private Song CreateSong() {

var firstTrack = song.Tracks.First();
firstTrack.Instrument.Oscillator = new SawToothOscillator();
firstTrack.Instrument.NoteEnvelope.Attack = 50;
firstTrack.Instrument.NoteEnvelope.Release = 50;
firstTrack.LeftChannelVolume = 0.25f;
firstTrack.RightChannelVolume = 0.75f;

firstTrack.AddNote(0f, 1f, Note.C);
firstTrack.AddNote(1f, 1f, Note.F);
firstTrack.AddNote(2f, 1f, Note.G);
firstTrack.AddNote(3f, 1f, Note.C);
var secondTrack = song.AddTrack();
secondTrack.Instrument.Oscillator = new SineWaveOscillator();
secondTrack.Instrument.NoteEnvelope.Attack = 100;
secondTrack.Instrument.NoteEnvelope.Release = 500;
secondTrack.LeftChannelVolume = 0.75f;
secondTrack.RightChannelVolume = 0.25f;

//var secondTrack = song.AddTrack();
//secondTrack.Instrument.Oscillator = new SineWaveOscillator();
//secondTrack.LeftChannelVolume = 0.75f;
//secondTrack.RightChannelVolume = 0.25f;
for (var i = 0; i < 4; i++) {
firstTrack.AddNote((4f * i) + 0f, 1f, Note.C);
firstTrack.AddNote((4f * i) + 1f, 1f, Note.F);
firstTrack.AddNote((4f * i) + 2f, 1f, Note.G);
firstTrack.AddNote((4f * i) + 3f, 1f, Note.C);

//firstTrack.AddSlideNote(0f, 0.5f, new Frequency(Note.C, Pitch.Low), new Frequency(Note.C, Pitch.Normal), 1f);
//firstTrack.AddSlideNote(0.5f, 0.5f, new Frequency(Note.C, Pitch.Low), new Frequency(Note.C, Pitch.Normal), 1f);
//firstTrack.AddSlideNote(1f, 0.5f, new Frequency(Note.F, Pitch.Low), new Frequency(Note.F, Pitch.Normal), 1f);
//firstTrack.AddSlideNote(1.5f, 0.5f, new Frequency(Note.F, Pitch.Low), new Frequency(Note.F, Pitch.Normal), 1f);
//firstTrack.AddSlideNote(2f, 0.5f, new Frequency(Note.G, Pitch.Low), new Frequency(Note.G, Pitch.Normal), 1f);
//firstTrack.AddSlideNote(2.5f, 0.5f, new Frequency(Note.G, Pitch.Low), new Frequency(Note.G, Pitch.Normal), 1f);
//firstTrack.AddSlideNote(3f, 0.5f, new Frequency(Note.C, Pitch.Low), new Frequency(Note.C, Pitch.Normal), 1f);
//firstTrack.AddSlideNote(3.5f, 0.5f, new Frequency(Note.C, Pitch.Low), new Frequency(Note.C, Pitch.Normal), 1f);
secondTrack.AddSlideNote((4f * i) + 0f, 0.4f, new Frequency(Note.C, Pitch.Low), new Frequency(Note.C, Pitch.Normal), 1f);
secondTrack.AddSlideNote((4f * i) + 0.5f, 0.4f, new Frequency(Note.C, Pitch.Low), new Frequency(Note.C, Pitch.Normal), 1f);
secondTrack.AddSlideNote((4f * i) + 1f, 0.4f, new Frequency(Note.F, Pitch.Low), new Frequency(Note.F, Pitch.Normal), 1f);
secondTrack.AddSlideNote((4f * i) + 1.5f, 0.4f, new Frequency(Note.F, Pitch.Low), new Frequency(Note.F, Pitch.Normal), 1f);
secondTrack.AddSlideNote((4f * i) + 2f, 0.4f, new Frequency(Note.G, Pitch.Low), new Frequency(Note.G, Pitch.Normal), 1f);
secondTrack.AddSlideNote((4f * i) + 2.5f, 0.4f, new Frequency(Note.G, Pitch.Low), new Frequency(Note.G, Pitch.Normal), 1f);
secondTrack.AddSlideNote((4f * i) + 3f, 0.4f, new Frequency(Note.C, Pitch.High), new Frequency(Note.C, Pitch.Normal), 1f);
secondTrack.AddSlideNote((4f * i) + 3.5f, 0.4f, new Frequency(Note.C, Pitch.High), new Frequency(Note.C, Pitch.Normal), 1f);
}

return song;
}
Expand Down
15 changes: 13 additions & 2 deletions Framework/Audio/Synthesizer/LiveVoice.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
namespace Macabre2D.Framework {

/// <summary>
/// A live voice that isn't necesarrily tied to a real note instance.
/// </summary>
public sealed class LiveVoice : Voice {
private bool _isPlaying = false;
private ulong _samplesBeforeRelease = 0;

/// <summary>
/// Gets the frequency.
/// </summary>
/// <value>The frequency.</value>
public Frequency Frequency {
get {
return this.Note.StartFrequency;
}
}

public override void Reinitialize(Song song, Track track, NoteInstance note, float offset = 0f) {
base.Reinitialize(song, track, note, offset);
/// <inheritdoc/>
public override void Reinitialize(Song song, Track track, NoteInstance note, float startingBeat = 0f) {
base.Reinitialize(song, track, note, startingBeat);

this._isPlaying = true;
this._samplesBeforeRelease = 0;
}

/// <summary>
/// Stops this instance.
/// </summary>
public void Stop() {
this._isPlaying = false;
this._samplesBeforeRelease = 0;
Expand Down
18 changes: 16 additions & 2 deletions Framework/Audio/Synthesizer/Song.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,22 @@ public ushort BeatsPerMinute {

set {
this._beatsPerMinute = value.Clamp(MinimumBeatsPerMinute, MaximummBeatsPerMinute);
this.BeatsPerSecond = this._beatsPerMinute / 60f;
}
}

/// <summary>
/// Gets the beats per second.
/// </summary>
/// <value>The beats per second.</value>
public float BeatsPerSecond { get; private set; } = 120f / 60f;

/// <summary>
/// Gets the inverse sample rate.
/// </summary>
/// <value>The inverse sample rate.</value>
public float InverseSampleRate { get; private set; } = 1f / MaximumSampleRate;

/// <summary>
/// Gets the length.
/// </summary>
Expand All @@ -66,6 +79,7 @@ public ushort SampleRate {

set {
this._sampleRate = value.Clamp(MinimumSampleRate, MaximumSampleRate);
this.InverseSampleRate = 1f / this._sampleRate;
}
}

Expand Down Expand Up @@ -95,7 +109,7 @@ public Track AddTrack() {
/// <param name="beats">The beats.</param>
/// <returns>The number of samples within the beat length.</returns>
public ulong ConvertBeatsToSamples(float beats) {
return (ulong)Math.Floor((this.SampleRate * 60f * beats) / this.BeatsPerMinute);
return (ulong)Math.Floor((this.SampleRate * beats) / this.BeatsPerSecond);
}

/// <summary>
Expand All @@ -104,7 +118,7 @@ public ulong ConvertBeatsToSamples(float beats) {
/// <param name="numberOfSamples">The number of samples.</param>
/// <returns>The length of the beat that the number of samples encompass.</returns>
public float ConvertSamplesToBeats(ushort numberOfSamples) {
return (this.BeatsPerMinute * numberOfSamples) / (this.SampleRate * 60f);
return this.BeatsPerSecond * numberOfSamples * this.InverseSampleRate;
}

/// <summary>
Expand Down
4 changes: 2 additions & 2 deletions Framework/Audio/Synthesizer/SongPlayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,15 @@ public void Buffer(float volume, ushort numberOfSamples) {
if (endOfBuffer > this.Song.Length) {
endOfBuffer = this.Song.Length;
beatLengthOfBuffer = endOfBuffer - this._currentBeat;
numberOfSamples = (ushort)this.Song.ConvertBeatsToSamples(beatLengthOfBuffer);
}

var range = new RangeVector(this._currentBeat, endOfBuffer);
foreach (var track in this.Song.Tracks) {
var notes = track.GetNotes(range);

foreach (var note in notes) {
var offset = note.Beat - this._currentBeat;
var voice = this._voicePool.GetNext(this.Song, track, note, offset);
var voice = this._voicePool.GetNext(this.Song, track, note, this._currentBeat);
voice.OnFinished += this.Voice_OnFinished;
this._activeVoices.Add(voice);
}
Expand Down
5 changes: 1 addition & 4 deletions Framework/Audio/Synthesizer/Voice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
/// A synthesizer voice. These are pooled and used to play notes to completion.
/// </summary>
public class Voice : IDisposable, IVoice {
private float _inverseSampleRate;
private bool _isActive;
private bool _isDisposed = false;
private ulong _noteLengthInSamples;
Expand Down Expand Up @@ -49,7 +48,7 @@ public AudioSample[] GetBuffer(ushort numberOfSamples) {
if (this._isActive && sampleNumber >= 0) {
var frequency = this.Note.GetFrequency((sampleNumber / (float)this._noteLengthInSamples).Clamp(0f, 1f));
var volume = this.GetSampleAmplitude((ulong)sampleNumber);
var time = sampleNumber * this._inverseSampleRate;
var time = sampleNumber * this._song.InverseSampleRate;
var leftSample = this.Instrument.Oscillator.GetSignal(time, frequency, volume * this._track.LeftChannelVolume);
var rightSample = this.Instrument.Oscillator.GetSignal(time, frequency, volume * this._track.RightChannelVolume);

Expand Down Expand Up @@ -86,10 +85,8 @@ public virtual void Reinitialize(Song song, Track track, NoteInstance note, floa
this._noteLengthInSamples = this._song.ConvertBeatsToSamples(this.Note.Length);
this._preReleaseVolume = 0f;
this._peakAmplitude = this.Envelope.Decay > 0 ? this.Envelope.PeakAmplitude : this.Envelope.SustainAmplitude;
this._inverseSampleRate = 1f / this._song.SampleRate;
}

// To detect redundant calls
protected virtual void Dispose(bool disposing) {
if (!this._isDisposed) {
this.OnFinished = null;
Expand Down

0 comments on commit a883de8

Please sign in to comment.