222 lines
6.1 KiB
C++
222 lines
6.1 KiB
C++
/*********************************************************************************/
|
|
/*!
|
|
@file Chord.h
|
|
|
|
@brief Find the all the chords in a piece of music.
|
|
|
|
@author L. J. Barman
|
|
|
|
Copyright (c) 2008-2013, L. J. Barman, all rights reserved
|
|
|
|
This file is part of the PianoBooster application
|
|
|
|
PianoBooster is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
PianoBooster is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with PianoBooster. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
/*********************************************************************************/
|
|
|
|
#ifndef __CHORD_H__
|
|
#define __CHORD_H__
|
|
|
|
#include <assert.h>
|
|
|
|
#include "Cfg.h"
|
|
#include "MidiFile.h"
|
|
#include "Queue.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//! @brief The part for each hand uses a different midi channel
|
|
typedef enum
|
|
{
|
|
PB_PART_both = 200, // keep well clear of real midi channels
|
|
PB_PART_right,
|
|
PB_PART_left,
|
|
PB_PART_none,
|
|
} whichPart_t;
|
|
|
|
#define MAX_CHORD_NOTES 20 // The maximum notes in a chord well we only have 10 fingers
|
|
|
|
class CNote
|
|
{
|
|
public:
|
|
CNote()
|
|
{
|
|
m_part = PB_PART_none;
|
|
m_pitch = 0;
|
|
m_duration = 0;
|
|
}
|
|
|
|
CNote(whichPart_t part, int note, int duration = 0)
|
|
{
|
|
m_part = part;
|
|
m_pitch = note;
|
|
m_duration = duration;
|
|
}
|
|
|
|
static void reset();
|
|
|
|
void transpose(int amount)
|
|
{
|
|
m_pitch += amount;
|
|
}
|
|
int pitch() {return m_pitch;}
|
|
whichPart_t part() {return m_part;}
|
|
void setPart(whichPart_t part) {m_part = part;}
|
|
|
|
static whichPart_t findHand(CMidiEvent midi, int whichChannel, whichPart_t whichPart);
|
|
|
|
static void setRightHandTrack(int channel, int rightHandTrackNumber) {
|
|
m_rightHandTrack[channel] = rightHandTrackNumber;
|
|
}
|
|
|
|
static int rightHandTrack(int channel) { return m_rightHandTrack[channel]; }
|
|
|
|
static void setChannelHands(int left, int right);
|
|
static void setActiveHand(whichPart_t hand){m_activeHand = hand;}
|
|
static whichPart_t getActiveHand(){return m_activeHand;}
|
|
|
|
static int rightHandChan() {return m_rightHandChannel;}
|
|
static int leftHandChan() {return m_leftHandChannel;}
|
|
static int bothHandsChan() {return m_leftHandChannel;}
|
|
static int getHandChannel(whichPart_t whichPart) { return (whichPart == PB_PART_right) ? m_rightHandChannel : m_leftHandChannel;}
|
|
static bool hasPianoPart(int chan) { return (m_leftHandChannel == chan || m_rightHandChannel == chan ) ? true : false;}
|
|
|
|
private:
|
|
whichPart_t m_part;
|
|
int m_pitch;
|
|
int m_duration;
|
|
static int m_leftHandChannel;
|
|
static int m_rightHandChannel;
|
|
static whichPart_t m_activeHand;
|
|
// -1 means there is a single track and no separate left and right hand parts
|
|
static int m_rightHandTrack[MAX_MIDI_CHANNELS];
|
|
};
|
|
|
|
class CNoteRange
|
|
{
|
|
public:
|
|
|
|
int highestNote; // The highest note in the range (often on the users piano keyboard)
|
|
int lowestNote;
|
|
};
|
|
|
|
class CChord
|
|
{
|
|
public:
|
|
CChord()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
CNote getNote(int index) {return m_notes[index];}
|
|
int length() {return m_length;}
|
|
void setDeltaTime(int delta) {m_deltaTime = delta;}
|
|
int getDeltaTime() {return m_deltaTime;}
|
|
void clear() { m_length = 0; m_deltaTime = 0;}
|
|
void addNote(whichPart_t part, int note, int duration = 0);
|
|
bool removeNote(int note);
|
|
bool searchChord(int note, int transpose = 0);
|
|
int trimOutOfRangeNotes(int transpose);
|
|
|
|
void transpose(int amount)
|
|
{
|
|
for (int i = 0; i < m_length; i++)
|
|
{
|
|
m_notes[i].transpose(amount);
|
|
}
|
|
}
|
|
|
|
static void setPianoRange(int lowestNote, int highestNote ){
|
|
m_cfg_highestPianoNote = highestNote; // The highest note on the users piano keyboard;
|
|
m_cfg_lowestPianoNote = lowestNote;
|
|
}
|
|
|
|
static bool isNotePlayable(int note, int transpose )
|
|
{
|
|
note += transpose;
|
|
if (note >= m_cfg_lowestPianoNote && note <= m_cfg_highestPianoNote)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
static bool isPianistNote(CMidiEvent midi, int transpose, int whichChannel)
|
|
{
|
|
whichPart_t whichPart = CNote::getActiveHand();
|
|
|
|
int note = midi.note();
|
|
whichPart_t hand = CNote::findHand( midi, whichChannel, whichPart );
|
|
if (hand == PB_PART_none) {
|
|
return false;
|
|
}
|
|
|
|
return CChord::isNotePlayable(note, transpose);
|
|
}
|
|
|
|
static bool isHandPlayable(whichPart_t hand)
|
|
{
|
|
if (CNote::getActiveHand() == PB_PART_both)
|
|
return true;
|
|
if (CNote::getActiveHand() == hand)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
private:
|
|
int m_deltaTime;
|
|
|
|
CNote m_notes[MAX_CHORD_NOTES];
|
|
int m_length;
|
|
static int m_cfg_highestPianoNote; // The highest note on the users piano keyboard;
|
|
static int m_cfg_lowestPianoNote;
|
|
};
|
|
|
|
// Define a chord
|
|
class CFindChord
|
|
{
|
|
public:
|
|
CFindChord()
|
|
{
|
|
reset();
|
|
}
|
|
|
|
void reset()
|
|
{
|
|
m_noteGapTime = 0;
|
|
m_cordSpanGapTime = 0;
|
|
m_completeChord.clear();
|
|
m_currentChord.clear();
|
|
m_cfg_ChordNoteGap = CMidiFile::ppqnAdjust(static_cast<float>(Cfg::chordNoteGap()));
|
|
m_cfg_ChordMaxLength = CMidiFile::ppqnAdjust(static_cast<float>(Cfg::chordMaxLength()));
|
|
}
|
|
|
|
CChord getChord()
|
|
{
|
|
CChord chord;
|
|
chord = m_completeChord;
|
|
m_completeChord.clear();
|
|
return chord;
|
|
}
|
|
|
|
bool findChord(CMidiEvent midi, int channel, whichPart_t part);
|
|
private:
|
|
int m_noteGapTime;
|
|
int m_cordSpanGapTime;
|
|
CChord m_currentChord;
|
|
CChord m_completeChord;
|
|
int m_cfg_ChordNoteGap;
|
|
int m_cfg_ChordMaxLength;
|
|
};
|
|
|
|
#endif // __CHORD_H__
|