/// <summary> /// Initializes a new instance of the <see cref="Note"/> class. /// </summary> /// <param name="audioBuffer">The audioBuffer to fill<see cref="List{float}"/></param> /// <param name="sampleRate">The sampleRate<see cref="int"/></param> /// <param name="oscillator">The oscillator reference<see cref="Oscillator"/></param> /// <param name="duration">The duration of the note<see cref="float"/></param> /// <param name="volume">The volume of the note<see cref="byte"/></param> /// <param name="waveform">The waveform of the note<see cref="byte"/></param> /// <param name="pitch">The pitch of the note<see cref="byte"/></param> /// <param name="pitchFrom">The pitch to start the note from<see cref="int"/></param> /// <param name="fadeIn">The fadeIn length<see cref="float"/></param> /// <param name="fadeOut">The fadeOut length<see cref="float"/></param> /// <param name="vibrato">If it should have a vibrato effect<see cref="bool"/></param> public Note(ref List <float> audioBuffer, int sampleRate, ref Oscillator oscillator, float duration, byte volume, byte waveform, byte pitch, int pitchFrom = -1, float fadeIn = 1, float fadeOut = 1, bool vibrato = false) { _audioBuffer = audioBuffer; _duration = duration; _sampleRate = sampleRate; _fadeIn = fadeIn * duration / 100.0f; _fadeOut = fadeOut * duration / 100.0f; _timePassed = 0.0f; _volume = 1; isCustom = waveform > 7; targetVolume = volume / 7.0f; this.waveform = waveform; this.pitch = pitch; if (pitchFrom == -1) { _pitchFrom = pitch; } else { _pitchFrom = pitchFrom; } _oscillator = oscillator; _vibrato = vibrato; }
/// <summary> /// Initializes a new instance of the <see cref="MusicPlayer"/> class. /// </summary> /// <param name="memory">The memory unit reference<see cref="MemoryUnit"/></param> /// <param name="audioBuffer">The audioBuffer reference<see cref="List{float}"/></param> /// <param name="sampleRate">The sampleRate for the music<see cref="int"/></param> public MusicPlayer(ref MemoryUnit memory, ref List <float> audioBuffer, int sampleRate) { sfxs = new Sfx[4] { null, null, null, null }; isPlaying = false; _ram = memory.ram; _audioBuffer = audioBuffer; _sampleRate = sampleRate; _oscillator = new Oscillator(_sampleRate); patternData = new PatternData[64]; for (int i = 0; i < patternData.Length; i += 1) { byte[] vals = { _ram[i * 4 + 0 + util.ADDR_SONG], _ram[i * 4 + 1 + util.ADDR_SONG], _ram[i * 4 + 2 + util.ADDR_SONG], _ram[i * 4 + 3 + util.ADDR_SONG] }; if ((vals[0] & 0x80) == 0x80) { patternData[i].loopStart = true; } if ((vals[1] & 0x80) == 0x80) { patternData[i].loopEnd = true; } if ((vals[2] & 0x80) == 0x80) { patternData[i].shouldStop = true; } patternData[i].channels = new ChannelData[4]; for (int j = 0; j < 4; j += 1) { patternData[i].channels[j] = new ChannelData(); if ((vals[j] & 0b01000000) != 0) { patternData[i].channels[j].isSilent = true; } patternData[i].channels[j].sfxIndex = (byte)(vals[j] & 0b00111111); } } }
/// <summary> /// Initializes a new instance of the <see cref="Sfx"/> class. /// </summary> /// <param name="_sfxData">The _sfxData to use<see cref="byte[]"/></param> /// <param name="_sfxIndex">The _sfxIndex that this sfx references to<see cref="int"/></param> /// <param name="audioBuffer">The audioBuffer to fill with data<see cref="List{float}"/></param> /// <param name="oscillator">The oscillator reference<see cref="Oscillator"/></param> /// <param name="sampleRate">The sampleRate<see cref="int"/></param> /// <param name="audioBufferIndex">The index to start filling the audio buffer<see cref="int"/></param> public Sfx(byte[] _sfxData, int _sfxIndex, ref List <float> audioBuffer, ref Oscillator oscillator, int sampleRate, int audioBufferIndex = 0) { notes = new P8Note[32]; _audioBuffer = audioBuffer; duration = _sfxData[65] / 120.0f; startLoop = _sfxData[66]; endLoop = _sfxData[67]; _sampleRate = sampleRate; sfxIndex = _sfxIndex; _oscillator = oscillator; Console.WriteLine($"header {_sfxData[64]} {_sfxData[65]} {_sfxData[66]} {_sfxData[67]}"); for (int i = 0; i < _sfxData.Length - 4; i += 2) { byte lo = _sfxData[i]; byte hi = _sfxData[i + 1]; notes[i / 2].pitch = (byte)(lo & 0b00111111); notes[i / 2].waveform = (byte)(((lo & 0b11000000) >> 6) | ((hi & 0b1) << 2)); notes[i / 2].volume = (byte)((hi & 0b00001110) >> 1); notes[i / 2].effect = (byte)((hi & 0b01110000) >> 4); notes[i / 2].isCustom = (byte)((hi & 0b10000000) >> 7) == 1; Console.WriteLine($"{i} {notes[i / 2].pitch} {notes[i / 2].waveform} {notes[i / 2].volume} {notes[i / 2].effect} {notes[i / 2].isCustom}"); } oscillator = new Oscillator(sampleRate); notesToPlay = new Queue <Note>(); this.audioBufferIndex = audioBufferIndex; isActive = true; _fadeIn = 0.05f / duration; }
/// <summary> /// play sfx n on channel (0..3) from note offset (0..31) for length notes /// n -1 to stop sound on that channel /// n -2 to release sound on that channel from looping /// Any music playing on the channel will be halted /// offset in number of notes(0..31) /// channel -1 (default) to automatically choose a channel that is not being used /// channel -2 to stop the sound from playing on any channel /// </summary> /// <param name="n">The sfx number<see cref="int"/></param> /// <param name="channel">The channel to play the sfx in<see cref="int?"/></param> /// <param name="offset">The offset note to start playing from<see cref="int?"/></param> /// <param name="length">The length of the sfx to play<see cref="int?"/></param> /// <returns>The <see cref="object"/></returns> public object Sfx(int n, int?channel = -1, int?offset = 0, int?length = 32) { switch (n) { case -1: if (channel == -1) { StopAllChannels(); break; } if (channel < 0 || channel >= channelCount) { break; } sfxChannels[channel.Value] = null; break; case -2: if (channel.Value < 0 || channel.Value >= channelCount) { break; } if (sfxChannels[channel.Value] != null) { sfxChannels[channel.Value].loop = false; } break; default: // If sound is already playing, stop it. int?index = FindSoundOnAChannel(n); if (index != null) { sfxChannels[index.Value] = null; } if (channel == -1) { channel = FindAvailableChannel(); if (channel == null) { break; } } if (channel == -2) { break; } byte[] _sfxData = new byte[68]; Buffer.BlockCopy(_memory.ram, util.ADDR_SFX + 68 * n, _sfxData, 0, 68); Oscillator osc = new Oscillator(sampleRate); sfxChannels[channel.Value] = new Sfx(_sfxData, n, ref audioBuffer, ref osc, sampleRate); sfxChannels[channel.Value].currentNote = offset.Value; sfxChannels[channel.Value].lastIndex = offset.Value + length.Value - 1; sfxChannels[channel.Value].Start(); break; } return(null); }