drumstick 2.10.0
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-2024, 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
37namespace drumstick { namespace File {
38
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
76{ }
77
82void Rmidi::readFromFile(QString fileName)
83{
84 //qDebug() << Q_FUNC_INFO << fileName;
85 QFile file(m_fileName = fileName);
86 file.open(QIODevice::ReadOnly);
87 QDataStream ds(&file);
88 readFromStream(&ds);
89 file.close();
90}
91
96void Rmidi::readFromStream(QDataStream* ds)
97{
98 //qDebug() << Q_FUNC_INFO;
99 if (ds != nullptr) {
100 m_stream = ds;
101 m_stream->setByteOrder(QDataStream::LittleEndian);
102 read();
103 }
104}
105
106QString Rmidi::toString(quint32 ckid)
107{
108 QByteArray data(reinterpret_cast<char *>(&ckid), sizeof(quint32));
109 return QString::fromLatin1(data);
110}
111
112QByteArray Rmidi::readByteArray(int size)
113{
114 //qDebug() << Q_FUNC_INFO << size;
115 char *buffer = new char[size];
116 m_stream->readRawData(buffer, size);
117 QByteArray ba(buffer);
118 delete[] buffer;
119 return ba;
120}
121
122void Rmidi::skip(quint32 cktype, int size)
123{
124 Q_UNUSED(cktype)
125 //qDebug() << Q_FUNC_INFO << toString(cktype) << size;
126 m_stream->skipRawData(size);
127}
128
129quint32 Rmidi::readExpectedChunk(quint32 cktype)
130{
131 quint32 chunkType, len = 0;
132 *m_stream >> chunkType;
133 if (chunkType == cktype) {
134 *m_stream >> len;
135 if (len % 2) len++; // alignment to even size
136 /*qDebug() << Q_FUNC_INFO
137 << "Expected:" << toString(chunkType)
138 << "(" << hex << chunkType << ")"
139 << "length:" << dec << len;*/
140 } /*else {
141 qDebug() << Q_FUNC_INFO
142 << "Expected:" << toString(cktype)
143 << "(" << hex << cktype << ")"
144 << "got instead:" << toString(chunkType)
145 << "(" << hex << chunkType << ")";
146 }*/
147 return len;
148}
149
150quint32 Rmidi::readChunk(quint32& chunkType)
151{
152 quint32 len = 0;
153 *m_stream >> chunkType;
154 *m_stream >> len;
155 if (len % 2) len++; // alignment to even size
156 /*qDebug() << Q_FUNC_INFO
157 << "chunkType:" << toString(chunkType)
158 << "(" << hex << chunkType << ")"
159 << "length:" << dec << len;*/
160 return len;
161}
162
163quint32 Rmidi::readChunkID()
164{
165 quint32 chunkID;
166 *m_stream >> chunkID;
167 /*qDebug() << Q_FUNC_INFO
168 << "chunkID:" << toString(chunkID)
169 << "(" << hex << chunkID << ")";*/
170 return chunkID;
171}
172
173void Rmidi::processINFO(int size)
174{
175 //qDebug() << Q_FUNC_INFO << size;
176 quint32 chunkID = 0;
177 quint32 length = 0;
178 while ((size > 0) && !m_stream->atEnd()) {
179 length = readChunk(chunkID);
180 size -= 8;
181 size -= length;
182 QString cktype = toString(chunkID);
183 QByteArray data = readByteArray(length);
184 Q_EMIT signalRiffInfo(cktype, data);
185 }
186}
187
188void Rmidi::processList(int size)
189{
190 //qDebug() << Q_FUNC_INFO;
191 quint32 chunkID = 0;
192 if (m_stream->atEnd()) return;
193 chunkID = readChunkID();
194 size -= 4;
195 switch (chunkID) {
196 case CKID_INFO:
197 processINFO(size);
198 break;
199 default:
200 skip(chunkID, size);
201 }
202}
203
204void Rmidi::processRMID(int size)
205{
206 //qDebug() << Q_FUNC_INFO << size;
207 quint32 chunkID = 0;
208 int length;
209 while ((size > 0) && !m_stream->atEnd()) {
210 length = readChunk(chunkID);
211 size -= 8;
212 switch (chunkID) {
213 case CKID_data:
214 processData("RMID", length);
215 break;
216 case CKID_LIST:
217 processList(length);
218 break;
219 case CKID_DISP:
220 skip(chunkID, length);
221 break;
222 case CKID_RIFF:
223 processRIFF(length);
224 break;
225 default:
226 skip(chunkID, length);
227 }
228 size -= length;
229 }
230}
231
232void Rmidi::processRIFF(int size)
233{
234 quint32 chunkID = readChunkID();
235 quint32 length = size - 4;
236 switch(chunkID) {
237 case CKID_RMID:
238 //qDebug() << "RMID format";
239 processRMID(length);
240 break;
241 case CKID_DLS:
242 //qDebug() << "DLS format";
243 if (m_stream->device() != nullptr && m_stream->device()->pos() >= 12) {
244 m_stream->device()->seek(m_stream->device()->pos() - 12);
245 processData("DLS", length + 12);
246 } else {
247 skip(chunkID, length);
248 }
249 break;
250 default:
251 qWarning() << "Unsupported format";
252 skip(chunkID, length);
253 }
254}
255
256void Rmidi::processData(const QString& dataType, int size)
257{
258 //qDebug() << Q_FUNC_INFO << size;
259 QByteArray memdata(size, '\0');
260 m_stream->readRawData(memdata.data(), size);
261 Q_EMIT signalRiffData(dataType, memdata);
262}
263
264void Rmidi::read()
265{
266 //qDebug() << Q_FUNC_INFO;
267 quint32 length = readExpectedChunk(CKID_RIFF);
268 if (length > 0) {
269 processRIFF(length);
270 }
271}
272
273}} // 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:96
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 common.
Definition: alsaclient.cpp:71
RIFF MIDI Files Input.