Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Float note positions and tuplets #1251

Draft
wants to merge 37 commits into
base: development
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
caffdf2
adding trueTuplets support
oddtime Jan 28, 2021
f8e41c9
temporary save commit
oddtime Jan 29, 2021
3813b5f
better formulas operating on integer numbers to calculate the tuplet …
oddtime Jan 30, 2021
09d3982
draw better note position better
oddtime Jan 30, 2021
45bda50
fix read tuplet denominator in preferences
oddtime Jan 30, 2021
927369e
minor fixes
oddtime Jan 30, 2021
0e31b7e
rough mod of cursor to make its position dependent on the grid resolu…
oddtime Jan 31, 2021
52f9c87
move keyboard_cursor to the nearest grid index after changing resolut…
oddtime Jan 31, 2021
4345f27
deprecate cursorIncrement
oddtime Jan 31, 2021
bc58388
comments changed
oddtime Jan 31, 2021
815c753
fix fill notes
oddtime Jan 31, 2021
7f888f4
magnetic addOrRemoveNote on click checks the time offset of already p…
oddtime Feb 1, 2021
331e1b5
load tuplet preferences, allo '/' separator update editor panel resol…
oddtime Feb 1, 2021
6c1dc29
TODO comments
oddtime Feb 3, 2021
008e634
Merge branch 'master' into trueTuplets
oddtime Feb 3, 2021
02dbe6f
copy the new tuplet members in note copying constructor
oddtime Feb 4, 2021
faee518
[fix] check if the note has same FRACTIONAL position before choosing …
oddtime Feb 7, 2021
8ef3c98
Merge branch 'development' into trueTuplets
oddtime Apr 17, 2021
abb512e
make note positions float type
oddtime Apr 18, 2021
6358e90
deprecate tuplet offsets in Note class
oddtime Apr 19, 2021
187276a
double precision positions
oddtime Apr 25, 2021
1acd515
fix pattern editor panel constructor, double granularity()
oddtime Apr 26, 2021
9019956
fix cursor update while change resolution
oddtime Apr 26, 2021
1fb405a
fix move notes
oddtime Apr 26, 2021
a27344c
noteProperty ruler undo/redo, keyboard cursor pixel rounded position
oddtime Apr 26, 2021
cd77840
add readXMLDouble()
oddtime Apr 27, 2021
64c96bf
add double XMLnode reader/writer in Xml.cpp
oddtime Apr 27, 2021
d120357
Merge branch 'development' into floatNotePositionsAndTuplets
oddtime Apr 27, 2021
bf22b47
adapt real time record to tuplet resolution
oddtime Apr 27, 2021
e128eb5
deprecate getFloatColumn
oddtime Apr 27, 2021
5432549
default.conf rename nodes for coherence
oddtime Apr 27, 2021
2be6842
fix copy/cut & paste
oddtime Apr 27, 2021
d7dbd23
fix copy/cut & paste BIS: increase precision in XML double float prin…
oddtime Apr 28, 2021
3101b64
fix copy/cut & paste TRIS: fix deselectAndOverwriteNotes()
oddtime Apr 28, 2021
d4689ef
fix expression: one only epsilon
oddtime May 3, 2021
032873c
Merge branch 'development' into floatNotePositionsAndTuplets
oddtime May 3, 2021
81d61d6
fix bug: no negative grid index
oddtime Jun 2, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion data/hydrogen.default.conf
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,10 @@
<mixer_falloff_speed>1.1</mixer_falloff_speed>

<patternEditorGridResolution>8</patternEditorGridResolution>
<patternEditorGridTupletNumerator>4</patternEditorGridTupletNumerator>
<patternEditorGridTupletDenominator>4</patternEditorGridTupletDenominator>
<patternEditorGridHeight>21</patternEditorGridHeight>
<patternEditorGridWidth>3</patternEditorGridWidth>
<patternEditorUsingTriplets>false</patternEditorUsingTriplets>

<showInstrumentPeaks>true</showInstrumentPeaks>

Expand Down
Binary file modified data/img/gray/patternEditor/background_res-new.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 10 additions & 5 deletions src/core/AudioEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ AudioEngine::AudioEngine()
, m_nPatternTickPosition( 0 )
, m_nSongSizeInTicks( 0 )
, m_nRealtimeFrames( 0 )
, m_nAddRealtimeNoteTickPosition( 0 )
, m_fAddRealtimeNoteTickPosition( 0. )
, m_nSongPos( -1 )
, m_nSelectedPatternNumber( 0 )
{
Expand Down Expand Up @@ -932,7 +932,7 @@ inline void AudioEngine::processPlayNotes( unsigned long nframes )

float velocity_adjustment = 1.0f;
if ( pSong->getMode() == Song::SONG_MODE ) {
float fPos = m_nSongPos + (pNote->get_position()%192) / 192.f;
float fPos = m_nSongPos + ( ( (int) pNote->get_position() ) %192) / 192.f; //TODO what if pattern length > 192?
velocity_adjustment = vp->get_value(fPos);
}

Expand Down Expand Up @@ -1713,10 +1713,14 @@ inline int AudioEngine::updateNoteQueue( unsigned nFrames )
// iterator (notes won't be altered!). After some
// humanization was applied to onset of each note, it
// will be added to `m_songNoteQueue` for playback.
FOREACH_NOTE_CST_IT_BOUND(notes,it,m_nPatternTickPosition) {
//FOREACH_NOTE_CST_IT_BOUND(notes,it,m_nPatternTickPosition) { //TODO macro
for( Pattern::notes_cst_it_t it=notes->lower_bound( m_nPatternTickPosition );
it != notes->end() && it->first < m_nPatternTickPosition + 1;
it++ ) {
Note *pNote = it->second;
if ( pNote ) {
pNote->set_just_recorded( false );

int nOffset = 0;

// Swing //
Expand Down Expand Up @@ -1761,9 +1765,10 @@ inline int AudioEngine::updateNoteQueue( unsigned nFrames )
// it the new offset, and push it to the list
// of all notes, which are about to be played
// back.
// TODO: Why a copy?
// Why a copy? because it has the new offset (including swing and random timing) in its
// humanized delay, and tick position is expressed referring to start time (and not pattern).
Note *pCopiedNote = new Note( pNote );
pCopiedNote->set_position( tick );
pCopiedNote->set_position( tick + pNote->get_position() - floor( pNote->get_position() ) );
pCopiedNote->set_humanize_delay( nOffset );
pNote->get_instrument()->enqueue();
m_songNoteQueue.push( pCopiedNote );
Expand Down
14 changes: 7 additions & 7 deletions src/core/AudioEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -704,8 +704,8 @@ class AudioEngine : public H2Core::Object
unsigned long getRealtimeFrames() const;
void setRealtimeFrames( unsigned long nFrames );

unsigned int getAddRealtimeNoteTickPosition() const;
void setAddRealtimeNoteTickPosition( unsigned int tickPosition );
double getAddRealtimeNoteTickPosition() const;
void setAddRealtimeNoteTickPosition( double fTickPosition );


struct timeval& getCurrentTickTime();
Expand Down Expand Up @@ -952,7 +952,7 @@ class AudioEngine : public H2Core::Object
* position TransportInfo::m_nFrames.
*/
unsigned long m_nRealtimeFrames;
unsigned int m_nAddRealtimeNoteTickPosition;
double m_fAddRealtimeNoteTickPosition;

/**
* Current state of the H2Core::AudioEngine.
Expand Down Expand Up @@ -1145,12 +1145,12 @@ inline void AudioEngine::setRealtimeFrames( unsigned long nFrames ) {
m_nRealtimeFrames = nFrames;
}

inline unsigned int AudioEngine::getAddRealtimeNoteTickPosition() const {
return m_nAddRealtimeNoteTickPosition;
inline double AudioEngine::getAddRealtimeNoteTickPosition() const {
return m_fAddRealtimeNoteTickPosition;
}

inline void AudioEngine::setAddRealtimeNoteTickPosition( unsigned int tickPosition) {
m_nAddRealtimeNoteTickPosition = tickPosition;
inline void AudioEngine::setAddRealtimeNoteTickPosition( double fTickPosition) {
m_fAddRealtimeNoteTickPosition = fTickPosition;
}

};
Expand Down
18 changes: 9 additions & 9 deletions src/core/Basics/Note.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ namespace H2Core
const char* Note::__class_name = "Note";
const char* Note::__key_str[] = { "C", "Cs", "D", "Ef", "E", "F", "Fs", "G", "Af", "A", "Bf", "B" };

Note::Note( Instrument* instrument, int position, float velocity, float pan_l, float pan_r, int length, float pitch )
Note::Note( Instrument* instrument, double position, float velocity, float pan_l, float pan_r, int length, float pitch )
: Object( __class_name ),
__instrument( instrument ),
__instrument_id( 0 ),
Expand Down Expand Up @@ -212,14 +212,14 @@ void Note::dump()

void Note::save_to( XMLNode* node )
{
node->write_int( "position", __position );
node->write_double( "position", __position );
node->write_float( "leadlag", __lead_lag );
node->write_float( "velocity", __velocity );
node->write_float( "pan_L", __pan_l );
node->write_float( "pan_R", __pan_r );
node->write_float( "pitch", __pitch );
node->write_string( "key", key_to_string() );
node->write_int( "length", __length );
node->write_double( "length", __length );
node->write_int( "instrument", get_instrument()->get_id() );
node->write_bool( "note_off", __note_off );
node->write_float( "probability", __probability );
Expand All @@ -229,11 +229,11 @@ Note* Note::load_from( XMLNode* node, InstrumentList* instruments )
{
Note* note = new Note(
nullptr,
node->read_int( "position", 0 ),
node->read_double( "position", 0 ),
node->read_float( "velocity", 0.8f ),
node->read_float( "pan_L", 0.5f ),
node->read_float( "pan_R", 0.5f ),
node->read_int( "length", -1 ),
node->read_double( "length", -1 ),
node->read_float( "pitch", 0.0f )
);
note->set_lead_lag( node->read_float( "leadlag", 0, false, false ) );
Expand All @@ -253,11 +253,11 @@ QString Note::toQString( const QString& sPrefix, bool bShort ) const {
sOutput = QString( "%1[Note]\n" ).arg( sPrefix )
.append( QString( "%1%2instrument_id: %3\n" ).arg( sPrefix ).arg( s ).arg( __instrument_id ) )
.append( QString( "%1%2specific_compo_id: %3\n" ).arg( sPrefix ).arg( s ).arg( __specific_compo_id ) )
.append( QString( "%1%2position: %3\n" ).arg( sPrefix ).arg( s ).arg( __position ) )
.append( QString( "%1%2position: %3\n" ).arg( sPrefix ).arg( s ).arg( __position, 0, 'g', 10 ) ) //TODO what precision?
.append( QString( "%1%2velocity: %3\n" ).arg( sPrefix ).arg( s ).arg( __velocity ) )
.append( QString( "%1%2pan_l: %3\n" ).arg( sPrefix ).arg( s ).arg( __pan_l ) )
.append( QString( "%1%2pan_r: %3\n" ).arg( sPrefix ).arg( s ).arg( __pan_r ) )
.append( QString( "%1%2length: %3\n" ).arg( sPrefix ).arg( s ).arg( __length ) )
.append( QString( "%1%2length: %3\n" ).arg( sPrefix ).arg( s ).arg( __length, 0, 'g', 10 ) ) //TODO what precision?
.append( QString( "%1%2pitch: %3\n" ).arg( sPrefix ).arg( s ).arg( __pitch ) )
.append( QString( "%1%2key: %3\n" ).arg( sPrefix ).arg( s ).arg( __key ) )
.append( QString( "%1%2octave: %3\n" ).arg( sPrefix ).arg( s ).arg( __octave ) )
Expand Down Expand Up @@ -291,11 +291,11 @@ QString Note::toQString( const QString& sPrefix, bool bShort ) const {
sOutput = QString( "[Note]" )
.append( QString( ", instrument_id: %1" ).arg( __instrument_id ) )
.append( QString( ", specific_compo_id: %1" ).arg( __specific_compo_id ) )
.append( QString( ", position: %1" ).arg( __position ) )
.append( QString( ", position: %1" ).arg( __position, 0, 'g', 10 ) ) //TODO what precision?
.append( QString( ", velocity: %1" ).arg( __velocity ) )
.append( QString( ", pan_l: %1" ).arg( __pan_l ) )
.append( QString( ", pan_r: %1" ).arg( __pan_r ) )
.append( QString( ", length: %1" ).arg( __length ) )
.append( QString( ", length: %1" ).arg( __length, 0, 'g', 10 ) ) //TODO what precision?
.append( QString( ", pitch: %1" ).arg( __pitch ) )
.append( QString( ", key: %1" ).arg( __key ) )
.append( QString( ", octave: %1" ).arg( __octave ) )
Expand Down
24 changes: 13 additions & 11 deletions src/core/Basics/Note.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class Note : public H2Core::Object
* \param length it's length
* \param pitch it's pitch
*/
Note( Instrument* instrument, int position, float velocity, float pan_l, float pan_r, int length, float pitch );
Note( Instrument* instrument, double position, float velocity, float pan_l, float pan_r, int length, float pitch );

/**
* copy constructor with an optional parameter
Expand Down Expand Up @@ -136,9 +136,9 @@ class Note : public H2Core::Object
* #__position setter
* \param value the new value
*/
void set_position( int value );
void set_position( double value );
/** #__position accessor */
int get_position() const;
double get_position() const;
/**
* #__velocity setter
* \param value the new value
Expand Down Expand Up @@ -171,9 +171,9 @@ class Note : public H2Core::Object
* #__length setter
* \param value the new value
*/
void set_length( int value );
void set_length( double value );
/** #__length accessor */
int get_length() const;
double get_length() const;
/**
* #__pitch setter
* \param value the new value
Expand Down Expand Up @@ -299,6 +299,7 @@ class Note : public H2Core::Object
* \param val_r the right channel value
*/
void compute_lr_values( float* val_l, float* val_r );

/** Formatted string version for debugging purposes.
* \param sPrefix String prefix which will be added in front of
* every new line
Expand All @@ -313,11 +314,11 @@ class Note : public H2Core::Object
Instrument* __instrument; ///< the instrument to be played by this note
int __instrument_id; ///< the id of the instrument played by this note
int __specific_compo_id; ///< play a specific component, -1 if playing all
int __position; ///< note position inside the pattern
double __position; ///< note position inside the pattern, in ticks
float __velocity; ///< velocity (intensity) of the note [0;1]
float __pan_l; ///< pan of the note (left volume) [0;0.5]
float __pan_r; ///< pan of the note (right volume) [0;0.5]
int __length; ///< the length of the note
double __length; ///< the length of the note
float __pitch; ///< the frequency of the note
Key __key; ///< the key, [0;11]==[C;B]
Octave __octave; ///< the octave [-3;3]
Expand Down Expand Up @@ -376,12 +377,12 @@ inline int Note::get_specific_compo_id() const
return __specific_compo_id;
}

inline void Note::set_position( int value )
inline void Note::set_position( double value )
{
__position = value;
}

inline int Note::get_position() const
inline double Note::get_position() const
{
return __position;
}
Expand All @@ -406,12 +407,12 @@ inline float Note::get_lead_lag() const
return __lead_lag;
}

inline void Note::set_length( int value )
inline void Note::set_length( double value )
{
__length = value;
}

inline int Note::get_length() const
inline double Note::get_length() const
{
return __length;
}
Expand Down Expand Up @@ -593,6 +594,7 @@ inline void Note::compute_lr_values( float* val_l, float* val_r )

};


#endif // H2C_NOTE_H

/* vim: set softtabstop=4 noexpandtab: */
12 changes: 6 additions & 6 deletions src/core/Basics/Pattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,9 @@ void Pattern::save_to( XMLNode* node, const Instrument* instrumentOnly ) const
}
}

Note* Pattern::find_note( int idx_a, int idx_b, Instrument* instrument, Note::Key key, Note::Octave octave, bool strict ) const
Note* Pattern::find_note( double idx_a, int idx_b, Instrument* instrument, Note::Key key, Note::Octave octave, bool strict ) const
{
for( notes_cst_it_t it=__notes.lower_bound( idx_a ); it!=__notes.upper_bound( idx_a ); it++ ) {
for( notes_cst_it_t it=__notes.lower_bound( idx_a - POS_EPSILON ) ; it!=__notes.upper_bound( idx_a + POS_EPSILON ); it++ ) {
Note* note = it->second;
assert( note );
if ( note->match( instrument, key, octave ) ) return note;
Expand All @@ -176,10 +176,10 @@ Note* Pattern::find_note( int idx_a, int idx_b, Instrument* instrument, Note::Ke
return nullptr;
}

Note* Pattern::find_note( int idx_a, int idx_b, Instrument* instrument, bool strict ) const
Note* Pattern::find_note( double idx_a, int idx_b, Instrument* instrument, bool strict ) const
{
notes_cst_it_t it;
for( it=__notes.lower_bound( idx_a ); it!=__notes.upper_bound( idx_a ); it++ ) {
for( it=__notes.lower_bound( idx_a - POS_EPSILON ); it!=__notes.upper_bound( idx_a + POS_EPSILON ); it++ ) {
Note* note = it->second;
assert( note );
if ( note->get_instrument() == instrument ) return note;
Expand All @@ -205,8 +205,8 @@ Note* Pattern::find_note( int idx_a, int idx_b, Instrument* instrument, bool str

void Pattern::remove_note( Note* note )
{
int pos = note->get_position();
for( notes_it_t it=__notes.lower_bound( pos ); it!=__notes.end() && it->first == pos; ++it ) {
double fPos = note->get_position();
FOREACH_NOTE_IT_BOUND( &__notes, it, fPos ) {
if( it->second==note ) {
__notes.erase( it );
break;
Expand Down
12 changes: 7 additions & 5 deletions src/core/Basics/Pattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class Pattern : public H2Core::Object
H2_OBJECT
public:
///< multimap note type
typedef std::multimap <int, Note*> notes_t;
typedef std::multimap <float, Note*> notes_t;
///< multimap note iterator type
typedef notes_t::iterator notes_it_t;
///< multimap note const iterator type
Expand Down Expand Up @@ -125,7 +125,7 @@ class Pattern : public H2Core::Object
* \param strict if set to false, will search for a note around the given idx
* \return the note if found, 0 otherwise
*/
Note* find_note( int idx_a, int idx_b, Instrument* instrument, bool strict=true ) const;
Note* find_note( double idx_a, int idx_b, Instrument* instrument, bool strict=true ) const; // TODO second arg float
/**
* search for a note at a given index within __notes which correspond to the given arguments
* \param idx_a the first __notes index to search in
Expand All @@ -136,7 +136,7 @@ class Pattern : public H2Core::Object
* \param strict if set to false, will search for a note around the given idx
* \return the note if found, 0 otherwise
*/
Note* find_note( int idx_a, int idx_b, Instrument* instrument, Note::Key key, Note::Octave octave, bool strict=true) const;
Note* find_note( double idx_a, int idx_b, Instrument* instrument, Note::Key key, Note::Octave octave, bool strict=true) const; // TODO second arg float
/**
* removes a given note from __notes, it's not deleted
* \param note the note to be removed
Expand Down Expand Up @@ -222,15 +222,17 @@ class Pattern : public H2Core::Object

#define FOREACH_NOTE_CST_IT_BEGIN_END(_notes,_it) \
for( Pattern::notes_cst_it_t _it=(_notes)->begin(); (_it)!=(_notes)->end(); (_it)++ )

#define POS_EPSILON 0.0001 // TODO choose value. use as argument of macro?

#define FOREACH_NOTE_CST_IT_BOUND(_notes,_it,_bound) \
for( Pattern::notes_cst_it_t _it=(_notes)->lower_bound((_bound)); (_it)!=(_notes)->end() && (_it)->first == (_bound); (_it)++ )
for( Pattern::notes_cst_it_t _it=(_notes)->lower_bound((_bound) - POS_EPSILON ); (_it)!=(_notes)->end() && (_it)->first < (_bound) + POS_EPSILON; (_it)++ )

#define FOREACH_NOTE_IT_BEGIN_END(_notes,_it) \
for( Pattern::notes_it_t _it=(_notes)->begin(); (_it)!=(_notes)->end(); (_it)++ )

#define FOREACH_NOTE_IT_BOUND(_notes,_it,_bound) \
for( Pattern::notes_it_t _it=(_notes)->lower_bound((_bound)); (_it)!=(_notes)->end() && (_it)->first == (_bound); (_it)++ )
for( Pattern::notes_it_t _it=(_notes)->lower_bound((_bound) - POS_EPSILON ); (_it)!=(_notes)->end() && (_it)->first < (_bound) + POS_EPSILON; (_it)++ )

// DEFINITIONS

Expand Down
8 changes: 4 additions & 4 deletions src/core/Basics/Song.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1531,7 +1531,7 @@ Pattern* SongReader::getPattern( QDomNode pattern, InstrumentList* pInstrList )

Note* pNote = nullptr;

unsigned nPosition = LocalFileMng::readXmlInt( noteNode, "position", 0 );
double fPosition = LocalFileMng::readXmlDouble( noteNode, "position", 0 );
float fLeadLag = LocalFileMng::readXmlFloat( noteNode, "leadlag", 0.0, false, false );
float fVelocity = LocalFileMng::readXmlFloat( noteNode, "velocity", 0.8f );
float fPan_L = LocalFileMng::readXmlFloat( noteNode, "pan_L", 0.5 );
Expand All @@ -1558,7 +1558,7 @@ Pattern* SongReader::getPattern( QDomNode pattern, InstrumentList* pInstrList )
noteoff = true;
}

pNote = new Note( pInstrumentRef, nPosition, fVelocity, fPan_L, fPan_R, nLength, nPitch );
pNote = new Note( pInstrumentRef, fPosition, fVelocity, fPan_L, fPan_R, nLength, nPitch );
pNote->set_key_octave( sKey );
pNote->set_lead_lag( fLeadLag );
pNote->set_note_off( noteoff );
Expand All @@ -1582,7 +1582,7 @@ Pattern* SongReader::getPattern( QDomNode pattern, InstrumentList* pInstrList )

Note* pNote = nullptr;

unsigned nPosition = LocalFileMng::readXmlInt( noteNode, "position", 0 );
double fPosition = LocalFileMng::readXmlDouble( noteNode, "position", 0 );
float fLeadLag = LocalFileMng::readXmlFloat( noteNode, "leadlag", 0.0, false, false );
float fVelocity = LocalFileMng::readXmlFloat( noteNode, "velocity", 0.8f );
float fPan_L = LocalFileMng::readXmlFloat( noteNode, "pan_L", 0.5 );
Expand All @@ -1595,7 +1595,7 @@ Pattern* SongReader::getPattern( QDomNode pattern, InstrumentList* pInstrList )
Instrument* instrRef = pInstrList->find( instrId );
assert( instrRef );

pNote = new Note( instrRef, nPosition, fVelocity, fPan_L, fPan_R, nLength, nPitch );
pNote = new Note( instrRef, fPosition, fVelocity, fPan_L, fPan_R, nLength, nPitch );
pNote->set_lead_lag( fLeadLag );

//infoLog( "new note!! pos: " + toString( pNote->m_nPosition ) + "\t instr: " + instrId );
Expand Down
2 changes: 1 addition & 1 deletion src/core/EventQueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ class EventQueue : public H2Core::Object
Event pop_event();

struct AddMidiNoteVector {
int m_column; //position
double m_column; //position
int m_row; //instrument row
int m_pattern; // pattern number
int m_length;
Expand Down
Loading