Separate left and right parts contained in different midi tracks.

This commit is contained in:
louis-barman 2020-05-23 10:44:51 +01:00
parent 2667bf360f
commit 3fd6b85b88
15 changed files with 256 additions and 116 deletions

View File

@ -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 /////////////////////

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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
}

View File

@ -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;
}

View File

@ -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__

View File

@ -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);
}

View File

@ -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__

View File

@ -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;
}

View File

@ -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()) {

View File

@ -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 );

View File

@ -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");

View File

@ -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__