1 module test1.sampleman; 2 3 import pixelperfectengine.concrete.window; 4 import pixelperfectengine.audio.base.types; 5 import pixelperfectengine.audio.base.func; 6 import pixelperfectengine.audio.base.config; 7 import std.math : floor, nearbyint; 8 import std.conv; 9 import test1.app; 10 import test1.editorevents; 11 12 public class WaveformViewer : WindowElement { 13 int[] waveform; 14 public this(string source, Box position) { 15 this.source = source; 16 this.position = position; 17 } 18 public void setWaveform(const(ubyte)[] src, WaveFormat fmt) { 19 DecoderWorkpad wp; 20 switch (fmt.format) { 21 case AudioFormat.PCM: 22 if (fmt.bitsPerSample == 8) { 23 waveform.length = src.length; 24 decode8bitPCM(cast(const(ubyte)[])src, waveform, wp); 25 } else if (fmt.bitsPerSample == 16) { 26 waveform.length = src.length / 2; 27 decode16bitPCM(cast(const(short)[])src, waveform, wp); 28 } 29 break; 30 case AudioFormat.ADPCM, AudioFormat.IMA_ADPCM: 31 waveform.length = src.length * 2; 32 decode4bitIMAADPCM(ADPCMStream(src.dup, src.length*2), waveform, wp); 33 break; 34 case AudioFormat.DIALOGIC_OKI_ADPCM, AudioFormat.OKI_ADPCM: 35 waveform.length = src.length * 2; 36 decode4bitDialogicADPCM(ADPCMStream(src.dup, src.length*2), waveform, wp); 37 break; 38 case AudioFormat.MULAW: 39 waveform.length = src.length; 40 decodeMuLawStream(cast(const(ubyte)[])src, waveform, wp); 41 break; 42 case AudioFormat.ALAW: 43 waveform.length = src.length; 44 decodeALawStream(cast(const(ubyte)[])src, waveform, wp); 45 break; 46 default: 47 return; 48 } 49 } 50 public override void draw() { 51 if (parent is null) return; 52 StyleSheet ss = getStyleSheet(); 53 parent.clearArea(position); 54 parent.drawBox(position, 24); 55 if (waveform.length) { 56 real ratio = cast(real)waveform.length / position.width; 57 const int divident = ushort.max / position.height() * -1; 58 { 59 Point o = Point(0, position.height / 2); 60 parent.drawLine(position.cornerUL + o, position.cornerUR + o, 23); 61 } 62 Point p0 = Point(position.left, (waveform[0] / divident) + position.top + (position.height / 2)); 63 for (int i ; i < position.width - 1 ; i++) { 64 /+Point p0 = 65 Point(i + position.left, 66 (waveform[cast(size_t)nearbyint(i * ratio)] / divident) + position.top + (position.height / 2));+/ 67 const Point p1 = 68 Point(i + position.left + 1, 69 (waveform[cast(size_t)nearbyint(i * ratio) + 1] / divident) + position.top + (position.height / 2)); 70 parent.drawLine(p0, p1, 0x1F); 71 p0 = p1; 72 } 73 74 if (isFocused) { 75 const int textPadding = ss.drawParameters["horizTextPadding"]; 76 parent.drawBoxPattern(position - textPadding, ss.pattern["blackDottedLine"]); 77 } 78 } 79 if (state == ElementState.Disabled) { 80 parent.bitBLTPattern(position, ss.getImage("ElementDisabledPtrn")); 81 } 82 if (onDraw !is null) { 83 onDraw(); 84 } 85 } 86 } 87 88 public class SampleMan : Window { 89 ListView listView_sampleList; 90 Button button_load; 91 Button button_slice; 92 Button button_remove; 93 Label label_info; 94 Label label_format; 95 Label label_slmpR; 96 Label label_len; 97 WaveformViewer wfv; 98 99 AudioDevKit adk; 100 101 WaveFileData[] waveFileData; 102 string path; 103 104 string moduleName; 105 //TextBox textBox0; 106 public this(AudioDevKit adk) { 107 moduleName = adk.selectedModID; 108 this.adk = adk; 109 110 super(Box(0, 0, 520, 322), "Sample manager ["d ~ moduleName.to!dstring ~ "]"d); 111 listView_sampleList = new ListView(new ListViewHeader(16, [40, 120, 250], ["ID" ,"name" ,"file source"]), null, 112 "listView0", Box(5, 20, 335, 185)); 113 button_load = new Button("Load"d, "button0", Box(340, 20, 440, 40)); 114 button_slice = new Button("Slice"d, "button1", Box(340, 45, 440, 65)); 115 button_remove = new Button("Remove"d, "button0", Box(340, 70, 440, 90)); 116 label_info = new Label("Info:"d, "label0", Box(340, 95, 500, 115)); 117 label_format = new Label("Format:"d, "label1", Box(340, 118, 512, 138)); 118 label_slmpR = new Label("Orig. samplerate:"d, "label2", Box(340, 140, 512, 160)); 119 label_len = new Label("Length:"d, "label3", Box(340, 162, 512, 182)); 120 //textBox0 = new TextBox("Placeholder"d, "textBox0", Box(4, 190, 516, 318)); 121 wfv = new WaveformViewer("wfv", Box(4, 190, 516, 318)); 122 123 addElement(listView_sampleList); 124 addElement(button_load); 125 addElement(button_slice); 126 addElement(button_remove); 127 addElement(label_info); 128 addElement(label_format); 129 addElement(label_slmpR); 130 addElement(label_len); 131 addElement(wfv); 132 133 button_load.onMouseLClick = &button_load_onClick; 134 button_slice.onMouseLClick = &button_slice_onClick; 135 button_remove.onMouseLClick = &button_remove_onClick; 136 listView_sampleList.onItemSelect = &listView_sampleList_onSelect; 137 listView_sampleList.onTextInput = &listView_sampleList_onTextEdit; 138 listView_sampleList.editEnable = true; 139 140 refreshSampleList(); 141 } 142 protected void refreshSampleList() { 143 waveFileData = adk.mcfg.getWaveFileList(moduleName); 144 listView_sampleList.clear(); 145 foreach (WaveFileData key; waveFileData) { 146 listView_sampleList ~= new ListViewItem(16, [to!dstring(key.id), to!dstring(key.name), to!dstring(key.path)], 147 [TextInputFieldType.None, TextInputFieldType.ASCIIText, TextInputFieldType.None]); 148 } 149 listView_sampleList.refresh(); 150 } 151 protected void listView_sampleList_onSelect(Event ev) { 152 if (listView_sampleList.value >= 0) { 153 import pixelperfectengine.audio.base.modulebase; 154 ModuleConfig mcfg = adk.mcfg; 155 AudioModule am = mcfg.getModule(moduleName); 156 wfv.setWaveform(am.getWaveformData(listView_sampleList.value), am.getWaveformDataFormat(listView_sampleList.value)); 157 wfv.draw(); 158 WaveFormat wf = am.getWaveformDataFormat(listView_sampleList.value); 159 dstring format; 160 switch(wf.format) { 161 case AudioFormat.PCM: 162 if (wf.bitsPerSample == 8) { 163 format = "PCM 8Bit U"d; 164 } else if (wf.bitsPerSample == 16) { 165 format = "PCM 16Bit S"d; 166 } 167 break; 168 case AudioFormat.ADPCM, AudioFormat.IMA_ADPCM: 169 format = "IMA ADPCM 4Bit"d; 170 break; 171 case AudioFormat.DIALOGIC_OKI_ADPCM, AudioFormat.OKI_ADPCM: 172 format = "Dialogic ADPCM"d; 173 break; 174 case AudioFormat.MULAW: 175 format = "Mu-Law ADPCM"d; 176 break; 177 case AudioFormat.ALAW: 178 format = "A-Law ADPCM"d; 179 break; 180 default: 181 format = "UNKNOWN"; 182 break; 183 } 184 label_format.setText("Format: "d ~ format); 185 label_slmpR.setText("Orig. samplerate:"d ~ to!dstring(wf.samplerate)); 186 label_len.setText("Length:"d ~ to!dstring(wfv.waveform.length)); 187 } 188 } 189 protected void listView_sampleList_onTextEdit(Event ev) { 190 CellEditEvent cev = cast(CellEditEvent)ev; 191 if (listView_sampleList.value >= 0) { 192 WaveFileData wfd = waveFileData[listView_sampleList.value]; 193 adk.eventStack.addToTop(new RenameSample(adk.mcfg, moduleName, wfd.id, to!string(cev.text.toDString))); 194 } 195 } 196 protected void button_load_onClick(Event ev) { 197 import pixelperfectengine.concrete.dialogs.filedialog; 198 handler.addWindow(new FileDialog("Add sample"d, "sampleLoad", &onSampleLoad, 199 [FileDialog.FileAssociationDescriptor("Wave file", [".wav"]), 200 FileDialog.FileAssociationDescriptor("Dialogic ADPCM file", [".vox", ".ad4"])], "./")); 201 } 202 protected void onSampleLoad(Event ev) { 203 import pixelperfectengine.concrete.dialogs.textinputdialog; 204 FileEvent fev = cast(FileEvent)ev; 205 path = fev.getFullPath(); 206 handler.addWindow(new TextInputDialog(Box.bySize(0, 0, 500, 120), &onSampleCreate, "sampleID", "Add sample", 207 "Sample ID?")); 208 } 209 protected void onSampleCreate(Text tx) { 210 try { 211 const int sampleID = to!int(tx.toDString); 212 //check if sample exists 213 foreach (WaveFileData key; waveFileData) { 214 if (key.id == sampleID) return; 215 } 216 adk.eventStack.addToTop(new AddSampleFile(adk.mcfg, moduleName, sampleID, path)); 217 refreshSampleList(); 218 } catch (Exception e) { 219 220 } 221 } 222 protected void button_slice_onClick(Event ev) { 223 handler.addWindow(new SliceDialog(&onSliceCreate)); 224 } 225 protected void onSliceCreate(int id, int begin, int end) { 226 if (listView_sampleList.value >= 0) { 227 const int src = waveFileData[listView_sampleList.value].id; 228 const int len = end - begin; 229 adk.eventStack.addToTop(new AddSampleSlice(adk.mcfg, moduleName, id, src, begin, len)); 230 refreshSampleList(); 231 } 232 } 233 protected void button_remove_onClick(Event ev) { 234 if (listView_sampleList.value >= 0) { 235 const int selID = waveFileData[listView_sampleList.value].id; 236 adk.eventStack.addToTop(new RemoveSample(adk.mcfg, moduleName, selID)); 237 refreshSampleList(); 238 } 239 } 240 } 241 242 public class SliceDialog : Window { 243 Label label_newID; 244 Label label_from; 245 Label label_to; 246 TextBox textBox_newID; 247 TextBox textBox_from; 248 TextBox textBox_to; 249 Button button_create; 250 void delegate(int id, int begin, int end) onCreate; 251 public this(void delegate(int id, int begin, int end) onCreate) { 252 this.onCreate = onCreate; 253 super(Box.bySize(0,0,125,120), "Create new slice"); 254 label_newID = new Label("New ID:", "label_newID", Box(5,20,55,40)); 255 label_from = new Label("From:", "label_from", Box(5,45,55,65)); 256 label_to = new Label("To:", "label_to", Box(5,70,55,90)); 257 textBox_newID = new TextBox("", "textBox_newID", Box(55, 20, 120, 40)); 258 textBox_from = new TextBox("", "textBox_from", Box(55, 45, 120, 65)); 259 textBox_to = new TextBox("", "textBox_to", Box(55, 70, 120, 90)); 260 button_create = new Button("Create", "button_create", Box(60, 95, 120, 115)); 261 262 textBox_newID.setFilter(TextInputFieldType.IntegerP); 263 textBox_from.setFilter(TextInputFieldType.IntegerP); 264 textBox_to.setFilter(TextInputFieldType.IntegerP); 265 266 addElement(label_newID); 267 addElement(label_from); 268 addElement(label_to); 269 addElement(textBox_newID); 270 addElement(textBox_from); 271 addElement(textBox_to); 272 addElement(button_create); 273 button_create.onMouseLClick = &button_create_onClick; 274 } 275 protected void button_create_onClick(Event ev) { 276 onCreate(to!int(textBox_newID.getText.toDString), to!int(textBox_from.getText.toDString), 277 to!int(textBox_to.getText.toDString)); 278 close(); 279 } 280 }