drumstick  2.9.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-2023, 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 
37 namespace drumstick { namespace File {
38 
56 const quint32 CKID_RIFF = 0x46464952;
57 const quint32 CKID_LIST = 0x5453494c;
58 const quint32 CKID_INFO = 0x4f464e49;
59 const quint32 CKID_RMID = 0x44494d52;
60 const quint32 CKID_data = 0x61746164;
61 const quint32 CKID_DISP = 0x50534944;
62 const quint32 CKID_DLS = 0x20534C44;
63 
69  QObject(parent)
70 { }
71 
76 { }
77 
82 void 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 
96 void 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 
106 QString Rmidi::toString(quint32 ckid)
107 {
108  QByteArray data(reinterpret_cast<char *>(&ckid), sizeof(quint32));
109  return QString::fromLatin1(data);
110 }
111 
112 QByteArray 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 
122 void 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 
129 quint32 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 
150 quint32 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 
163 quint32 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 
173 void 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 
188 void 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 
204 void 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 
232 void 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 
256 void 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 
264 void 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:68
RIFF MIDI Files Input.