
package micromod;

public class Macro {
	private Scale scale;
	private int rootKey;
	private Pattern notes;
	
	public Macro( String scale, String root, Pattern notes ) {
		this.scale = new Scale( scale != null ? scale : Scale.CHROMATIC );
		this.rootKey = Note.parseKey( root != null ? root : "C-2" );
		this.notes = notes;
	}
	
	/* Expand macro into Pattern until end or an instrument is set. */
	public void expand( Module module, int patternIdx, int channelIdx, int rowIdx ) {
		int macroRowIdx = 0, srcKey = 0, dstKey = 0, distance = 0, volume = 64;
		Pattern pattern = module.getPattern( patternIdx );
		Note note = new Note();
		while( rowIdx < Pattern.NUM_ROWS ) {
			pattern.getNote( rowIdx, channelIdx, note );
			if( note.instrument > 0 ) {
				break;
			}
			if( note.key > 0 ) {
				distance = scale.getDistance( rootKey, note.key );
			}
			int effect = note.effect;
			int param = note.parameter;
			notes.getNote( macroRowIdx++, 0, note );
			if( effect == 0xC ) {
				volume = param;
			} else if( ( note.effect | note.parameter ) == 0 ) {
				note.effect = effect;
				note.parameter = param;
			}
			int semitones = 0;
			if( note.key > 0 ) {
				srcKey = note.key;
				dstKey = scale.transpose( srcKey, distance );
				semitones = dstKey - srcKey;
			}
			note.transpose( semitones, volume, module );
			if( srcKey > 0 && note.effect == 0 && note.parameter != 0 ) {
				/* Adjust arpeggio.*/
				int dist = scale.getDistance( srcKey, srcKey + ( ( note.parameter >> 4 ) & 0xF ) );
				int arp1 = scale.transpose( srcKey, distance + dist ) - dstKey;
				if( arp1 > 15 ) arp1 = ( arp1 - 3 ) % 12 + 3;
				dist = scale.getDistance( srcKey, srcKey + ( note.parameter & 0xF ) );
				int arp2 = scale.transpose( srcKey, distance + dist ) - dstKey;
				if( arp2 > 15 ) arp2 = ( arp2 - 3 ) % 12 + 3;
				note.parameter = ( arp1 << 4 ) + ( arp2 & 0xF );
			}
			pattern.setNote( rowIdx++, channelIdx, note );
		}
	}
}

@@ -960,311 +960,338 @@
 if( 
-effect == 0xC ) %7B%0A%09%09%09%09volume = param;%0A%09%09%09%7D else if( ( note.effect %7C note.parameter ) == 0 ) %7B%0A%09%09%09%09note.effect = effect;%0A%09%09%09%09note.parameter = param;%0A%09%09%09%7D%0A%09%09%09int semitones = 0;%0A%09%09%09if( note.key %3E 0 ) %7B%0A%09%09%09%09srcKey = note.key;%0A%09%09%09%09dstKey = scale.transpose( srcKey, distance );%0A%09%09%09%09semitones = dstKey - srcKey
+note.key %3E 0 ) %7B%0A%09%09%09%09srcKey = note.key;%0A%09%09%09%09dstKey = scale.transpose( srcKey, distance );%0A%09%09%09%7D%0A%09%09%09int semitones = 0;%0A%09%09%09if( dstKey %3E 0 ) %7B%0A%09%09%09%09semitones = dstKey - srcKey;%0A%09%09%09%7D%0A%09%09%09if( effect == 0xC ) %7B%0A%09%09%09%09volume = param;%0A%09%09%09%7D else if( ( note.effect %7C note.parameter ) == 0 ) %7B%0A%09%09%09%09note.effect = effect;%0A%09%09%09%09note.parameter = param
 ;%0A%09%09
@@ -1353,15 +1353,19 @@
 f( s
-rcKey %3E
+emitones !=
  0 &
@@ -1548,35 +1548,35 @@
 cale.transpose( 
-src
+dst
 Key, distance + 
@@ -1564,35 +1564,24 @@
 dstKey, dist
-ance + dist
  ) - dstKey;
@@ -1571,32 +1571,61 @@
  dist ) - dstKey
+;%0A%09%09%09%09if( arp1 %3C 0 ) arp1 = 0
 ;%0A%09%09%09%09if( arp1 %3E
@@ -1759,35 +1759,35 @@
 cale.transpose( 
-src
+dst
 Key, distance + 
@@ -1783,19 +1783,8 @@
 dist
-ance + dist
  ) -
@@ -1782,32 +1782,61 @@
  dist ) - dstKey
+;%0A%09%09%09%09if( arp2 %3C 0 ) arp2 = 0
 ;%0A%09%09%09%09if( arp2 %3E

Make transpose more robust.