hydrogen 1.2.3
Smf.cpp
Go to the documentation of this file.
1/*
2 * Hydrogen
3 * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.sourceforge.net]
4 * Copyright(c) 2008-2024 The hydrogen development team [hydrogen-devel@lists.sourceforge.net]
5 *
6 * http://www.hydrogen-music.org
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY, without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see https://www.gnu.org/licenses
20 *
21 */
22
23#include <core/Smf/SMF.h>
24#include <core/Basics/Pattern.h>
26#include <core/Basics/Note.h>
27#include <core/Basics/Song.h>
31#include <fstream>
32
33namespace H2Core
34{
35
36SMFHeader::SMFHeader( int nFormat, int nTracks, int nTPQN )
37 : m_nFormat( nFormat )
38 , m_nTracks( nTracks )
39 , m_nTPQN( nTPQN )
40{
41
42}
43
44
46{
47 INFOLOG( "DESTROY" );
48}
49
51 m_nTracks++;
52}
53
54std::vector<char> SMFHeader::getBuffer()
55{
56 SMFBuffer buffer;
57
58 buffer.writeDWord( 1297377380 ); // MThd
59 buffer.writeDWord( 6 ); // Header length = 6
60 buffer.writeWord( m_nFormat );
61 buffer.writeWord( m_nTracks );
62 buffer.writeWord( m_nTPQN );
63
64 return buffer.m_buffer;
65}
66
67
68
69// :::::::::::::::
70
72 : Object()
73{
74
75}
76
77
78
80{
81 INFOLOG( "DESTROY" );
82
83 for ( unsigned i = 0; i < m_eventList.size(); i++ ) {
84 delete m_eventList[ i ];
85 }
86}
87
88
89
90std::vector<char> SMFTrack::getBuffer()
91{
92 // fill the data vector
93 std::vector<char> trackData;
94
95 for ( unsigned i = 0; i < m_eventList.size(); i++ ) {
96 SMFEvent *pEv = m_eventList[ i ];
97 std::vector<char> buf = pEv->getBuffer();
98
99 // copy the buffer into the data vector
100 for ( unsigned j = 0; j < buf.size(); j++ ) {
101 trackData.push_back( buf[ j ] );
102 }
103 }
104
105
106 SMFBuffer buf;
107
108 buf.writeDWord( 1297379947 ); // MTrk
109 buf.writeDWord( trackData.size() + 4 ); // Track length
110
111 std::vector<char> trackBuf = buf.getBuffer();
112
113 for ( unsigned i = 0; i < trackData.size(); i++ ) {
114 trackBuf.push_back( trackData[i] );
115 }
116
117
118 // track end
119 trackBuf.push_back( 0x00 ); // delta
120 trackBuf.push_back( 0xFF );
121 trackBuf.push_back( 0x2F );
122 trackBuf.push_back( 0x00 );
123
124
125
126 return trackBuf;
127}
128
129
130
132{
133 m_eventList.push_back( pEvent );
134}
135
136
137
138// ::::::::::::::::::::::
139
140SMF::SMF(int nFormat, int nTPQN )
141{
142
143
144 m_pHeader = new SMFHeader( nFormat, 0, nTPQN );
145}
146
147
148
150{
151 INFOLOG( "DESTROY" );
152
153 delete m_pHeader;
154
155 for ( unsigned i = 0; i < m_trackList.size(); i++ ) {
156 delete m_trackList[i];
157 }
158}
159
160
161
162void SMF::addTrack( SMFTrack *pTrack )
163{
165 m_trackList.push_back( pTrack );
166}
167
168
169
170std::vector<char> SMF::getBuffer()
171{
172 std::vector<char> smfVect;
173
174 // header
175 std::vector<char> headerVect = m_pHeader->getBuffer();
176 for ( unsigned i = 0; i < headerVect.size(); i++ ) {
177 smfVect.push_back( headerVect[ i ] );
178 }
179
180
181 // tracks
182 for ( unsigned nTrack = 0; nTrack < m_trackList.size(); nTrack++ ) {
183 SMFTrack *pTrack = m_trackList[ nTrack ];
184 std::vector<char> trackVect = pTrack->getBuffer();
185 for ( unsigned i = 0; i < trackVect.size(); i++ ) {
186 smfVect.push_back( trackVect[ i ] );
187 }
188 }
189
190 return smfVect;
191}
192
193
194
195// :::::::::::::::::::...
196
197constexpr unsigned int TPQN = 192;
198constexpr unsigned int DRUM_CHANNEL = 9;
199constexpr unsigned int NOTE_LENGTH = 12;
200
202{
203
204}
205
206
208{
209 INFOLOG( "DESTROY" );
210}
211
212
213SMFTrack* SMFWriter::createTrack0( std::shared_ptr<Song> pSong ) {
214 SMFTrack *pTrack0 = new SMFTrack();
215 pTrack0->addEvent( new SMFCopyRightNoticeMetaEvent( pSong->getAuthor() , 0 ) );
216 pTrack0->addEvent( new SMFTrackNameMetaEvent( pSong->getName() , 0 ) );
217 pTrack0->addEvent( new SMFSetTempoMetaEvent( pSong->getBpm() , 0 ) );
218 pTrack0->addEvent( new SMFTimeSignatureMetaEvent( 4 , 4 , 24 , 8 , 0 ) );
219 return pTrack0;
220}
221
222
223void SMFWriter::save( const QString& sFilename, std::shared_ptr<Song> pSong )
224{
225 INFOLOG( "save" );
226
227 SMF* pSmf = createSMF( pSong );
228
229 AutomationPath* pAutomationPath = pSong->getVelocityAutomationPath();
230
231 // here writers must prepare to receive pattern events
232 prepareEvents( pSong, pSmf );
233
234 auto pInstrumentList = pSong->getInstrumentList();
235 // ogni pattern sara' una diversa traccia
236 int nTick = 1;
237 for ( unsigned nPatternList = 0 ;
238 nPatternList < pSong->getPatternGroupVector()->size() ;
239 nPatternList++ ) {
240 // infoLog( "[save] pattern list pos: " + toString( nPatternList ) );
241 PatternList *pPatternList =
242 ( *(pSong->getPatternGroupVector()) )[ nPatternList ];
243
244 int nStartTicks = nTick;
245 int nMaxPatternLength = 0;
246 for ( unsigned nPattern = 0 ;
247 nPattern < pPatternList->size() ;
248 nPattern++ ) {
249 Pattern *pPattern = pPatternList->get( nPattern );
250 // infoLog( " |-> pattern: " + pPattern->getName() );
251 if ( ( int )pPattern->get_length() > nMaxPatternLength ) {
252 nMaxPatternLength = pPattern->get_length();
253 }
254
255 for ( unsigned nNote = 0; nNote < pPattern->get_length(); nNote++ ) {
256 const Pattern::notes_t* notes = pPattern->get_notes();
257 FOREACH_NOTE_CST_IT_BOUND_LENGTH(notes,it,nNote,pPattern) {
258 Note *pNote = it->second;
259 if ( pNote ) {
260 float rnd = (float)rand()/(float)RAND_MAX;
261 if ( pNote->get_probability() < rnd ) {
262 continue;
263 }
264
265 float fPos = nPatternList + (float)nNote/(float)nMaxPatternLength;
266 float fVelocityAdjustment = pAutomationPath->get_value(fPos);
267 int nVelocity =
268 (int)( 127.0 * pNote->get_velocity() * fVelocityAdjustment );
269
270 auto pInstr = pNote->get_instrument();
271 int nPitch = pNote->get_midi_key();
272
273 int nChannel = pInstr->get_midi_out_channel();
274 if ( nChannel == -1 ) {
275 nChannel = DRUM_CHANNEL;
276 }
277
278 int nLength = pNote->get_length();
279 if ( nLength == -1 ) {
280 nLength = NOTE_LENGTH;
281 }
282
283 // get events for specific instrument
284 EventList* eventList = getEvents(pSong, pInstr);
285 eventList->push_back(
286 new SMFNoteOnEvent(
287 nStartTicks + nNote,
288 nChannel,
289 nPitch,
290 nVelocity
291 )
292 );
293
294 eventList->push_back(
295 new SMFNoteOffEvent(
296 nStartTicks + nNote + nLength,
297 nChannel,
298 nPitch,
299 nVelocity
300 )
301 );
302 }
303 }
304 }
305 }
306 nTick += nMaxPatternLength;
307 }
308
309 //tracks creation
310 packEvents(pSong, pSmf);
311
312 saveSMF(sFilename, pSmf);
313 delete pSmf;
314}
315
316
318{
319 // awful bubble sort..
320 for ( unsigned i = 0; i < pEvents->size(); i++ ) {
321 for ( std::vector<SMFEvent*>::iterator it = pEvents->begin() ;
322 it != ( pEvents->end() - 1 ) ;
323 it++ ) {
324 SMFEvent *pEvent = *it;
325 SMFEvent *pNextEvent = *( it + 1 );
326 if ( pNextEvent->m_nTicks < pEvent->m_nTicks ) {
327 // swap
328 *it = pNextEvent;
329 *( it +1 ) = pEvent;
330 }
331 }
332 }
333}
334
335
336void SMFWriter::saveSMF( const QString& sFilename, SMF* pSmf )
337{
338 // save the midi file
339 FILE* pFile = fopen( sFilename.toLocal8Bit(), "wb" );
340
341 if( pFile == nullptr ) {
342 return;
343 }
344
345 std::vector<char> smfVect = pSmf->getBuffer();
346 for ( unsigned i = 0; i < smfVect.size(); i++ ) {
347 fwrite( &smfVect[ i ], 1, 1, pFile );
348 }
349 fclose( pFile );
350}
351
352
353// SMF1Writer - base class for two smf1 writers
354
359
360
364
365
366SMF* SMF1Writer::createSMF( std::shared_ptr<Song> pSong ){
367 SMF* pSmf = new SMF( 1, TPQN );
368 // Standard MIDI format 1 files should have the first track being the tempo map
369 // which is a track that contains global meta events only.
370
371 SMFTrack* pTrack0 = createTrack0( pSong );
372 pSmf->addTrack( pTrack0 );
373
374 // Standard MIDI Format 1 files should have note events in tracks =>2
375 return pSmf;
376}
377
378
379// SMF1 MIDI SINGLE EXPROT
380
381
383 : SMF1Writer(),
384 m_eventList()
385{
386}
387
388
389
393
394
395
396EventList* SMF1WriterSingle::getEvents( std::shared_ptr<Song> pSong, std::shared_ptr<Instrument> pInstr )
397{
398 return &m_eventList;
399}
400
401
402
403void SMF1WriterSingle::prepareEvents( std::shared_ptr<Song> pSong, SMF* pSmf )
404{
405 m_eventList.clear();
406}
407
408
409
410void SMF1WriterSingle::packEvents( std::shared_ptr<Song> pSong, SMF* pSmf )
411{
413
414 SMFTrack *pTrack1 = new SMFTrack();
415 pSmf->addTrack( pTrack1 );
416
417 unsigned nLastTick = 1;
418 for( auto& pEvent : m_eventList ) {
419 pEvent->m_nDeltaTime = ( pEvent->m_nTicks - nLastTick ) * 4;
420 nLastTick = pEvent->m_nTicks;
421
422 // infoLog( " pos: " + toString( (*it)->m_nTicks ) + ", delta: "
423 // + toString( (*it)->m_nDeltaTime ) );
424
425 pTrack1->addEvent( pEvent );
426 }
427
428 m_eventList.clear();
429}
430
431
432
433// SMF1 MIDI MULTI EXPORT
434
436 : SMF1Writer(),
437 m_eventLists()
438{
439}
440
441
445
446
447void SMF1WriterMulti::prepareEvents( std::shared_ptr<Song> pSong, SMF* pSmf )
448{
449 auto pInstrumentList = pSong->getInstrumentList();
450 m_eventLists.clear();
451 for( unsigned nInstr=0; nInstr < pInstrumentList->size(); nInstr++ ){
452 m_eventLists.push_back( new EventList() );
453 }
454}
455
456
457EventList* SMF1WriterMulti::getEvents( std::shared_ptr<Song> pSong, std::shared_ptr<Instrument> pInstr )
458{
459 int nInstr = pSong->getInstrumentList()->index(pInstr);
460 EventList* pEventList = m_eventLists.at( nInstr );
461
462 return pEventList;
463}
464
465
466void SMF1WriterMulti::packEvents( std::shared_ptr<Song> pSong, SMF* pSmf )
467{
468 auto pInstrumentList = pSong->getInstrumentList();
469 for ( unsigned nTrack = 0; nTrack < m_eventLists.size(); nTrack++ ) {
470 EventList* pEventList = m_eventLists.at( nTrack );
471 auto instrument = pInstrumentList->get( nTrack );
472
473 sortEvents( pEventList );
474
475 SMFTrack *pTrack = new SMFTrack();
476 pSmf->addTrack( pTrack );
477
478 //Set instrument name as track name
479 pTrack->addEvent( new SMFTrackNameMetaEvent( instrument->get_name() , 0 ) );
480
481 unsigned nLastTick = 1;
482 for ( std::vector<SMFEvent*>::iterator it = pEventList->begin();
483 it != pEventList->end();
484 it++ ) {
485 SMFEvent *pEvent = *it;
486 pEvent->m_nDeltaTime = ( pEvent->m_nTicks - nLastTick ) * 4;
487 nLastTick = pEvent->m_nTicks;
488
489 pTrack->addEvent( *it );
490 }
491
492 // we can safely delete vector with events now
493 delete pEventList;
494 }
495 m_eventLists.clear();
496}
497
498
499// SMF0 MIDI EXPORT
500
502 : SMFWriter(),
503 m_pTrack( nullptr ),
504 m_eventList()
505{
506}
507
508
512
513
514SMF* SMF0Writer::createSMF( std::shared_ptr<Song> pSong ){
515 // MIDI files format 0 have all their events in one track
516 SMF* pSmf = new SMF( 0, TPQN );
517 m_pTrack = createTrack0( pSong );
518 pSmf->addTrack( m_pTrack );
519 return pSmf;
520}
521
522
523EventList* SMF0Writer::getEvents( std::shared_ptr<Song> pSong, std::shared_ptr<Instrument> pInstr )
524{
525 return &m_eventList;
526}
527
528
529void SMF0Writer::prepareEvents( std::shared_ptr<Song> pSong, SMF* pSmf )
530{
531 m_eventList.clear();
532}
533
534
535void SMF0Writer::packEvents( std::shared_ptr<Song> pSong, SMF* pSmf )
536{
538
539 unsigned nLastTick = 1;
540 for ( std::vector<SMFEvent*>::iterator it = m_eventList.begin();
541 it != m_eventList.end();
542 it++ ) {
543 SMFEvent *pEvent = *it;
544 pEvent->m_nDeltaTime = ( pEvent->m_nTicks - nLastTick ) * 4;
545 nLastTick = pEvent->m_nTicks;
546
547 m_pTrack->addEvent( *it );
548 }
549
550 m_eventList.clear();
551}
552
553
554};
#define INFOLOG(x)
Definition Object.h:237
#define FOREACH_NOTE_CST_IT_BOUND_LENGTH(_notes, _it, _bound, _pattern)
Iterate over all notes in column _bound in an immutable way if it is contained in _pattern.
Definition Pattern.h:290
float get_value(float x) const noexcept
Get value at given location.
A note plays an associated instrument with a velocity left and right pan.
Definition Note.h:102
std::shared_ptr< Instrument > get_instrument()
__instrument accessor
Definition Note.h:500
int get_length() const
__length accessor
Definition Note.h:560
int get_midi_key() const
return scaled key for midi output, !!! DO NOT CHECK IF INSTRUMENT IS SET !!!
Definition Note.h:682
float get_velocity() const
__velocity accessor
Definition Note.h:540
float get_probability() const
Definition Note.h:610
PatternList is a collection of patterns.
Definition PatternList.h:43
int size() const
returns the numbers of patterns
Pattern * get(int idx)
get a pattern from the list
Pattern class is a Note container.
Definition Pattern.h:46
int get_length() const
set the denominator of the pattern
Definition Pattern.h:340
const notes_t * get_notes() const
get the virtual pattern set
Definition Pattern.h:355
std::multimap< int, Note * > notes_t
< multimap note type
Definition Pattern.h:50
virtual void prepareEvents(std::shared_ptr< Song > pSong, SMF *pSmf) override
Definition Smf.cpp:529
SMFTrack * m_pTrack
Definition SMF.h:185
virtual EventList * getEvents(std::shared_ptr< Song > pSong, std::shared_ptr< Instrument > pInstr) override
Definition Smf.cpp:523
EventList m_eventList
Definition SMF.h:186
virtual ~SMF0Writer()
Definition Smf.cpp:509
virtual SMF * createSMF(std::shared_ptr< Song > pSong) override
Definition Smf.cpp:514
virtual void packEvents(std::shared_ptr< Song > pSong, SMF *pSmf) override
Definition Smf.cpp:535
virtual void prepareEvents(std::shared_ptr< Song > pSong, SMF *pSmf) override
Definition Smf.cpp:447
virtual EventList * getEvents(std::shared_ptr< Song > pSong, std::shared_ptr< Instrument > pInstr) override
Definition Smf.cpp:457
std::vector< EventList * > m_eventLists
Definition SMF.h:166
virtual ~SMF1WriterMulti()
Definition Smf.cpp:442
virtual void packEvents(std::shared_ptr< Song > pSong, SMF *pSmf) override
Definition Smf.cpp:466
virtual void prepareEvents(std::shared_ptr< Song > pSong, SMF *pSmf) override
Definition Smf.cpp:403
virtual EventList * getEvents(std::shared_ptr< Song > pSong, std::shared_ptr< Instrument > pInstr) override
Definition Smf.cpp:396
EventList m_eventList
Definition SMF.h:149
virtual ~SMF1WriterSingle()
Definition Smf.cpp:390
virtual void packEvents(std::shared_ptr< Song > pSong, SMF *pSmf) override
Definition Smf.cpp:410
virtual SMF * createSMF(std::shared_ptr< Song > pSong) override
Definition Smf.cpp:366
virtual ~SMF1Writer()
Definition Smf.cpp:361
virtual std::vector< char > getBuffer()=0
std::vector< char > getBuffer()
Definition SMFEvent.h:37
std::vector< char > m_buffer
Definition SMFEvent.h:47
void writeDWord(long nVal)
Definition SmfEvent.cpp:48
void writeWord(int nVal)
Definition SmfEvent.cpp:39
int m_nTPQN
ticks per quarter note
Definition SMF.h:54
SMFHeader(int nFormat, int nTracks, int nTPQN)
Definition Smf.cpp:36
int m_nTracks
number of tracks
Definition SMF.h:53
void addTrack()
Definition Smf.cpp:50
virtual std::vector< char > getBuffer() override
Definition Smf.cpp:54
int m_nFormat
SMF format.
Definition SMF.h:52
virtual std::vector< char > getBuffer() override
Definition Smf.cpp:90
std::vector< SMFEvent * > m_eventList
Definition SMF.h:73
void addEvent(SMFEvent *pEvent)
Definition Smf.cpp:131
void saveSMF(const QString &sFilename, SMF *pSmf)
Definition Smf.cpp:336
virtual void packEvents(std::shared_ptr< Song > pSong, SMF *pSmf)=0
virtual SMF * createSMF(std::shared_ptr< Song > pSong)=0
void sortEvents(EventList *pEventList)
Definition Smf.cpp:317
virtual EventList * getEvents(std::shared_ptr< Song > pSong, std::shared_ptr< Instrument > pInstr)=0
virtual ~SMFWriter()
Definition Smf.cpp:207
SMFTrack * createTrack0(std::shared_ptr< Song > pSong)
Definition Smf.cpp:213
virtual void prepareEvents(std::shared_ptr< Song > pSong, SMF *pSmf)=0
void save(const QString &sFilename, std::shared_ptr< Song > pSong)
Definition Smf.cpp:223
void addTrack(SMFTrack *pTrack)
Definition Smf.cpp:162
SMFHeader * m_pHeader
Definition SMF.h:92
std::vector< SMFTrack * > m_trackList
Definition SMF.h:90
virtual std::vector< char > getBuffer() override
Definition Smf.cpp:170
SMF(int nFormat, int nTPQN)
Definition Smf.cpp:140
constexpr unsigned int DRUM_CHANNEL
Definition Smf.cpp:198
constexpr unsigned int NOTE_LENGTH
Definition Smf.cpp:199
constexpr unsigned int TPQN
Definition Smf.cpp:197
std::vector< SMFEvent * > EventList
Definition SMF.h:97