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