//
// The algorithm for chords is:
// - The chords are done in a separate track.
// - If there are notes before the first chord, then put that much silence to start the track.
// - The pattern of chord expression depends on the meter, and how many chords are in a measure.
// - There is a possibility that a measure will have an incorrect number of beats, if that is the case, then
// start the pattern anew on the next measure number.
// - If a chord root is not A-G, then ignore it as if the chord wasn't there at all.
// - If a chord modification isn't in our supported list, change it to a major triad.
//
// - There is a standard pattern of boom-chick for each time sig, or it can be overridden.
// - For any unrecognized meter, play the full chord on each beat.
//
//	- If there is a chord specified that is not on a beat, move it earlier to the previous beat, unless there is already a chord on that beat.
//	- Otherwise, move it later, unless there is already a chord on that beat.
// 	- Otherwise, ignore it. (TODO-PER: expand this as more support is added.)
//
// If there is any note in the melody that has a rhythm head, then assume the melody controls the rhythm, so there is no chord added for that entire measure.

var ChordTrack = function ChordTrack(numVoices, chordsOff, midiOptions, meter) {
	this.chordTrack = [];
	this.chordTrackFinished = false;
	this.chordChannel = numVoices; // first free channel for chords
	this.currentChords = [];
	this.lastChord;
	this.chordLastBar;
	this.chordsOff = !!chordsOff
	this.gChordTacet = this.chordsOff;
	this.hasRhythmHead = false;
	this.transpose = 0;
	this.lastBarTime = 0;
	this.meter = meter;
	this.tempoChangeFactor = 1;

	// MAE 17 Jun 2024 - To allow for bass and chord instrument octave shifts
	this.bassInstrument = midiOptions.bassprog && midiOptions.bassprog.length >= 1 ? midiOptions.bassprog[0] : 0;
	this.chordInstrument = midiOptions.chordprog && midiOptions.chordprog.length >= 1 ? midiOptions.chordprog[0] : 0;

	// MAE For octave shifted bass and chords
	this.bassOctaveShift = midiOptions.bassprog && midiOptions.bassprog.length === 2 ? midiOptions.bassprog[1] : 0;
	this.chordOctaveShift = midiOptions.chordprog && midiOptions.chordprog.length === 2 ? midiOptions.chordprog[1] : 0;

	this.boomVolume = midiOptions.bassvol && midiOptions.bassvol.length === 1 ? midiOptions.bassvol[0] : 64;
	this.chickVolume = midiOptions.chordvol && midiOptions.chordvol.length === 1 ? midiOptions.chordvol[0] : 48;

	// This allows for an initial %%MIDI gchord with no string
	if (midiOptions.gchord && (midiOptions.gchord.length > 0)) {
		this.overridePattern = parseGChord(midiOptions.gchord[0])
	}
	else {
		this.overridePattern = undefined;
	}
};

ChordTrack.prototype.setMeter = function (meter) {
	this.meter = meter
};

ChordTrack.prototype.setTempoChangeFactor = function (tempoChangeFactor) {
	this.tempoChangeFactor = tempoChangeFactor
};

ChordTrack.prototype.setLastBarTime = function (lastBarTime) {
	this.lastBarTime = lastBarTime
};

ChordTrack.prototype.setTranspose = function (transpose) {
	this.transpose = transpose
};

ChordTrack.prototype.setRhythmHead = function (isRhythmHead, elem) {
	this.hasRhythmHead = isRhythmHead
	var ePitches = [];
	if (isRhythmHead) {
		if (this.lastChord && this.lastChord.chick) {
			for (var i2 = 0; i2 < this.lastChord.chick.length; i2++) {
				var note2 = Object.assign({},elem.pitches[0]);
				note2.actualPitch = this.lastChord.chick[i2];
				ePitches.push(note2);
			}
		}
	}
	return ePitches
};

ChordTrack.prototype.barEnd = function (element) {
	if (this.chordTrack.length > 0 && !this.chordTrackFinished) {
		this.resolveChords(this.lastBarTime, timeToRealTime(element.time));
		this.currentChords = [];
	}
	this.chordLastBar = this.lastChord;
};

ChordTrack.prototype.gChordOn = function (element) {
	if (!this.chordsOff)
		this.gChordTacet = element.tacet;
};

ChordTrack.prototype.paramChange = function (element) {
	switch (element.el_type) {
		case "gchord":
			// Skips gchord elements that don't have pattern strings
			if (element.param && element.param.length > 0) {
				this.overridePattern = parseGChord(element.param);

				// Generate a default duration scale based on the pattern
				//this.gchordduration = generateDefaultDurationScale(element.param);
			} else
				this.overridePattern = undefined;
			break;
		case "bassprog":
			this.bassInstrument = element.value;
			if ((element.octaveShift != undefined) && (element.octaveShift != null)) {
				this.bassOctaveShift = element.octaveShift;
			}
			else {
				this.bassOctaveShift = 0;
			}
			break;
		case "chordprog":
			this.chordInstrument = element.value;
			if ((element.octaveShift != undefined) && (element.octaveShift != null)) {
				this.chordOctaveShift = element.octaveShift;
			}
			else {
				this.chordOctaveShift = 0;
			}
			break;
		case "bassvol":
			this.boomVolume = element.param;
			break;
		case "chordvol":
			this.chickVolume = element.param;
			break;
		default:
			console.log("unhandled midi param", element)	
	}
};

ChordTrack.prototype.finish = function () {
	if (!this.chordTrackEmpty()) // Don't do chords on more than one track, so turn off chord detection after we create it.
		this.chordTrackFinished = true;
};

ChordTrack.prototype.addTrack = function (tracks) {
	if (!this.chordTrackEmpty())
		tracks.push(this.chordTrack);
};

ChordTrack.prototype.findChord = function (elem) {
	if (this.gChordTacet)
		return 'break';

	// TODO-PER: Just using the first chord if there are more than one.
	if (this.chordTrackFinished || !elem.chord || elem.chord.length === 0)
		return null;

	// Return the first annotation that is a regular chord: that is, it is in the default place or is a recognized "tacet" phrase.
	for (var i = 0; i < elem.chord.length; i++) {
		var ch = elem.chord[i];
		if (ch.position === 'default')
			return ch.name;
		if (this.breakSynonyms.indexOf(ch.name.toLowerCase()) >= 0)
			return 'break';
	}
	return null;
}

ChordTrack.prototype.interpretChord = function (name) {
	// chords have the format:
	// [root][acc][modifier][/][bass][acc]
	// (The chord might be surrounded by parens. Just ignore them.)
	// root must be present and must be from A-G.
	// acc is optional and can be # or b
	// The modifier can be a wide variety of things, like "maj7". As they are discovered, more are supported here.
	// If there is a slash, then there is a bass note, which can be from A-G, with an optional acc.
	// If the root is unrecognized, then "undefined" is returned and there is no chord.
	// If the modifier is unrecognized, a major triad is returned.
	// If the bass notes is unrecognized, it is ignored.
	if (name.length === 0)
		return undefined;
	if (name === 'break')
		return { chick: [] };
	var root = name.substring(0, 1);
	if (root === '(') {
		name = name.substring(1, name.length - 1);
		if (name.length === 0)
			return undefined;
		root = name.substring(0, 1);
	}
	var bass = this.basses[root];
	if (!bass)	// If the bass note isn't listed, then this was an unknown root. Only A-G are accepted.
		return undefined;
	// Don't transpose the chords more than an octave.
	var chordTranspose = this.transpose;
	while (chordTranspose < -8)
		chordTranspose += 12;
	while (chordTranspose > 8)
		chordTranspose -= 12;
	bass += chordTranspose;
	
    	// MAE 31 Aug 2024 - For visual transpose backup range issue
    	// If transposed below A or above G, bring it back in the normal backup range
    	if (bass < 33){
      		bass += 12;
    	}
    	else if (bass > 44){
	     	 bass -= 12;
    	}

	// MAE 17 Jun 2024 - Supporting octave shifted bass and chords
	var unshiftedBass = bass;

	bass += this.bassOctaveShift * 12;

	var bass2 = bass - 5;	// The alternating bass is a 4th below
	var chick;
	if (name.length === 1)
		chick = this.chordNotes(bass, '');
	var remaining = name.substring(1);
	var acc = remaining.substring(0, 1);
	if (acc === 'b' || acc === '♭') {
		unshiftedBass--;
		bass--;
		bass2--;
		remaining = remaining.substring(1);
	} else if (acc === '#' || acc === '♯') {
		unshiftedBass++;
		bass++;
		bass2++;
		remaining = remaining.substring(1);
	}
	var arr = remaining.split('/');
	chick = this.chordNotes(unshiftedBass, arr[0]);
	// If the 5th is altered then the bass is altered. Normally the bass is 7 from the root, so adjust if it isn't.
	if (chick.length >= 3) {
		var fifth = chick[2] - chick[0];
		bass2 = bass2 + fifth - 7;
	}

	if (arr.length === 2) {
		var explicitBass = this.basses[arr[1].substring(0, 1)];
		if (explicitBass) {
			var bassAcc = arr[1].substring(1);
			var bassShift = { '#': 1, '♯': 1, 'b': -1, '♭': -1 }[bassAcc] || 0;
			bass = this.basses[arr[1].substring(0, 1)] + bassShift + chordTranspose;

			// MAE 22 May 2024 - Supporting octave shifted bass and chords
			bass += this.bassOctaveShift * 12;

			bass2 = bass;
		}
	}
	return { boom: bass, boom2: bass2, chick: chick };
}

ChordTrack.prototype.chordNotes = function (bass, modifier) {
	var intervals = this.chordIntervals[modifier];
	if (!intervals) {
		if (modifier.slice(0, 2).toLowerCase() === 'ma' || modifier[0] === 'M')
			intervals = this.chordIntervals.M;
		else if (modifier[0] === 'm' || modifier[0] === '-')
			intervals = this.chordIntervals.m;
		else
			intervals = this.chordIntervals.M;
	}
	bass += 12;	// the chord is an octave above the bass note.

	// MAE 22 May 2024 - For chick octave shift
	bass += (this.chordOctaveShift * 12);

	var notes = [];
	for (var i = 0; i < intervals.length; i++) {
		notes.push(bass + intervals[i]);
	}
	return notes;
}

ChordTrack.prototype.writeNote = function (note, beatLength, volume, beat, noteLength, instrument) {
	// undefined means there is a stop time.
	if (note !== undefined)
		this.chordTrack.push({ cmd: 'note', pitch: note, volume: volume, start: this.lastBarTime + beat * durationRounded(beatLength, this.tempoChangeFactor), duration: durationRounded(noteLength, this.tempoChangeFactor), gap: 0, instrument: instrument });
}

ChordTrack.prototype.chordTrackEmpty = function () {
	var isEmpty = true;
	for (var i = 0; i < this.chordTrack.length && isEmpty; i++) {
		if (this.chordTrack[i].cmd === 'note')
			isEmpty = false
	}
	return isEmpty;
}

ChordTrack.prototype.resolveChords = function (startTime, endTime) {
	// If there is a rhythm head anywhere in the measure then don't add a separate rhythm track
	if (this.hasRhythmHead)
		return

	var num = this.meter.num;
	var den = this.meter.den;
	var beatLength = 1 / den;
	var noteLength = beatLength / 2;
	var thisMeasureLength = parseInt(num, 10) / parseInt(den, 10);
	var portionOfAMeasure = thisMeasureLength - (endTime - startTime) / this.tempoChangeFactor;
	if (Math.abs(portionOfAMeasure) < 0.00001)
		portionOfAMeasure = 0;

	 // there wasn't a new chord this measure, so use the last chord declared.
	 // also the case where there is a chord declared in the measure, but not on its first beat.
	if (this.currentChords.length === 0 || this.currentChords[0].beat !== 0) {
		this.currentChords.unshift({ beat: 0, chord: this.chordLastBar });
	}

	//console.log(this.currentChords)
	var currentChordsExpanded = expandCurrentChords(this.currentChords, 8*num/den, beatLength)
	//console.log(currentChordsExpanded)
	var thisPattern = this.overridePattern ? this.overridePattern : this.rhythmPatterns[num + '/' + den]
	if (portionOfAMeasure) {
		thisPattern = [];
		var beatsPresent = ((endTime - startTime) / this.tempoChangeFactor) * 8;
		for (var p = 0; p < beatsPresent/2; p += 2) {
			thisPattern.push("chick");
			thisPattern.push("");
		}
	}
	if (!thisPattern) {
		thisPattern = []
		for (var p = 0; p < (8*num/den)/2; p++) {
			thisPattern.push('chick')
			thisPattern.push("");
		}
	}
	var firstBoom = true
	// If the pattern is overridden, it might be longer than the length of a measure. If so, then ignore the rest of it
	var minLength = Math.min(thisPattern.length, currentChordsExpanded.length)
	for (var p = 0; p < minLength; p++) {
		if (p > 0 && currentChordsExpanded[p-1] && currentChordsExpanded[p] && currentChordsExpanded[p-1].boom !== currentChordsExpanded[p].boom)
			firstBoom = true
		var type = thisPattern[p]
		var isBoom = type.indexOf('boom') >= 0
		// If we changed chords at a time when we're not expecting a bass note, then add an extra bass note in if the first thing in the pattern is a bass note.
		var newBass = !isBoom &&
			p !== 0 &&
			thisPattern[0].indexOf('boom') >= 0 &&
			(!currentChordsExpanded[p-1] || currentChordsExpanded[p-1].boom !== currentChordsExpanded[p].boom)
		var pitches = resolvePitch(currentChordsExpanded[p], type, firstBoom, newBass)
		if (isBoom)
			firstBoom = false
		for (var oo = 0; oo < pitches.length; oo++) {
			this.writeNote(pitches[oo], 
				0.125,
				isBoom || newBass ? this.boomVolume : this.chickVolume,
				p,
				noteLength,
				isBoom || newBass ? this.bassInstrument : this.chordInstrument
			)
			if (newBass)
				newBass = false
			else
				isBoom = false // only the first note in a chord is a bass note. This handles the case where bass and chord are played at the same time.
		}
	}
	return
}

ChordTrack.prototype.processChord = function (elem) {
	if (this.chordTrackFinished)
		return
	var chord = this.findChord(elem);
	if (chord) {
		var c = this.interpretChord(chord);
		// If this isn't a recognized chord, just completely ignore it.
		if (c) {
			// If we ever have a chord in this voice, then we add the chord track.
			// However, if there are chords on more than one voice, then just use the first voice.
			if (this.chordTrack.length === 0) {
				this.chordTrack.push({ cmd: 'program', channel: this.chordChannel, instrument: this.chordInstrument });
			}

			this.lastChord = c;
			var barBeat = calcBeat(this.lastBarTime, timeToRealTime(elem.time));
			this.currentChords.push({ chord: this.lastChord, beat: barBeat, start: timeToRealTime(elem.time) });
		}
	}
}

function resolvePitch(currentChord, type, firstBoom, newBass) {
	var ret = []
	if (!currentChord)
		return ret
	if (type.indexOf('boom') >= 0)
		ret.push(firstBoom ? currentChord.boom : currentChord.boom2)
	else if (newBass)
		ret.push(currentChord.boom)
	var numChordNotes = currentChord.chick.length
	if (type.indexOf('chick') >= 0) {
		for (var i = 0; i < numChordNotes; i++)
			ret.push(currentChord.chick[i])
	}
	switch (type) {
		case 'DO': ret.push(currentChord.chick[0]); break;
		case 'MI': ret.push(currentChord.chick[1]); break;
		case 'SOL': ret.push(extractNote(currentChord,2)); break;
		case 'TI': ret.push(extractNote(currentChord,3)); break;
		case 'TOP': ret.push(extractNote(currentChord,4)); break;
		case 'do': ret.push(currentChord.chick[0]+12); break;
		case 'mi': ret.push(currentChord.chick[1]+12); break;
		case 'sol': ret.push(extractNote(currentChord,2)+12); break;
		case 'ti': ret.push(extractNote(currentChord,3)+12); break;
		case 'top': ret.push(extractNote(currentChord,4)+12); break;
	}
	return ret
}

function extractNote(chord, index) {
	// This creates an arpeggio note no matter how many notes are in the chord - if it runs out of notes it continues in the next octave
	var octave = Math.floor(index / chord.chick.length)
	var note = chord.chick[index % chord.chick.length]
	//console.log(chord.chick, {index, octave, note}, index % chord.chick.length)
	return note + octave * 12
}

function parseGChord(gchord) {
	// TODO-PER: The spec is more complicated than this but for now this will not try to do anything with error cases like the wrong number of beats.
	var pattern = []
	for (var i = 0; i < gchord.length; i++) {
		var ch = gchord[i]
		switch(ch) {
			case 'z' : pattern.push(''); break;
			case '2' : pattern.push(''); break; // TODO-PER: This should extend the last note, but that's a small effect
			case 'c' : pattern.push('chick'); break;
			case 'b' : pattern.push('boom&chick'); break;
			case 'f' : pattern.push('boom'); break;
			case 'G' : pattern.push('DO'); break;
			case 'H' : pattern.push('MI'); break;
			case 'I' : pattern.push('SOL'); break;
			case 'J' : pattern.push('TI'); break;
			case 'K' : pattern.push('TOP'); break;
			case 'g' : pattern.push('do'); break;
			case 'h' : pattern.push('mi'); break;
			case 'i' : pattern.push('sol'); break;
			case 'j' : pattern.push('ti'); break;
			case 'k' : pattern.push('top'); break;
		}
	}
	return pattern
}

// This returns an array that has a chord for each 1/8th note position in the current measure
function expandCurrentChords(currentChords, num8thNotes, beatLength) {
	beatLength = beatLength * 8 // this is expressed as a fraction, so that 0.25 is a quarter notes. We want it to be the number of 8th notes
	var chords = []
	if (currentChords.length === 0)
		return chords

	var currentChord = currentChords[0].chord
	for (var i = 1; i < currentChords.length; i++) {
		var current = currentChords[i]
		while (chords.length < current.beat) {
			chords.push(currentChord)
		}
		currentChord = current.chord
	}
	while (chords.length < num8thNotes)
		chords.push(currentChord)
	return chords
}

function calcBeat(measureStart, currTime) {
	var distanceFromStart = currTime - measureStart;
	return distanceFromStart * 8;
}

ChordTrack.prototype.breakSynonyms = ['break', '(break)', 'no chord', 'n.c.', 'tacet'];

ChordTrack.prototype.basses = {
	'A': 33, 'B': 35, 'C': 36, 'D': 38, 'E': 40, 'F': 41, 'G': 43
};

ChordTrack.prototype.chordIntervals = {
	// diminished (all flat 5 chords)
	'dim': [0, 3, 6],
	'°': [0, 3, 6],
	'˚': [0, 3, 6],

	'dim7': [0, 3, 6, 9],
	'°7': [0, 3, 6, 9],
	'˚7': [0, 3, 6, 9],

	'ø7': [0, 3, 6, 10],
	'm7(b5)': [0, 3, 6, 10],
	'm7b5': [0, 3, 6, 10],
	'm7♭5': [0, 3, 6, 10],
	'-7(b5)': [0, 3, 6, 10],
	'-7b5': [0, 3, 6, 10],

	'7b5': [0, 4, 6, 10],
	'7(b5)': [0, 4, 6, 10],
	'7♭5': [0, 4, 6, 10],

	'7(b9,b5)': [0, 4, 6, 10, 13],
	'7b9,b5': [0, 4, 6, 10, 13],
	'7(#9,b5)': [0, 4, 6, 10, 15],
	'7#9b5': [0, 4, 6, 10, 15],
	'maj7(b5)': [0, 4, 6, 11],
	'maj7b5': [0, 4, 6, 11],
	'13(b5)': [0, 4, 6, 10, 14, 21],
	'13b5': [0, 4, 6, 10, 14, 21],

	// minor (all normal 5, minor 3 chords)
	'm': [0, 3, 7],
	'-': [0, 3, 7],
	'm6': [0, 3, 7, 9],
	'-6': [0, 3, 7, 9],
	'm7': [0, 3, 7, 10],
	'-7': [0, 3, 7, 10],

	'-(b6)': [0, 3, 7, 8],
	'-b6': [0, 3, 7, 8],
	'-6/9': [0, 3, 7, 9, 14],
	'-7(b9)': [0, 3, 7, 10, 13],
	'-7b9': [0, 3, 7, 10, 13],
	'-maj7': [0, 3, 7, 11],
	'-9+7': [0, 3, 7, 11, 13],
	'-11': [0, 3, 7, 11, 14, 17],
	'm11': [0, 3, 7, 11, 14, 17],
	'-maj9': [0, 3, 7, 11, 14],
	'-∆9': [0, 3, 7, 11, 14],
	'mM9': [0, 3, 7, 11, 14],

	// major (all normal 5, major 3 chords)
	'M': [0, 4, 7],
	'6': [0, 4, 7, 9],
	'6/9': [0, 4, 7, 9, 14],
	'6add9': [0, 4, 7, 9, 14],
	'69': [0, 4, 7, 9, 14],

	'7': [0, 4, 7, 10],
	'9': [0, 4, 7, 10, 14],
	'11': [0, 7, 10, 14, 17],
	'13': [0, 4, 7, 10, 14, 21],
	'7b9': [0, 4, 7, 10, 13],
	'7♭9': [0, 4, 7, 10, 13],
	'7(b9)': [0, 4, 7, 10, 13],
	'7(#9)': [0, 4, 7, 10, 15],
	'7#9': [0, 4, 7, 10, 15],
	'(13)': [0, 4, 7, 10, 14, 21],
	'7(9,13)': [0, 4, 7, 10, 14, 21],
	'7(#9,b13)': [0, 4, 7, 10, 15, 20],
	'7(#11)': [0, 4, 7, 10, 14, 18],
	'7#11': [0, 4, 7, 10, 14, 18],
	'7(b13)': [0, 4, 7, 10, 20],
	'7b13': [0, 4, 7, 10, 20],
	'9(#11)': [0, 4, 7, 10, 14, 18],
	'9#11': [0, 4, 7, 10, 14, 18],
	'13(#11)': [0, 4, 7, 10, 18, 21],
	'13#11': [0, 4, 7, 10, 18, 21],

	'maj7': [0, 4, 7, 11],
	'∆7': [0, 4, 7, 11],
	'Δ7': [0, 4, 7, 11],
	'maj9': [0, 4, 7, 11, 14],
	'maj7(9)': [0, 4, 7, 11, 14],
	'maj7(11)': [0, 4, 7, 11, 17],
	'maj7(#11)': [0, 4, 7, 11, 18],
	'maj7(13)': [0, 4, 7, 14, 21],
	'maj7(9,13)': [0, 4, 7, 11, 14, 21],

	'7sus4': [0, 5, 7, 10],
	'm7sus4': [0, 3, 7, 10, 17],
	'sus4': [0, 5, 7],
	'sus2': [0, 2, 7],
	'7sus2': [0, 2, 7, 10],
	'9sus4': [0, 5, 7, 10, 14],
	'13sus4': [0, 5, 7, 10, 14, 21],

	// augmented (all sharp 5 chords)
	'aug7': [0, 4, 8, 10],
	'+7': [0, 4, 8, 10],
	'+': [0, 4, 8],
	'7#5': [0, 4, 8, 10],
	'7♯5': [0, 4, 8, 10],
	'7+5': [0, 4, 8, 10],
	'9#5': [0, 4, 8, 10, 14],
	'9♯5': [0, 4, 8, 10, 14],
	'9+5': [0, 4, 8, 10, 14],
	'-7(#5)': [0, 3, 8, 10],
	'-7#5': [0, 3, 8, 10],
	'7(#5)': [0, 4, 8, 10],
	'7(b9,#5)': [0, 4, 8, 10, 13],
	'7b9#5': [0, 4, 8, 10, 13],
	'maj7(#5)': [0, 4, 8, 11],
	'maj7#5': [0, 4, 8, 11],
	'maj7(#5,#11)': [0, 4, 8, 11, 18],
	'maj7#5#11': [0, 4, 8, 11, 18],
	'9(#5)': [0, 4, 8, 10, 14],
	'13(#5)': [0, 4, 8, 10, 14, 21],
	'13#5': [0, 4, 8, 10, 14, 21],
	// MAE Power chords added 10 April 2024
	'5': [0, 7],
	'5(8)': [0, 7, 12],
	'5add8': [0, 7, 12]

};

ChordTrack.prototype.rhythmPatterns = {
	"2/2": ['boom', '', '', '', 'chick', '', '', ''],
	"3/2": ['boom', '', '', '', 'chick', '', '', '', 'chick', '', '', ''],
	"4/2": ['boom', '', '', '', 'chick', '', '', '', 'boom', '', '', '', 'chick', '', '', ''],

	"2/4": ['boom', '', 'chick', ''],
	"3/4": ['boom', '', 'chick', '', 'chick', ''],
	"4/4": ['boom', '', 'chick', '', 'boom', '', 'chick', ''],
	"5/4": ['boom', '', 'chick', '', 'chick', '', 'boom', '', 'chick', ''],
	"6/4": ['boom', '', 'chick', '', 'boom', '', 'chick', '', 'boom', '', 'chick', ''],

	"3/8": ['boom', '', 'chick'],
	"5/8": ['boom', 'chick', 'chick', 'boom', 'chick'],
	"6/8": ['boom', '', 'chick', 'boom', '', 'chick'],
	"7/8": ['boom', 'chick', 'chick', 'boom', 'chick', 'boom', 'chick'],
	"9/8": ['boom', '', 'chick', 'boom', '', 'chick', 'boom', '', 'chick'],
	"10/8": ['boom', 'chick', 'chick', 'boom', 'chick', 'chick', 'boom', 'chick', 'boom', 'chick'],
	"11/8": ['boom', 'chick', 'chick', 'boom', 'chick', 'chick', 'boom', 'chick', 'boom', 'chick', 'chick'],
	"12/8": ['boom', '', 'chick', 'boom', '', 'chick', 'boom', '', 'chick', 'boom', '', 'chick'],
};

// TODO-PER: these are repeated in flattener. Can it be shared?

function timeToRealTime(time) {
	return time / 1000000;
}

function durationRounded(duration, tempoChangeFactor) {
	return Math.round(duration * tempoChangeFactor * 1000000) / 1000000;
}

module.exports = ChordTrack;
