drumstick  2.5.0
rmid.cpp
Go to the documentation of this file.
1 /*
2  Standard RIFF MIDI Component
3  Copyright (C) 2006-2021, 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 
68  QObject(parent)
69 { }
70 
75 { }
76 
81 void 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 
95 void 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 
105 QString Rmidi::toString(quint32 ckid)
106 {
107  QByteArray data(reinterpret_cast<char *>(&ckid), sizeof(quint32));
108  return QString::fromLatin1(data);
109 }
110 
111 QByteArray 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 
121 void 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 
128 quint32 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 
149 quint32 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 
162 quint32 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 
172 void 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 
187 void 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 
203 void 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 
228 void 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 
236 void 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
void signalRiffInfo(const QString &infoType, const QByteArray &info)
signalRMidInfo is emitted for each RIFF INFO element
RIFF MIDI Files Input.
The QObject class is the base class of all Qt objects.
Drumstick common.
Definition: alsaclient.cpp:68
void signalRiffData(const QString &dataType, const QByteArray &data)
signalRiffData is emitted for each RMID data element
void readFromFile(QString fileName)
Reads a stream from a disk file.
Definition: rmid.cpp:81
void readFromStream(QDataStream *ds)
Reads a stream.
Definition: rmid.cpp:95
virtual ~Rmidi()
Destructor.
Definition: rmid.cpp:74
Rmidi(QObject *parent=nullptr)
Constructor.
Definition: rmid.cpp:67