pianobooster/src/MidiFile.cpp

163 lines
4.3 KiB
C++

/* oooOOO MidiFile.cpp OOOooo
* Reads a Standard MIDI File
Copyright (c) 1993, 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/>.
*/
#include <QMessageBox>
#include "MidiFile.h"
int CMidiFile::m_ppqn = DEFAULT_PPQN;
/* Read 16 bits from the Standard MIDI file */
int CMidiFile::readWord(void)
{
int value;
value = (m_file.get()&0x0ff) <<8 ;
value |= m_file.get()&0x0ff;
return value;
}
int CMidiFile::readHeader(void)
{
int i, c;
for ( i=0; i < 4; i++)
{
c = m_file.get();
if (c !="MThd"[i] )
{
midiError(SMF_CORRUPTED_MIDI_FILE);
return 0;
}
}
/* length */
if ( readWord() != 0)
{
midiError(SMF_CORRUPTED_MIDI_FILE);
return 0;
}
if ( readWord() != 6)
{
midiError(SMF_CORRUPTED_MIDI_FILE);
return 0;
}
readWord(); /* midi file format */
i = readWord(); /* ntrks (see Standard MIDI File Spec) */
m_ppqn=readWord(); /* division */
ppLogInfo("Tracks %d PPQN %d", i, m_ppqn);
if (i == 0)
{
midiError(SMF_CORRUPTED_MIDI_FILE);
return 0;
}
return i;
}
void CMidiFile::openMidiFile(const std::string &filename)
{
if (m_file.is_open())
m_file.close();
m_file.clear(); // clear any errors
m_file.open(filename.c_str(), std::ios_base::in | std::ios_base::binary);
if (m_file.fail() == true)
{
QMessageBox::warning(nullptr, QMessageBox::tr("MIDI File Error"),
QMessageBox::tr("Cannot open \"%1\"").arg(QString::fromStdString(filename)));
midiError(SMF_CANNOT_OPEN_FILE);
return;
}
rewind();
if (getMidiError() != SMF_NO_ERROR)
QMessageBox::warning(nullptr, QMessageBox::tr("MIDI File Error"),
QMessageBox::tr("MIDI file \"%1\" is corrupted").arg(QString::fromStdString(filename)));
}
void CMidiFile::rewind()
{
m_numberOfTracks = 0;
dword_t trackLength;
std::streampos filePos;
midiError(SMF_NO_ERROR);
m_ppqn = DEFAULT_PPQN;
m_file.seekg (0, std::ios::beg);
const auto ntrks = readHeader();
if (ntrks == 0)
{
midiError(SMF_CORRUPTED_MIDI_FILE);
ppLogError("Zero tracks in SMF file");
return;
}
if (ntrks < 0 || ntrks > arraySize(m_tracks))
{
midiError(SMF_ERROR_TOO_MANY_TRACK);
ppLogError("Too many tracks in SMF file");
return;
}
m_numberOfTracks = ntrks;
for (int trk = 0; trk < arraySize(m_tracks); ++trk)
{
delete m_tracks[trk];
m_tracks[trk] = nullptr;
}
filePos = m_file.tellg();
for (auto trk = 0; trk < ntrks; ++trk)
{
m_tracks[trk] = new CMidiTrack(m_file, trk);
trackLength = m_tracks[trk]->getTrackLength();
m_tracks[trk]->decodeTrack();
if (m_tracks[trk]->failed())
{
midiError(m_tracks[trk]->getMidiError());
break;
}
//now move onto the next track
filePos += static_cast<std::streamoff>(trackLength);
m_file.seekg (filePos, std::ios::beg);
}
m_songTitle = m_tracks[0]->getTrackName();
initMergedEvents();
}
bool CMidiFile::checkMidiEventFromStream(int streamIdx)
{
if (streamIdx < 0 || streamIdx >= MAX_TRACKS)
{
assert("streamIdx out of range");
return false;
}
if (m_tracks[streamIdx] != nullptr && m_tracks[streamIdx]->length() > 0)
return true;
return false;
}
CMidiEvent CMidiFile::fetchMidiEventFromStream(int trackNo)
{
return m_tracks[trackNo]->pop(trackNo);
}