1 /** 2 * Copyright © Underground Rekordz 2019 3 * License: MIT (https://github.com/UndergroundRekordz/Musicpulator/blob/master/LICENSE) 4 * Author: Jacob Jensen (bausshf) 5 */ 6 module musicpulator.songsequence; 7 8 import std.algorithm : map, sum; 9 import std.array : array, join; 10 import std.string : format; 11 12 import musicpulator.musicalnote; 13 import musicpulator.core; 14 import musicpulator.constants; 15 16 /// Aliases for the song sequence entry collection. 17 private alias SongSequenceEntryCollection = InternalMaxSizeCollection!(size_t, 32); 18 19 /// Wrapper around a song sequence. 20 final class SongSequence 21 { 22 private: 23 /// The note of the sequence. 24 MusicalNote _note; 25 /// The entries of the sequence. 26 SongSequenceEntryCollection _entries; 27 /// The bar of the sequence. 28 size_t _bar; 29 /// The octave of the sequence. 30 size_t _octave; 31 32 public: 33 final: 34 /** 35 * Creates a new song sequence. 36 * Params: 37 * note = The note of the sequence. 38 * bar = The bar of the sequence. 39 * octave = The octave of the sequence. 40 * sequence = The sequence entries. 41 */ 42 this(MusicalNote note, size_t bar, size_t octave, size_t[] sequence) 43 { 44 _note = note; 45 _bar = bar; 46 _octave = octave; 47 48 foreach (s; sequence) 49 { 50 addEntry(s); 51 } 52 } 53 54 @property 55 { 56 /// Gets the note of the sequence. 57 MusicalNote note() { return _note; } 58 59 /// Gets the entries of the sequence. 60 SongSequenceEntryCollection entries() { return _entries; } 61 62 /// Gets the bar of the sequence. 63 size_t bar() { return _bar; } 64 65 /// Gets the octave of the sequence. 66 size_t octave() { return _octave; } 67 } 68 69 /** 70 * Adds an entry to the sequence. 71 * Params: 72 * length = The length of the entry to add. 73 */ 74 void addEntry(size_t length) 75 { 76 size_t maxLength = songBarSize; 77 78 if (_entries.length) 79 { 80 maxLength = songBarSize - _entries.sum(); 81 } 82 83 if (length > maxLength) 84 { 85 length = maxLength; 86 } 87 else if (length == 0) 88 { 89 length = 1; 90 } 91 92 _entries.add(length); 93 } 94 95 /// Converts the sequence to a string. This calls toJson(). 96 override string toString() 97 { 98 return toJson(); 99 } 100 101 /// Converts the sequence to json. 102 string toJson() 103 { 104 return `{"note":%s,"bar":%d,"octave":%d,"sequenceEntry":%s}` 105 .format(_note.toJson(), bar, _octave, _entries); 106 } 107 108 /// Converts the sequence to xml. 109 string toXml() 110 { 111 auto entryXml = ""; 112 113 if (_entries.length) 114 { 115 entryXml = _entries.map!(e => format(`<SequenceEntry length="%d" />`, e)).array.join; 116 } 117 118 return `<SongSequence note="%s" bar="%d" octave="%d">%s</SongSequence>` 119 .format(_note, bar, _octave, entryXml); 120 } 121 }