drumstick 2.11.1
C++ MIDI libraries using Qt objects, idioms, and style.
rmid.cpp
Go to the documentation of this file.
1/*
2 Standard RIFF MIDI Component
3 Copyright (C) 2006-2026, Pedro Lopez-Cabanillas <plcl@users.sf.net>
4
5 This library is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#include <QDebug>
20#include <QIODevice>
21#include <QFile>
22#include <drumstick/rmid.h>
23
24#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
25#define right Qt::right
26#define left Qt::left
27#define endl Qt::endl
28#define hex Qt::hex
29#define dec Qt::dec
30#endif
31
36
37namespace drumstick { namespace File {
38
55
56const quint32 CKID_RIFF = 0x46464952;
57const quint32 CKID_LIST = 0x5453494c;
58const quint32 CKID_INFO = 0x4f464e49;
59const quint32 CKID_RMID = 0x44494d52;
60const quint32 CKID_data = 0x61746164;
61const quint32 CKID_DISP = 0x50534944;
62const quint32 CKID_DLS = 0x20534C44;
63
69 QObject(parent)
70{ }
71
77
82void Rmidi::readFromFile(QString fileName)
83{
84 //qDebug() << Q_FUNC_INFO << fileName;
85 QFile file(m_fileName = fileName);
86 auto ok = file.open(QIODevice::ReadOnly);
87 if (ok) {
88 QDataStream ds(&file);
89 readFromStream(&ds);
90 file.close();
91 } else {
92 qCritical() << "cannot open file" << fileName;
93 }
94}
95
100void Rmidi::readFromStream(QDataStream* ds)
101{
102 //qDebug() << Q_FUNC_INFO;
103 if (ds != nullptr) {
104 m_stream = ds;
105 m_stream->setByteOrder(QDataStream::LittleEndian);
106 read();
107 }
108}
109
110QString Rmidi::toString(quint32 ckid)
111{
112 QByteArray data(reinterpret_cast<char *>(&ckid), sizeof(quint32));
113 return QString::fromLatin1(data);
114}
115
116QByteArray Rmidi::readByteArray(int size)
117{
118 //qDebug() << Q_FUNC_INFO << size;
119 char *buffer = new char[size];
120 m_stream->readRawData(buffer, size);
121 QByteArray ba(buffer);
122 delete[] buffer;
123 return ba;
124}
125
126void Rmidi::skip(quint32 cktype, int size)
127{
128 Q_UNUSED(cktype)
129 //qDebug() << Q_FUNC_INFO << toString(cktype) << size;
130 m_stream->skipRawData(size);
131}
132
133quint32 Rmidi::readExpectedChunk(quint32 cktype)
134{
135 quint32 chunkType, len = 0;
136 *m_stream >> chunkType;
137 if (chunkType == cktype) {
138 *m_stream >> len;
139 if (len % 2) len++; // alignment to even size
140 /*qDebug() << Q_FUNC_INFO
141 << "Expected:" << toString(chunkType)
142 << "(" << hex << chunkType << ")"
143 << "length:" << dec << len;*/
144 } /*else {
145 qDebug() << Q_FUNC_INFO
146 << "Expected:" << toString(cktype)
147 << "(" << hex << cktype << ")"
148 << "got instead:" << toString(chunkType)
149 << "(" << hex << chunkType << ")";
150 }*/
151 return len;
152}
153
154quint32 Rmidi::readChunk(quint32& chunkType)
155{
156 quint32 len = 0;
157 *m_stream >> chunkType;
158 *m_stream >> len;
159 if (len % 2) len++; // alignment to even size
160 /*qDebug() << Q_FUNC_INFO
161 << "chunkType:" << toString(chunkType)
162 << "(" << hex << chunkType << ")"
163 << "length:" << dec << len;*/
164 return len;
165}
166
167quint32 Rmidi::readChunkID()
168{
169 quint32 chunkID;
170 *m_stream >> chunkID;
171 /*qDebug() << Q_FUNC_INFO
172 << "chunkID:" << toString(chunkID)
173 << "(" << hex << chunkID << ")";*/
174 return chunkID;
175}
176
177void Rmidi::processINFO(int size)
178{
179 //qDebug() << Q_FUNC_INFO << size;
180 quint32 chunkID = 0;
181 quint32 length = 0;
182 while ((size > 0) && !m_stream->atEnd()) {
183 length = readChunk(chunkID);
184 size -= 8;
185 size -= length;
186 QString cktype = toString(chunkID);
187 QByteArray data = readByteArray(length);
188 Q_EMIT signalRiffInfo(cktype, data);
189 }
190}
191
192void Rmidi::processList(int size)
193{
194 //qDebug() << Q_FUNC_INFO;
195 quint32 chunkID = 0;
196 if (m_stream->atEnd()) return;
197 chunkID = readChunkID();
198 size -= 4;
199 switch (chunkID) {
200 case CKID_INFO:
201 processINFO(size);
202 break;
203 default:
204 skip(chunkID, size);
205 }
206}
207
208void Rmidi::processRMID(int size)
209{
210 //qDebug() << Q_FUNC_INFO << size;
211 quint32 chunkID = 0;
212 int length;
213 while ((size > 0) && !m_stream->atEnd()) {
214 length = readChunk(chunkID);
215 size -= 8;
216 switch (chunkID) {
217 case CKID_data:
218 processData("RMID", length);
219 break;
220 case CKID_LIST:
221 processList(length);
222 break;
223 case CKID_DISP:
224 skip(chunkID, length);
225 break;
226 case CKID_RIFF:
227 processRIFF(length);
228 break;
229 default:
230 skip(chunkID, length);
231 }
232 size -= length;
233 }
234}
235
236void Rmidi::processRIFF(int size)
237{
238 quint32 chunkID = readChunkID();
239 quint32 length = size - 4;
240 switch(chunkID) {
241 case CKID_RMID:
242 //qDebug() << "RMID format";
243 processRMID(length);
244 break;
245 case CKID_DLS:
246 //qDebug() << "DLS format";
247 if (m_stream->device() != nullptr && m_stream->device()->pos() >= 12) {
248 m_stream->device()->seek(m_stream->device()->pos() - 12);
249 processData("DLS", length + 12);
250 } else {
251 skip(chunkID, length);
252 }
253 break;
254 default:
255 qWarning() << "Unsupported format";
256 skip(chunkID, length);
257 }
258}
259
260void Rmidi::processData(const QString& dataType, int size)
261{
262 //qDebug() << Q_FUNC_INFO << size;
263 QByteArray memdata(size, '\0');
264 m_stream->readRawData(memdata.data(), size);
265 Q_EMIT signalRiffData(dataType, memdata);
266}
267
268void Rmidi::read()
269{
270 //qDebug() << Q_FUNC_INFO;
271 quint32 length = readExpectedChunk(CKID_RIFF);
272 if (length > 0) {
273 processRIFF(length);
274 }
275}
276
277}} // namespace drumstick::File
The QObject class is the base class of all Qt objects.
Rmidi(QObject *parent=nullptr)
Constructor.
Definition rmid.cpp:68
virtual ~Rmidi()
Destructor.
Definition rmid.cpp:75
void readFromStream(QDataStream *ds)
Reads a stream.
Definition rmid.cpp:100
void signalRiffData(const QString &dataType, const QByteArray &data)
signalRiffData is emitted for each RMID data element
void signalRiffInfo(const QString &infoType, const QByteArray &info)
signalRMidInfo is emitted for each RIFF INFO element
void readFromFile(QString fileName)
Reads a stream from a disk file.
Definition rmid.cpp:82
Drumstick File library.
Definition qsmf.cpp:40
Drumstick common.
RIFF MIDI Files Input.