Ejemplo n.º 1
0
        public NoteChannelController(OrganyaPlayerContext context, OrganyaInstrument instrument, bool isDrum)
        {
            currentNoteIndex   = 0;
            currentSampleIndex = 0;
            var pitchBend = instrument.FineTune - PITCH_BEND_NORMALIZATION_FACTOR;

            var tempNotes = new List <NoteEvent>();

            foreach (var note in instrument.Notes)
            {
                var adjustedInstrumentIndex = isDrum? instrument.InstrumentIndex + 100 : instrument.InstrumentIndex;
                NoteEventController prov    = new NoteEventController(context, note, adjustedInstrumentIndex,
                                                                      pitchBend, isDrum, instrument.DisableSustain);

                tempNotes.Add(new NoteEvent()
                {
                    Note        = prov,
                    StepOffset  = note.BeatNumber,
                    LengthSteps = note.Length
                }
                              );
            }

            _notes = tempNotes.OrderBy(
                (ne) => ne.StepOffset
                ).ToList();
        }
Ejemplo n.º 2
0
        //TODO: Add reset() for looping.

        public float[] RequestBuffer(OrganyaPlayerContext context, long lengthSamples)
        {
            float[] sampleBuffer = new float[lengthSamples];

            if (_notes.Count == 0) //Skip if there's no notes to play.
            {
                return(sampleBuffer);
            }

            float l, r;

            for (int i = 0; i < lengthSamples; i += 2)
            {
                //Bounds checking - make sure that we don't crash the program at the end of the song.
                if (this.currentNoteIndex >= _notes.Count)
                {
                    break;
                }

                var activeNote  = _notes[this.currentNoteIndex];
                var currentBeat = Utilities.SamplesToSteps(this.currentSampleIndex, context.StepMsec, context.Config.SampleRate);

                //Check if the other note is overlapping this note.
                //When two notes overlap (common - comment this out and listen to Jenka 1), the second note should always play.
                //TODO: Figure out if this is necessary, or only maskign a bug.
                if (this.currentNoteIndex + 1 < _notes.Count && currentBeat == _notes[currentNoteIndex + 1].StepOffset)
                {
                    activeNote = _notes[this.currentNoteIndex + 1];
                    currentNoteIndex++;
                }

                if (currentBeat > activeNote.StepOffset + activeNote.LengthSteps)
                {
                    //The note is done playing. Advance to the last note unless this is the last one.
                    currentNoteIndex++;

                    if (currentNoteIndex < _notes.Count)
                    {
                        activeNote = _notes[currentNoteIndex];
                    }
                }

                if (currentBeat >= activeNote.StepOffset)
                {
                    //We've advanced to the correct note at this point and it's active, so play it.
                    activeNote.Note.RequestSample(out l, out r);
                    sampleBuffer[i]     = l;
                    sampleBuffer[i + 1] = r;
                }
                else
                {
                    sampleBuffer[i] = sampleBuffer[i + 1] = 0;
                }

                currentSampleIndex++;
            }
            return(sampleBuffer);
        }
Ejemplo n.º 3
0
        public OrganyaSongPlayer(SampleProviderConfiguration config, OrganyaSong song,
                                 WavetableSampleLoader sampleLoader)
        {
            _context      = new OrganyaPlayerContext(config, song, sampleLoader);
            _noteChannels = new List <NoteChannelController>();

            for (int i = 0; i < song.Tracks.Count; i++)
            {
                var  track   = song.Tracks[i];
                bool isDrum  = i >= 8;
                var  channel = new NoteChannelController(_context, track, isDrum);
                _noteChannels.Add(channel);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="OrgPlay.SampleController.WavetableNoteSampleProvider"/> class.
        /// </summary>
        /// <param name="context">Context.</param>
        /// <param name="note">Note.</param>
        /// <param name="bankNumber">Bank number.</param>
        /// <param name="pitchBendNormalized">Pitch bend normalized.</param>
        /// <param name="drum">If set to <c>true</c> drum.</param>
        /// <param name="pi">If set to <c>true</c> pi.</param>
        public NoteEventController(OrganyaPlayerContext context, OrganyaNote note, int bankNumber,
                                   int pitchBendNormalized, bool drum, bool pi)
        {
            _sample        = context.SampleLoader.Load(bankNumber);
            samplePosition = 0;
            samplesPlayed  = 0;

            var pitchIndex = note.Pitch % KEYS_IN_OCTAVE;

            _octave = note.Pitch / KEYS_IN_OCTAVE;

            _volumeNormalized = (float)Math.Pow(10, ((float)note.Volume / 254) - 1);
            _panNormalized    = ((float)(note.Pan - 6)) / 6.0f;

            var samplePointFrequency = NOTE_POINT_FREQS[pitchIndex] + pitchBendNormalized;

            _normalizedSampleSpeed = samplePointFrequency / ((float)POINT_FREQ_RELATIVE_TO_SAMPLE_FREQ);

            if (drum)
            {
                //TODO: Not sure how drums are affected by pitch.

                //_normalizedSampleSpeed = 1.0f; //Do drums play at a constant point frequency?
                float stretchFactor = ((float)OCTAVE_REPEAT_TIMES[_octave]) / ((float)OCTAVE_ADVANCE_POINTS[_octave]);
                _lengthSamples = (int)(((float)_sample.Samples.Length / _normalizedSampleSpeed) * stretchFactor);
            }
            else if (pi)
            {
                //Is this correct? It should play a constant amount of samples I think.
                _lengthSamples = 256;
                //TODO: Lengths are given as periods in the notes page explanation of the 'pi' option.
            }
            else
            {
                //In this case, we know how long this'll have to be in samples.
                _lengthSamples = Utilities.StepsToSamples(note.Length, context.StepMsec, context.Config.SampleRate);
            }
        }