Separate left and right parts contained in different midi tracks.
This commit is contained in:
parent
2667bf360f
commit
3fd6b85b88
|
@ -31,13 +31,34 @@
|
|||
|
||||
int CNote::m_leftHandChannel = -2;
|
||||
int CNote::m_rightHandChannel = -2;
|
||||
int CNote::m_rightHandTrack[MAX_MIDI_CHANNELS];
|
||||
|
||||
whichPart_t CNote::m_activeHand = PB_PART_both;
|
||||
|
||||
int CChord::m_cfg_highestPianoNote = 127; // The highest note on the users piano keyboard;
|
||||
int CChord::m_cfg_lowestPianoNote = 0;
|
||||
|
||||
whichPart_t CNote::findHand(int midiNote, int midiChannel, int whichChannel, whichPart_t whichPart)
|
||||
|
||||
void CNote::reset()
|
||||
{
|
||||
CNote::setChannelHands(-2, -2); // -2 for not set -1 for none
|
||||
|
||||
for (int chan = 0; chan < MAX_MIDI_CHANNELS; chan++) {
|
||||
m_rightHandTrack[chan]=-1;
|
||||
}
|
||||
}
|
||||
|
||||
void CNote::setChannelHands(int left, int right)
|
||||
{
|
||||
m_leftHandChannel = left;
|
||||
m_rightHandChannel = right;
|
||||
}
|
||||
|
||||
|
||||
whichPart_t CNote::findHand(CMidiEvent midi, int whichChannel, whichPart_t whichPart)
|
||||
{
|
||||
int midiNote = midi.note();
|
||||
int midiChannel = midi.channel();
|
||||
whichPart_t hand = PB_PART_none;
|
||||
// exit if it is not for this channel
|
||||
if (midiChannel != whichChannel)
|
||||
|
@ -46,21 +67,18 @@ whichPart_t CNote::findHand(int midiNote, int midiChannel, int whichChannel, whi
|
|||
if (CNote::hasPianoPart(whichChannel) == false || CNote::hasPianoPart(midiChannel) == false)
|
||||
return PB_PART_none;
|
||||
}
|
||||
int rightHandTrack = CNote::rightHandTrack(midiChannel);
|
||||
|
||||
if (midiChannel == CNote::rightHandChan())
|
||||
if (midiChannel == whichChannel && rightHandTrack >= 0 ) {
|
||||
hand = (midi.track() == rightHandTrack) ? PB_PART_right : PB_PART_left ;
|
||||
} else if (midiChannel == CNote::rightHandChan()) {
|
||||
hand = PB_PART_right;
|
||||
else if (midiChannel == CNote::leftHandChan())
|
||||
} else if (midiChannel == CNote::leftHandChan()) {
|
||||
hand = PB_PART_left;
|
||||
else
|
||||
{
|
||||
if (midiChannel == whichChannel)
|
||||
{
|
||||
if (midiNote >= MIDDLE_C)
|
||||
hand = PB_PART_right;
|
||||
else
|
||||
hand = PB_PART_left;
|
||||
}
|
||||
} else if (midiChannel == whichChannel) {
|
||||
hand = (midiNote >= MIDDLE_C) ? PB_PART_right : PB_PART_left ;
|
||||
}
|
||||
|
||||
if (whichPart == PB_PART_left && hand == PB_PART_right)
|
||||
hand = PB_PART_none;
|
||||
if (whichPart == PB_PART_right && hand == PB_PART_left)
|
||||
|
@ -82,11 +100,6 @@ void CChord::addNote(whichPart_t part, int note, int duration)
|
|||
m_length++;
|
||||
}
|
||||
|
||||
void CNote::setChannelHands(int left, int right)
|
||||
{
|
||||
m_leftHandChannel = left;
|
||||
m_rightHandChannel = right;
|
||||
}
|
||||
|
||||
//////////////// CChord /////////////////////
|
||||
|
||||
|
|
29
src/Chord.h
29
src/Chord.h
|
@ -42,7 +42,6 @@ typedef enum
|
|||
PB_PART_both = 200, // keep well clear of real midi channels
|
||||
PB_PART_right,
|
||||
PB_PART_left,
|
||||
PB_PART_accump,
|
||||
PB_PART_all,
|
||||
PB_PART_none,
|
||||
} whichPart_t;
|
||||
|
@ -65,6 +64,9 @@ public:
|
|||
m_pitch = note;
|
||||
m_duration = duration;
|
||||
}
|
||||
|
||||
static void reset();
|
||||
|
||||
void transpose(int amount)
|
||||
{
|
||||
m_pitch += amount;
|
||||
|
@ -73,13 +75,14 @@ public:
|
|||
whichPart_t part() {return m_part;}
|
||||
void setPart(whichPart_t part) {m_part = part;}
|
||||
|
||||
static whichPart_t findHand(int midiNote, int midiChannel, int whichChannel, whichPart_t whichPart);
|
||||
static whichPart_t findHand(CMidiEvent midi, int whichChannel, whichPart_t whichPart);
|
||||
|
||||
static whichPart_t findHand(CMidiEvent midi, int channel, whichPart_t part)
|
||||
{
|
||||
return findHand(midi.note(), midi.channel(), channel, part);
|
||||
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;}
|
||||
|
@ -97,7 +100,8 @@ private:
|
|||
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
|
||||
|
@ -147,6 +151,19 @@ public:
|
|||
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)
|
||||
|
|
|
@ -283,7 +283,7 @@ void CConductor::transpose(int transpose)
|
|||
void CConductor::activatePianistMutePart()
|
||||
{
|
||||
mutePart(PB_PART_all, false);
|
||||
if (m_playMode != PB_PLAY_MODE_listen && m_mutePianistPart == true)
|
||||
if (shouldMutePianistPart())
|
||||
{
|
||||
if (CNote::hasPianoPart(m_activeChannel))
|
||||
{
|
||||
|
@ -451,9 +451,9 @@ void CConductor::playTransposeEvent(CMidiEvent event)
|
|||
(event.type() == MIDI_NOTE_ON || event.type() == MIDI_NOTE_OFF) )
|
||||
event.transpose(m_transpose);
|
||||
|
||||
if (event.type() == MIDI_NOTE_ON && isChannelMuted(event.channel()) == true &&
|
||||
CChord::isNotePlayable(event.note(), m_transpose) == true)
|
||||
if (event.type() == MIDI_NOTE_ON && CChord::isPianistNote(event, m_transpose, getActiveChannel()) && shouldMutePianistPart()) {
|
||||
return; // mute the note by not playing it
|
||||
}
|
||||
|
||||
// boost any volume events
|
||||
if (event.type() == MIDI_CONTROL_CHANGE && event.data1() == MIDI_MAIN_VOLUME)
|
||||
|
|
|
@ -165,6 +165,8 @@ public:
|
|||
}
|
||||
bool hasPianistKeyboardChannel(int chan) { return (m_pianistGoodChan == chan || m_pianistBadChan == chan ) ? true : false;}
|
||||
|
||||
bool shouldMutePianistPart() {return m_playMode != PB_PLAY_MODE_listen && m_mutePianistPart == true;}
|
||||
|
||||
CRating* getRating(){return &m_rating;}
|
||||
|
||||
// You MUST clear the time sig to 0 first before setting an new start time Sig
|
||||
|
|
|
@ -291,7 +291,7 @@ void GuiMidiSetupDialog::on_fluidLoadButton_clicked ( bool checked )
|
|||
}
|
||||
}
|
||||
|
||||
QFileInfo soundFontInfo = QFileDialog::getOpenFileName(this,tr("Open SoundFont File for fluidsynth"),
|
||||
QFileInfo soundFontInfo = QFileDialog::getOpenFileName(this, tr("Open SoundFont File for fluidsynth"),
|
||||
lastSoundFont, tr("SoundFont Files (*.sf2 *.sf3)"));
|
||||
if (!soundFontInfo.isFile()) return;
|
||||
|
||||
|
|
|
@ -155,9 +155,7 @@ void CMidiDeviceFluidSynth::playMidiEvent(const CMidiEvent & event)
|
|||
break;
|
||||
|
||||
case MIDI_NOTE_PRESSURE: //POLY_AFTERTOUCH: 3 bytes
|
||||
//message.push_back( channel | MIDI_NOTE_PRESSURE);
|
||||
//message.push_back( event.data1());
|
||||
//message.push_back( event.data2());
|
||||
//fluid_synth_key_pressure(m_synth, channel, event.data1(), event.data2());
|
||||
break;
|
||||
|
||||
case MIDI_CONTROL_CHANGE: //CONTROL_CHANGE:
|
||||
|
@ -170,15 +168,13 @@ void CMidiDeviceFluidSynth::playMidiEvent(const CMidiEvent & event)
|
|||
break;
|
||||
|
||||
case MIDI_CHANNEL_PRESSURE: //AFTERTOUCH: 2 bytes only
|
||||
//message.push_back( channel | MIDI_CHANNEL_PRESSURE);
|
||||
//message.push_back( event.data1());
|
||||
// FIXME missing
|
||||
fluid_synth_channel_pressure(m_synth, channel, event.programme());
|
||||
break;
|
||||
|
||||
case MIDI_PITCH_BEND: //PITCH_BEND:
|
||||
// a 14 bit number LSB first 0x4000 is the off positions
|
||||
fluid_synth_pitch_bend(m_synth, channel, (event.data2() << 7) | event.data1());
|
||||
break;
|
||||
break;
|
||||
|
||||
case MIDI_PB_collateRawMidiData: //used for a SYSTEM_EVENT
|
||||
if (m_rawDataIndex < arraySize(m_savedRawBytes))
|
||||
|
@ -192,7 +188,6 @@ void CMidiDeviceFluidSynth::playMidiEvent(const CMidiEvent & event)
|
|||
// FIXME missing
|
||||
break;
|
||||
}
|
||||
|
||||
//event.printDetails(); // useful for debugging
|
||||
}
|
||||
|
||||
|
|
|
@ -302,10 +302,7 @@ CMidiEvent CMidiDeviceRt::readMidiInput()
|
|||
break;
|
||||
|
||||
case MIDI_NOTE_PRESSURE: //MIDI_CMD_NOTE_PRESSURE: //POLY_AFTERTOUCH:
|
||||
// fixme fill in the blanks
|
||||
//midi_input_bytes[midi_input_length++] = channel | MIDI_CMD_NOTE_PRESSURE;
|
||||
//midi_input_bytes[midi_input_length++] = ev->data.note.note;
|
||||
//midi_input_bytes[midi_input_length++] = ev->data.note.velocity;
|
||||
midiEvent.notePressure(0, channel, m_inputMessage[1], m_inputMessage[2]);
|
||||
break;
|
||||
|
||||
case MIDI_CONTROL_CHANGE: //CONTROL_CHANGE:
|
||||
|
@ -313,19 +310,15 @@ CMidiEvent CMidiDeviceRt::readMidiInput()
|
|||
break;
|
||||
|
||||
case MIDI_PROGRAM_CHANGE: //PROGRAM_CHANGE:
|
||||
//midiEvent.programChangeEvent(0, ev->data.control.channel, ev->data.control.value);
|
||||
midiEvent.programChangeEvent(0, channel, m_inputMessage[1]);
|
||||
break;
|
||||
|
||||
case MIDI_CHANNEL_PRESSURE: //AFTERTOUCH:
|
||||
// fixme fill in the blanks
|
||||
//midi_input_bytes[midi_input_length++] = ev->data.control.channel | MIDI_CMD_CHANNEL_PRESSURE;
|
||||
//midi_input_bytes[midi_input_length++] = ev->data.control.value;
|
||||
midiEvent.channelPressure(0, channel, m_inputMessage[1]);
|
||||
break;
|
||||
|
||||
case MIDI_PITCH_BEND: //PITCH_BEND:
|
||||
// fixme fill in the blanks
|
||||
//midi_input_bytes[midi_input_length++] = ev->data.control.channel | MIDI_CMD_CHANNEL_PRESSURE;
|
||||
//midi_input_bytes[midi_input_length++] = ev->data.control.value;
|
||||
midiEvent.pitchBendEvent(0, channel, m_inputMessage[1], m_inputMessage[2]);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -126,6 +126,8 @@ public:
|
|||
int data1() const {return m_note;} // Meta data is stored here
|
||||
int data2() const {return m_velocity;}
|
||||
void setDatat2(int value) {m_velocity = value;}
|
||||
void setTrack(int track) {m_track = track;}
|
||||
int track() {return m_track;}
|
||||
|
||||
void noteOffEvent( int deltaTime, int channel, int note, int velocity)
|
||||
{
|
||||
|
@ -338,6 +340,7 @@ private:
|
|||
int m_note;
|
||||
int m_velocity;
|
||||
int m_duration;
|
||||
int m_track;
|
||||
};
|
||||
|
||||
#endif //__MIDI_EVENT_H__
|
||||
|
|
|
@ -100,6 +100,7 @@ void CMidiFile::openMidiFile(string filename)
|
|||
|
||||
void CMidiFile::rewind()
|
||||
{
|
||||
m_numberOfTracks = 0;
|
||||
size_t ntrks;
|
||||
size_t trk;
|
||||
dword_t trackLength;
|
||||
|
@ -123,6 +124,7 @@ void CMidiFile::rewind()
|
|||
ppLogError("Too many tracks in SMF file");
|
||||
return;
|
||||
}
|
||||
m_numberOfTracks = ntrks;
|
||||
for (trk = 0; trk < arraySize(m_tracks); trk++)
|
||||
{
|
||||
if (m_tracks[trk]!= nullptr)
|
||||
|
@ -163,7 +165,7 @@ bool CMidiFile::checkMidiEventFromStream(int streamIdx)
|
|||
return false;
|
||||
}
|
||||
|
||||
CMidiEvent CMidiFile::fetchMidiEventFromStream(int streamIdx)
|
||||
CMidiEvent CMidiFile::fetchMidiEventFromStream(int trackNo)
|
||||
{
|
||||
return m_tracks[streamIdx]->pop();
|
||||
return m_tracks[trackNo]->pop(trackNo);
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ public:
|
|||
setSize(MAX_TRACKS);
|
||||
for (i = 0; i < arraySize(m_tracks); i++)
|
||||
m_tracks[i] = 0;
|
||||
m_numberOfTracks = 0;
|
||||
}
|
||||
|
||||
void openMidiFile(string filename);
|
||||
|
@ -66,6 +67,7 @@ public:
|
|||
|
||||
void setLogLevel(int level){CMidiTrack::setLogLevel(level);}
|
||||
midiErrors_t getMidiError() { return m_midiError;}
|
||||
int numberOfTracks() const {return m_numberOfTracks;}
|
||||
|
||||
private:
|
||||
bool checkMidiEventFromStream(int streamIdx);
|
||||
|
@ -76,6 +78,7 @@ private:
|
|||
midiErrors_t m_midiError;
|
||||
CMidiTrack* m_tracks[MAX_TRACKS];
|
||||
QString m_songTitle;
|
||||
int m_numberOfTracks;
|
||||
};
|
||||
|
||||
#endif // __MIDIFILE_H__
|
||||
|
|
|
@ -78,8 +78,9 @@ public:
|
|||
midiErrors_t getMidiError() { return m_midiError;}
|
||||
|
||||
int length() {return m_trackEventQueue->length();}
|
||||
CMidiEvent pop() {
|
||||
CMidiEvent pop(int trackNo) {
|
||||
CMidiEvent m = m_trackEventQueue->pop();
|
||||
m.setTrack(trackNo);
|
||||
m.printDetails();
|
||||
return m;
|
||||
}
|
||||
|
|
|
@ -163,7 +163,7 @@ void QtWindow::displayUsage()
|
|||
fprintf(stdout, " -v, --version Displays version number and then exits.\n");
|
||||
fprintf(stdout, " -l --log Write debug info to the \"pb.log\" log file.\n");
|
||||
fprintf(stdout, " --midi-input-dump Displays the midi input in hex.\n");
|
||||
fprintf(stdout, " --lights: Turns on the keyboard lights.\n");
|
||||
fprintf(stdout, " --lights Turns on the keyboard lights.\n");
|
||||
}
|
||||
|
||||
int QtWindow::decodeIntegerParam(QString arg, int defaultParam)
|
||||
|
@ -641,7 +641,7 @@ void QtWindow::open()
|
|||
else
|
||||
dir = QDir::homePath();
|
||||
|
||||
QString fileName = QFileDialog::getOpenFileName(this,tr("Open Midi File"),
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Open Midi File"),
|
||||
dir, tr("Midi Files") + " (*.mid *.MID *.midi *.MIDI *.kar *.KAR)");
|
||||
if (!fileName.isEmpty()) {
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
void CSong::init2(CScore * scoreWin, CSettings* settings)
|
||||
{
|
||||
|
||||
CNote::setChannelHands(-2, -2); // -2 for not set -1 for none
|
||||
CNote::reset();
|
||||
|
||||
this->CConductor::init2(scoreWin, settings);
|
||||
|
||||
|
@ -44,7 +44,7 @@ void CSong::init2(CScore * scoreWin, CSettings* settings)
|
|||
|
||||
void CSong::loadSong(const QString & filename)
|
||||
{
|
||||
CNote::setChannelHands(-2, -2); // -2 for not set -1 for none
|
||||
CNote::reset();
|
||||
|
||||
m_songTitle = filename;
|
||||
int index = m_songTitle.lastIndexOf("/");
|
||||
|
@ -74,7 +74,7 @@ void CSong::loadSong(const QString & filename)
|
|||
// read the file ahead to collect info about the song first
|
||||
void CSong::midiFileInfo()
|
||||
{
|
||||
m_trackList->clear();
|
||||
m_trackList->reset(m_midiFile->numberOfTracks());
|
||||
setTimeSig(0,0);
|
||||
CStavePos::setKeySignature( NOT_USED, 0 );
|
||||
|
||||
|
|
|
@ -38,65 +38,61 @@ void CTrackList::init(CSong* songObj, CSettings* settings)
|
|||
m_settings = settings;
|
||||
}
|
||||
|
||||
void CTrackList::clear()
|
||||
void CTrackList::reset(int numberOfTracks)
|
||||
{
|
||||
int chan;
|
||||
|
||||
for (chan = 0; chan < MAX_MIDI_CHANNELS; chan++)
|
||||
{
|
||||
m_midiActiveChannels[chan] = false;
|
||||
m_midiFirstPatchChannels[chan] = -1;
|
||||
for (int i = 0; i < MAX_MIDI_NOTES; i++)
|
||||
m_partsList.clear();
|
||||
m_midiChannels.clear();
|
||||
for (int chan = 0; chan < MAX_MIDI_CHANNELS; chan++) {
|
||||
for (int i = 0; i < MAX_MIDI_NOTES; i++) {
|
||||
m_noteFrequency[chan][i]=0;
|
||||
}
|
||||
m_midiChannels.append(AnalyseItem(numberOfTracks));
|
||||
}
|
||||
m_trackQtList.clear();
|
||||
}
|
||||
|
||||
void CTrackList::currentRowChanged(int currentRow)
|
||||
{
|
||||
if (!m_song) return;
|
||||
if (currentRow >= m_trackQtList.size()|| currentRow < 0)
|
||||
if (currentRow >= m_partsList.size()|| currentRow < 0)
|
||||
return;
|
||||
|
||||
m_song->setActiveChannel(m_trackQtList[currentRow].midiChannel);
|
||||
m_song->setActiveChannel(m_partsList[currentRow].midiChannel());
|
||||
}
|
||||
|
||||
void CTrackList::examineMidiEvent(CMidiEvent event)
|
||||
{
|
||||
int chan;
|
||||
chan = event.channel();
|
||||
int chan = event.channel();
|
||||
|
||||
assert (chan < MAX_MIDI_CHANNELS && chan >= 0);
|
||||
if (chan < MAX_MIDI_CHANNELS && chan >= 0)
|
||||
{
|
||||
if (event.type() == MIDI_NOTE_ON)
|
||||
{
|
||||
m_midiActiveChannels[chan] = true;
|
||||
m_midiChannels[chan].addNoteEvent(event);
|
||||
|
||||
// count each note so we can guess the key signature
|
||||
if (event.note() >= 0 && event.note() < MAX_MIDI_NOTES)
|
||||
if (event.note() >= 0 && event.note() < MAX_MIDI_NOTES) {
|
||||
m_noteFrequency[chan][event.note()]++;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a note and no patch then default to grand piano patch
|
||||
if (m_midiFirstPatchChannels[chan] == -1)
|
||||
m_midiFirstPatchChannels[chan] = GM_PIANO_PATCH;
|
||||
|
||||
if (event.type() == MIDI_PROGRAM_CHANGE) {
|
||||
m_midiChannels[chan].addPatch(event.programme());
|
||||
}
|
||||
|
||||
if (event.type() == MIDI_PROGRAM_CHANGE && m_midiActiveChannels[chan] == false)
|
||||
m_midiFirstPatchChannels[chan] = event.programme();
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if there is a piano part on channels 3 & 4
|
||||
bool CTrackList::pianoPartConvetionTest()
|
||||
{
|
||||
if (m_midiFirstPatchChannels[CONVENTION_LEFT_HAND_CHANNEL] == GM_PIANO_PATCH &&
|
||||
m_midiActiveChannels[CONVENTION_LEFT_HAND_CHANNEL] == true &&
|
||||
m_midiFirstPatchChannels[CONVENTION_RIGHT_HAND_CHANNEL] <= GM_PIANO_PATCH)
|
||||
if (m_midiChannels[CONVENTION_LEFT_HAND_CHANNEL].firstPatch() == GM_PIANO_PATCH &&
|
||||
m_midiChannels[CONVENTION_LEFT_HAND_CHANNEL].active() &&
|
||||
m_midiChannels[CONVENTION_RIGHT_HAND_CHANNEL].firstPatch() <= GM_PIANO_PATCH)
|
||||
return true;
|
||||
|
||||
if (m_midiFirstPatchChannels[CONVENTION_RIGHT_HAND_CHANNEL] == GM_PIANO_PATCH &&
|
||||
m_midiActiveChannels[CONVENTION_RIGHT_HAND_CHANNEL] == true &&
|
||||
m_midiFirstPatchChannels[CONVENTION_LEFT_HAND_CHANNEL] <= GM_PIANO_PATCH)
|
||||
if (m_midiChannels[CONVENTION_RIGHT_HAND_CHANNEL].firstPatch() == GM_PIANO_PATCH &&
|
||||
m_midiChannels[CONVENTION_RIGHT_HAND_CHANNEL].active() &&
|
||||
m_midiChannels[CONVENTION_LEFT_HAND_CHANNEL].firstPatch() <= GM_PIANO_PATCH)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -108,9 +104,14 @@ bool CTrackList::findLeftAndRightPianoParts()
|
|||
int chanA = -1;
|
||||
|
||||
for (int chan = 0 ; chan < MAX_MIDI_CHANNELS; chan++) {
|
||||
if (m_midiActiveChannels[chan]) {
|
||||
int patch = m_midiFirstPatchChannels[chan];
|
||||
if (m_midiChannels[chan].active()) {
|
||||
int patch = m_midiChannels[chan].firstPatch();
|
||||
if (isPianoOrOrganPatch(patch)) {
|
||||
if (m_midiChannels[chan].trackCount() > 1) {
|
||||
CNote::setChannelHands(chan, chan);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (patchA == -1) {
|
||||
patchA = patch;
|
||||
chanA = chan;
|
||||
|
@ -205,7 +206,7 @@ int CTrackList::findFreeChannel(int startChannel)
|
|||
continue;
|
||||
if (chan == MIDI_DRUM_CHANNEL)
|
||||
continue;
|
||||
if (m_midiActiveChannels[chan] == false)
|
||||
if (!m_midiChannels[chan].active())
|
||||
return chan;
|
||||
}
|
||||
return -1; // Not found
|
||||
|
@ -214,17 +215,14 @@ int CTrackList::findFreeChannel(int startChannel)
|
|||
|
||||
void CTrackList::refresh()
|
||||
{
|
||||
int chan;
|
||||
int rowCount = 0;
|
||||
m_trackQtList.clear();
|
||||
m_partsList.clear();
|
||||
|
||||
for (chan = 0; chan < MAX_MIDI_CHANNELS; chan++)
|
||||
for (int chan = 0; chan < MAX_MIDI_CHANNELS; chan++)
|
||||
{
|
||||
if (m_midiActiveChannels[chan] == true)
|
||||
if (m_midiChannels[chan].active())
|
||||
{
|
||||
CTrackListItem trackItem;
|
||||
trackItem.midiChannel = chan;
|
||||
m_trackQtList.append(trackItem);
|
||||
m_partsList.append(CTrackListItem(chan));
|
||||
rowCount++;
|
||||
}
|
||||
}
|
||||
|
@ -240,14 +238,14 @@ void CTrackList::refresh()
|
|||
}
|
||||
else
|
||||
{
|
||||
if (m_trackQtList.count() > 0)
|
||||
if (m_partsList.count() > 0)
|
||||
{
|
||||
m_song->setActiveChannel(m_trackQtList[0].midiChannel);
|
||||
m_song->setActiveChannel(m_partsList[0].midiChannel());
|
||||
}
|
||||
}
|
||||
|
||||
if (CStavePos::getKeySignature() == NOT_USED)
|
||||
CStavePos::setKeySignature(guessKeySignature(CNote::rightHandChan(),CNote::leftHandChan()), 0);
|
||||
CStavePos::setKeySignature(guessKeySignature(CNote::rightHandChan(), CNote::leftHandChan()), 0);
|
||||
|
||||
// Find an unused channel that we can use for the keyboard
|
||||
m_song->reset();
|
||||
|
@ -260,18 +258,23 @@ void CTrackList::refresh()
|
|||
goodChan = 15 -1;
|
||||
badChan = 16-1;
|
||||
}
|
||||
m_song->setPianistChannels(goodChan,badChan);
|
||||
m_song->setPianistChannels(goodChan, badChan);
|
||||
ppLogInfo("Using Pianist Channels %d + %d", goodChan +1, badChan +1);
|
||||
if (Cfg::keyboardLightsChan != -1 && spareChan != -1)
|
||||
m_song->mapTrack2Channel(Cfg::keyboardLightsChan, spareChan);
|
||||
for (int chan = 0; chan < MAX_MIDI_CHANNELS; chan++) {
|
||||
AnalyseItem item = m_midiChannels[chan];
|
||||
ppLogInfo("ZZ track notes %d tracks %s", item.noteCount(), qPrintable(item.trackInfo()));
|
||||
CNote::setRightHandTrack(chan, item.rightHandTrack());
|
||||
}
|
||||
}
|
||||
|
||||
int CTrackList::getActiveItemIndex()
|
||||
{
|
||||
int chan;
|
||||
for (int i = 0; i < m_trackQtList.size(); ++i)
|
||||
for (int i = 0; i < m_partsList.size(); ++i)
|
||||
{
|
||||
chan = m_trackQtList.at(i).midiChannel;
|
||||
chan = m_partsList[i].midiChannel();
|
||||
if (chan == CNote::rightHandChan() )
|
||||
return i;
|
||||
}
|
||||
|
@ -285,10 +288,10 @@ QStringList CTrackList::getAllChannelProgramNames(bool raw)
|
|||
QString text;
|
||||
QString hand;
|
||||
|
||||
for (int i = 0; i < m_trackQtList.size(); ++i)
|
||||
for (int i = 0; i < m_partsList.size(); ++i)
|
||||
{
|
||||
hand.clear();
|
||||
chan = m_trackQtList.at(i).midiChannel;
|
||||
chan = m_partsList[i].midiChannel();
|
||||
if (raw == false)
|
||||
{
|
||||
if (CNote::leftHandChan() == chan)
|
||||
|
@ -305,8 +308,8 @@ QStringList CTrackList::getAllChannelProgramNames(bool raw)
|
|||
int CTrackList::getActiveHandIndex(whichPart_t whichPart)
|
||||
{
|
||||
int index = 0;
|
||||
for (int i = 0; i < m_trackQtList.size(); ++i)
|
||||
if (m_trackQtList.at(i).midiChannel == CNote::getHandChannel( whichPart))
|
||||
for (int i = 0; i < m_partsList.size(); ++i)
|
||||
if (m_partsList[i].midiChannel() == CNote::getHandChannel( whichPart))
|
||||
return index;
|
||||
|
||||
return index;
|
||||
|
@ -318,9 +321,9 @@ void CTrackList::setActiveHandsIndex(int leftIndex, int rightIndex)
|
|||
int rightChannel = -1;
|
||||
|
||||
if (leftIndex>=0)
|
||||
leftChannel = m_trackQtList.at(leftIndex).midiChannel;
|
||||
leftChannel = m_partsList.at(leftIndex).midiChannel();
|
||||
if (rightIndex>=0)
|
||||
rightChannel = m_trackQtList.at(rightIndex).midiChannel;
|
||||
rightChannel = m_partsList.at(rightIndex).midiChannel();
|
||||
m_settings->setChannelHands(leftChannel, rightChannel);
|
||||
refresh();
|
||||
m_song->rewind();
|
||||
|
@ -331,10 +334,10 @@ int CTrackList::getHandTrackIndex(whichPart_t whichPart)
|
|||
{
|
||||
int index = 0;
|
||||
int midiHand = CNote::getHandChannel(whichPart);
|
||||
for (int i = 0; i < m_trackQtList.size(); ++i)
|
||||
for (int i = 0; i < m_partsList.size(); ++i)
|
||||
{
|
||||
|
||||
if (m_trackQtList.at(i).midiChannel == midiHand)
|
||||
if (m_partsList[i].midiChannel() == midiHand)
|
||||
return index;
|
||||
index++;
|
||||
}
|
||||
|
@ -344,7 +347,7 @@ int CTrackList::getHandTrackIndex(whichPart_t whichPart)
|
|||
|
||||
void CTrackList::changeListWidgetItemView( unsigned int index, QListWidgetItem* listWidgetItem )
|
||||
{
|
||||
int chan = m_trackQtList[index].midiChannel;
|
||||
int chan = m_partsList[index].midiChannel();
|
||||
if ( CNote::hasPianoPart( chan ))
|
||||
{
|
||||
QFont font = listWidgetItem->font();
|
||||
|
@ -359,12 +362,12 @@ void CTrackList::changeListWidgetItemView( unsigned int index, QListWidgetItem*
|
|||
|
||||
QString CTrackList::getChannelProgramName(int chan)
|
||||
{
|
||||
if(chan<0 || chan>= static_cast<int>(arraySize(m_midiFirstPatchChannels)))
|
||||
if(chan<0 || chan>= MAX_MIDI_CHANNELS)
|
||||
{
|
||||
assert(true);
|
||||
return QString();
|
||||
}
|
||||
int program = m_midiFirstPatchChannels[chan];
|
||||
int program = m_midiChannels[chan].firstPatch();
|
||||
|
||||
if (chan==10-1)
|
||||
return QObject::tr("Drums");
|
||||
|
|
122
src/TrackList.h
122
src/TrackList.h
|
@ -43,10 +43,119 @@
|
|||
class CSong;
|
||||
class CSettings;
|
||||
|
||||
class AnalyseItem
|
||||
{
|
||||
public:
|
||||
|
||||
AnalyseItem() {}
|
||||
|
||||
AnalyseItem(int numberOfTracks)
|
||||
{
|
||||
m_noteCount = 0;
|
||||
for(int i = 0; i < numberOfTracks; i++) {
|
||||
QSharedPointer<int> notePtr (new int[MAX_MIDI_NOTES]);
|
||||
memset(notePtr.data(), 0, sizeof(int) * MAX_MIDI_NOTES );
|
||||
m_noteFrequencyByTrack.append( notePtr) ;
|
||||
m_noteCountByTrack.append(0);
|
||||
}
|
||||
}
|
||||
|
||||
void addNoteEvent(CMidiEvent event){
|
||||
m_noteCount++;
|
||||
int trackNo = event.track();
|
||||
m_noteCountByTrack[trackNo]++;
|
||||
int *noteFrequency = m_noteFrequencyByTrack[trackNo].data();
|
||||
int note = event.note();
|
||||
// count each note so we can guess the key signature
|
||||
if (note >= 0 && note< MAX_MIDI_NOTES) {
|
||||
(*(noteFrequency + note))++;
|
||||
}
|
||||
// If we have a note and no patch then default to grand piano patch
|
||||
if (m_firstPatch == -1) {
|
||||
m_firstPatch = GM_PIANO_PATCH;
|
||||
}
|
||||
}
|
||||
|
||||
int noteCount() const {return m_noteCount;}
|
||||
int active() {return m_noteCount >0;}
|
||||
|
||||
void addPatch(int patch){
|
||||
if (m_firstPatch == -1) {
|
||||
m_firstPatch = patch;
|
||||
}
|
||||
}
|
||||
|
||||
int firstPatch() {return m_firstPatch;}
|
||||
|
||||
QString trackInfo() { // ZZ not required
|
||||
QString info = QString("No of tracks %1 : ").arg( QString::number(m_noteFrequencyByTrack.size()) );
|
||||
for (int i = 0; i < m_noteCountByTrack.size(); i++) {
|
||||
info += QString(" track %1 note count %2 " ).arg(QString::number(i),QString::number(m_noteCountByTrack[i]));
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
int trackCount() {
|
||||
int acitveTracks = 0;
|
||||
for (int track = 0; track < m_noteCountByTrack.size(); track++) {
|
||||
if (m_noteCountByTrack[track] > 0) {
|
||||
acitveTracks++;
|
||||
}
|
||||
}
|
||||
return acitveTracks;
|
||||
}
|
||||
|
||||
int rightHandTrack() {
|
||||
if (trackCount() <= 1) {
|
||||
return -1;
|
||||
}
|
||||
double highestAveragePitch = 0.0;
|
||||
int rightHAndTrack = 1;
|
||||
for (int track = 0; track < m_noteCountByTrack.size(); track++) {
|
||||
if (m_noteCountByTrack[track] > 0) {
|
||||
double averagePitch = averageNotePitch(track);
|
||||
if (averagePitch > highestAveragePitch ) {
|
||||
highestAveragePitch = averagePitch;
|
||||
rightHAndTrack = track;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rightHAndTrack;
|
||||
}
|
||||
|
||||
double averageNotePitch(int trackNo) const {
|
||||
int totalNoteCount = 0;
|
||||
double sumOffAllPitches = 0.0;
|
||||
int *noteFrequency = m_noteFrequencyByTrack[trackNo].data();
|
||||
|
||||
for (int note = 0; note < MAX_MIDI_NOTES; note++) {
|
||||
int frequency = *(noteFrequency + note);
|
||||
totalNoteCount += frequency;
|
||||
sumOffAllPitches += frequency * note;
|
||||
}
|
||||
return sumOffAllPitches / totalNoteCount;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_noteCount;
|
||||
int m_firstPatch = -1;
|
||||
QVector<QSharedPointer<int>> m_noteFrequencyByTrack;
|
||||
QVector<int> m_noteCountByTrack;
|
||||
int m_noteFrequencyByChannel[MAX_MIDI_NOTES];
|
||||
};
|
||||
|
||||
class CTrackListItem
|
||||
{
|
||||
public:
|
||||
int midiChannel;
|
||||
CTrackListItem(int midiChannel) :
|
||||
m_midiChannel(midiChannel)
|
||||
{
|
||||
}
|
||||
|
||||
int midiChannel() const {return m_midiChannel;}
|
||||
|
||||
private:
|
||||
int m_midiChannel;
|
||||
};
|
||||
|
||||
class CTrackList : public QObject
|
||||
|
@ -57,13 +166,13 @@ public:
|
|||
{
|
||||
m_song = 0;
|
||||
m_settings = 0;
|
||||
clear();
|
||||
reset(0);
|
||||
}
|
||||
|
||||
void init(CSong* songObj, CSettings* settings);
|
||||
|
||||
void refresh();
|
||||
void clear();
|
||||
void reset(int numberOfTracks);
|
||||
|
||||
// Find an unused channel
|
||||
int findFreeChannel(int startChannel);
|
||||
|
@ -104,11 +213,10 @@ private:
|
|||
|
||||
CSong* m_song;
|
||||
CSettings* m_settings;
|
||||
QList<CTrackListItem> m_trackQtList;
|
||||
bool m_midiActiveChannels[MAX_MIDI_CHANNELS];
|
||||
int m_midiFirstPatchChannels[MAX_MIDI_CHANNELS];
|
||||
QList<CTrackListItem> m_partsList;
|
||||
QVector<AnalyseItem> m_midiChannels;
|
||||
int m_noteFrequency[MAX_MIDI_CHANNELS][MAX_MIDI_NOTES];
|
||||
float m_averagePitch[MAX_MIDI_CHANNELS];
|
||||
|
||||
};
|
||||
|
||||
#endif //__TRACK_LIST_H__
|
||||
|
|
Loading…
Reference in New Issue