1 /* Author: Romain "Artefact2" Dalmaso <artefact2@gmail.com> */
2 
3 /* This program is free software. It comes without any warranty, to the
4  * extent permitted by applicable law. You can redistribute it and/or
5  * modify it under the terms of the Do What The Fuck You Want To Public
6  * License, Version 2, as published by Sam Hocevar. See
7  * http://sam.zoy.org/wtfpl/COPYING for more details. */
8 module audioformats.libxm;
9 
10 import core.stdc.config: c_ulong;
11 import core.stdc.stdlib: malloc, free;
12 import core.stdc.string: memcpy, memcmp, memset;
13 
14 import dplug.core.math;
15 
16 nothrow:
17 @nogc:
18 
19 private alias int8_t = byte;
20 private alias int16_t = short;
21 private alias int32_t = int;
22 private alias uint8_t = ubyte;
23 private alias uint16_t = ushort;
24 private alias uint32_t = uint;
25 private alias uint64_t = ulong;
26 
27 // xm_internal.h
28 
29 version(BigEndian)
30 {
31     static assert(false, "Big endian platforms are not yet supported, sorry");
32 }
33 
34 /* ----- XM constants ----- */
35 
36 enum SAMPLE_NAME_LENGTH = 22;
37 enum INSTRUMENT_HEADER_LENGTH = 263;
38 enum INSTRUMENT_NAME_LENGTH = 22;
39 enum MODULE_NAME_LENGTH = 20;
40 enum TRACKER_NAME_LENGTH = 20;
41 enum PATTERN_ORDER_TABLE_LENGTH = 256;
42 enum NUM_NOTES = 96;
43 enum NUM_ENVELOPE_POINTS = 12;
44 enum MAX_NUM_ROWS = 256;
45 
46 
47 // Options
48 version = XM_RAMPING; // sounds better to me when on
49 //version = XM_STRINGS;
50 enum XM_DEFENSIVE = true;
51 enum XM_LINEAR_INTERPOLATION = false; // sounds better/digital to me when off
52 enum XM_DEBUG = false;
53 
54 version(XM_RAMPING)
55 {
56     enum XM_SAMPLE_RAMPING_POINTS = 0x20;
57 }
58 
59 /* ----- Data types ----- */
60 
61 alias xm_waveform_type_t = int;
62 enum : xm_waveform_type_t {
63     XM_SINE_WAVEFORM = 0,
64     XM_RAMP_DOWN_WAVEFORM = 1,
65     XM_SQUARE_WAVEFORM = 2,
66     XM_RANDOM_WAVEFORM = 3,
67     XM_RAMP_UP_WAVEFORM = 4,
68 }
69 
70 alias xm_loop_type_t = int;
71 enum : xm_loop_type_t
72 {
73     XM_NO_LOOP,
74     XM_FORWARD_LOOP,
75     XM_PING_PONG_LOOP,
76 }
77 
78 alias xm_frequency_type_t = int;
79 enum : xm_frequency_type_t 
80 {
81     XM_LINEAR_FREQUENCIES,
82     XM_AMIGA_FREQUENCIES,
83 }
84 
85 struct xm_envelope_point_t 
86 {
87     uint16_t frame;
88     uint16_t value;
89 }
90 
91 struct xm_envelope_t
92 {
93     xm_envelope_point_t[NUM_ENVELOPE_POINTS] points;
94     uint8_t num_points;
95     uint8_t sustain_point;
96     uint8_t loop_start_point;
97     uint8_t loop_end_point;
98     bool enabled;
99     bool sustain_enabled;
100     bool loop_enabled;
101 }
102 
103 struct xm_sample_t 
104 {
105     version(XM_STRINGS)
106     {
107         char[SAMPLE_NAME_LENGTH + 1] name;
108     }
109 
110     uint8_t bits; /* Either 8 or 16 */
111 
112     uint32_t length;
113     uint32_t loop_start;
114     uint32_t loop_length;
115     uint32_t loop_end;
116     float volume;
117     int8_t finetune;
118     xm_loop_type_t loop_type;
119     float panning;
120     int8_t relative_note;
121     uint64_t latest_trigger;
122 
123     union {
124         int8_t* data8;
125         int16_t* data16;
126     };
127 }
128 
129 struct xm_instrument_t
130 {
131     version(XM_STRINGS)
132     {
133          char[INSTRUMENT_NAME_LENGTH + 1] name;
134     }
135     uint16_t num_samples;
136     uint8_t[NUM_NOTES] sample_of_notes;
137     xm_envelope_t volume_envelope;
138     xm_envelope_t panning_envelope;
139     xm_waveform_type_t vibrato_type;
140     uint8_t vibrato_sweep;
141     uint8_t vibrato_depth;
142     uint8_t vibrato_rate;
143     uint16_t volume_fadeout;
144     uint64_t latest_trigger;
145     bool muted;
146 
147     xm_sample_t* samples;
148 }
149 
150 struct xm_pattern_slot_t 
151 {
152     uint8_t note; /* 1-96, 97 = Key Off note */
153     uint8_t instrument; /* 1-128 */
154     uint8_t volume_column;
155     uint8_t effect_type;
156     uint8_t effect_param;
157 
158     nothrow:
159     @nogc:
160 
161     bool HAS_TONE_PORTAMENTO()
162     {
163         return effect_type == 3  || effect_type == 5 || ((volume_column >> 4) == 0xF);
164     }
165 
166     bool HAS_ARPEGGIO()
167     {
168         return effect_param != 0;
169     }
170 
171     bool HAS_VIBRATO()
172     {
173         return effect_type == 4 || effect_type == 6 || (volume_column >> 4) == 0xB;
174     }
175 }
176 
177 struct xm_pattern_t
178 {
179     uint16_t num_rows;
180     xm_pattern_slot_t* slots; /* Array of size num_rows * num_channels */
181 }
182 
183 struct xm_module_t 
184 {
185     version(XM_STRINGS)
186     {
187         char[MODULE_NAME_LENGTH + 1] name;
188         char[TRACKER_NAME_LENGTH + 1] trackername;
189     }
190 
191     uint16_t length;
192     uint16_t restart_position;
193     uint16_t num_channels;
194     uint16_t num_patterns;
195     uint16_t num_instruments;
196     xm_frequency_type_t frequency_type;
197     uint8_t[PATTERN_ORDER_TABLE_LENGTH] pattern_table;
198 
199     xm_pattern_t* patterns;
200     xm_instrument_t* instruments; /* Instrument 1 has index 0,
201                                    * instrument 2 has index 1, etc. */
202 }
203 
204 struct xm_channel_context_t 
205 {
206     float note;
207     float orig_note; /* The original note before effect modifications, as read in the pattern. */
208     xm_instrument_t* instrument; /* Could be null */
209     xm_sample_t* sample; /* Could be null */
210     xm_pattern_slot_t* current;
211 
212     float sample_position;
213     float period;
214     float frequency;
215     float step;
216     bool ping; /* For ping-pong samples: true is -., false is <-- */
217 
218     float volume; /* Ideally between 0 (muted) and 1 (loudest) */
219     float panning; /* Between 0 (left) and 1 (right); 0.5 is centered */
220 
221     uint16_t autovibrato_ticks;
222 
223     bool sustained;
224     float fadeout_volume;
225     float volume_envelope_volume;
226     float panning_envelope_panning;
227     uint16_t volume_envelope_frame_count;
228     uint16_t panning_envelope_frame_count;
229 
230     float autovibrato_note_offset;
231 
232     bool arp_in_progress;
233     uint8_t arp_note_offset;
234     uint8_t volume_slide_param;
235     uint8_t fine_volume_slide_param;
236     uint8_t global_volume_slide_param;
237     uint8_t panning_slide_param;
238     uint8_t portamento_up_param;
239     uint8_t portamento_down_param;
240     uint8_t fine_portamento_up_param;
241     uint8_t fine_portamento_down_param;
242     uint8_t extra_fine_portamento_up_param;
243     uint8_t extra_fine_portamento_down_param;
244     uint8_t tone_portamento_param;
245     float tone_portamento_target_period;
246     uint8_t multi_retrig_param;
247     uint8_t note_delay_param;
248     uint8_t pattern_loop_origin; /* Where to restart a E6y loop */
249     uint8_t pattern_loop_count; /* How many loop passes have been done */
250     bool vibrato_in_progress;
251     xm_waveform_type_t vibrato_waveform;
252     bool vibrato_waveform_retrigger; /* True if a new note retriggers the waveform */
253     uint8_t vibrato_param;
254     uint16_t vibrato_ticks; /* Position in the waveform */
255     float vibrato_note_offset;
256     xm_waveform_type_t tremolo_waveform;
257     bool tremolo_waveform_retrigger;
258     uint8_t tremolo_param;
259     uint8_t tremolo_ticks;
260     float tremolo_volume;
261     uint8_t tremor_param;
262     bool tremor_on;
263 
264     uint64_t latest_trigger;
265     bool muted;
266 
267     version(XM_RAMPING)
268     {
269         /* These values are updated at the end of each tick, to save
270          * a couple of float operations on every generated sample. */
271         float[2] target_volume;
272 
273         c_ulong frame_count;
274         float[XM_SAMPLE_RAMPING_POINTS] end_of_previous_sample;
275     }
276 
277     float[2] actual_volume;
278 }
279 
280 struct xm_context_t
281 {
282     size_t ctx_size; /* Must be first, see xm_create_context_from_libxmize() */
283     xm_module_t module_;
284     uint32_t rate;
285 
286     uint16_t tempo;
287     uint16_t bpm;
288     float global_volume;
289     float amplification;
290 
291     version(XM_RAMPING)
292     {
293         /* How much is a channel final volume allowed to change per
294          * sample; this is used to avoid abrubt volume changes which
295          * manifest as "clicks" in the generated sound. */
296         float volume_ramp;
297     }
298 
299     uint next_rand;
300 
301     uint8_t current_table_index;
302     uint8_t current_row;
303     uint16_t current_tick; /* Can go below 255, with high tempo and a pattern delay */
304     float remaining_samples_in_tick;
305     uint64_t generated_samples;
306 
307     bool position_jump;
308     bool pattern_break;
309     uint8_t jump_dest;
310     uint8_t jump_row;
311 
312 
313     /* Extra ticks to be played before going to the next row -
314      * Used for EEy effect */
315     uint16_t extra_ticks;
316 
317     uint8_t* row_loop_count; /* Array of size MAX_NUM_ROWS * module_length */
318     uint8_t loop_count;
319     uint8_t max_loop_count;
320 
321     xm_channel_context_t* channels;
322 }
323 
324 // xm.c
325 
326 /* .xm files are little-endian. */
327 
328 /* Bounded reader macros.
329 * If we attempt to read the buffer out-of-bounds, pretend that the buffer is
330 * infinitely padded with zeroes.
331 */
332 /*
333 #define READ_U8_BOUND(offset, bound) (((offset) < bound) ? (*(uint8_t*)(moddata + (offset))) : 0)
334 #define READ_U16_BOUND(offset, bound) ((uint16_t)READ_U8(offset) | ((uint16_t)READ_U8((offset) + 1) << 8))
335 #define READ_U32_BOUND(offset, bound) ((uint32_t)READ_U16(offset) | ((uint32_t)READ_U16((offset) + 2) << 16))
336 #define READ_MEMCPY_BOUND(ptr, offset, length, bound) memcpy_pad(ptr, length, moddata, bound, offset)
337 
338 #define READ_U8(offset) READ_U8_BOUND(offset, moddata_length)
339 #define READ_U16(offset) READ_U16_BOUND(offset, moddata_length)
340 #define READ_U32(offset) READ_U32_BOUND(offset, moddata_length)
341 #define READ_MEMCPY(ptr, offset, length) READ_MEMCPY_BOUND(ptr, offset, length, moddata_length)
342 */
343 void memcpy_pad(void* dst, size_t dst_len, const(void)* src, size_t src_len, size_t offset) 
344 {
345     uint8_t* dst_c = cast(uint8_t*)dst;
346     const(uint8_t)* src_c = cast(const(uint8_t)*)src;
347 
348     /* how many bytes can be copied without overrunning `src` */
349     size_t copy_bytes = (src_len >= offset) ? (src_len - offset) : 0;
350     copy_bytes = copy_bytes > dst_len ? dst_len : copy_bytes;
351 
352     memcpy(dst_c, src_c + offset, copy_bytes);
353     /* padded bytes */
354     memset(dst_c + copy_bytes, 0, dst_len - copy_bytes);
355 }
356 
357 /** Check the module data for errors/inconsistencies.
358  *
359  * @returns 0 if everything looks OK. Module should be safe to load.
360  */
361 int xm_check_sanity_preload(const(char)* module_, size_t module_length) 
362 {
363     if(module_length < 60) {
364         return 4;
365     }
366 
367     if(memcmp("Extended Module: ".ptr, module_, 17) != 0) {
368         return 1;
369     }
370 
371     if(module_[37] != 0x1A) {
372         return 2;
373     }
374 
375     if(module_[59] != 0x01 || module_[58] != 0x04) {
376         /* Not XM 1.04 */
377         return 3;
378     }
379 
380     return 0;
381 }
382 
383 /** Check a loaded module for errors/inconsistencies.
384  *
385  * @returns 0 if everything looks OK.
386  */
387 
388 int xm_check_sanity_postload(xm_context_t* ctx) 
389 {   
390     /* @todo: plenty of stuff to do here */
391 
392     /* Check the POT */
393     for(uint8_t i = 0; i < ctx.module_.length; ++i) {
394         if(ctx.module_.pattern_table[i] >= ctx.module_.num_patterns) {
395             if(i+1 == ctx.module_.length && ctx.module_.length > 1) {
396                 /* Cheap fix */
397                 --ctx.module_.length;
398                 // DEBUG("trimming invalid POT at pos %X", i);
399             } 
400             else 
401             {
402                 import core.stdc.stdio;
403                 printf("module has invalid POT, pos %X references nonexistent pattern %X", i, ctx.module_.pattern_table[i]);
404                 
405                 return 1;
406             }
407         }
408     }
409 
410     return 0;
411 }
412 
413 /** Get the number of bytes needed to store the module data in a
414  * dynamically allocated blank context.
415  *
416  * Things that are dynamically allocated:
417  * - sample data
418  * - sample structures in instruments
419  * - pattern data
420  * - row loop count arrays
421  * - pattern structures in module
422  * - instrument structures in module
423  * - channel contexts
424  * - context structure itself
425 
426  * @returns 0 if everything looks OK.
427  */
428 size_t xm_get_memory_needed_for_context(const char* moddata, size_t moddata_length) 
429 {
430     size_t memory_needed = 0;
431     size_t offset = 60; /* Skip the first header */
432     uint16_t num_channels;
433     uint16_t num_patterns;
434     uint16_t num_instruments;
435 
436     /* Read the module header */
437 
438     ubyte READ_U8_BOUND(size_t offset, size_t bound)
439     {
440         return (offset < bound) ? *cast(uint8_t*)(moddata + offset) : 0;
441     }
442 
443     ubyte READ_U8(size_t offset)
444     {
445         return READ_U8_BOUND(offset, moddata_length);
446     }
447 
448     ushort READ_U16_BOUND(size_t offset, size_t bound)
449     {
450         return (cast(uint16_t)READ_U8(offset) | (cast(uint16_t)READ_U8((offset) + 1) << 8));
451     }
452 
453     ushort READ_U16(size_t offset)
454     {
455         return READ_U16_BOUND(offset, moddata_length);
456     }
457 
458     uint READ_U32_BOUND(size_t offset, size_t bound)
459     {
460         return (cast(uint32_t)READ_U16(offset) | (cast(uint32_t)READ_U16((offset) + 2) << 16));
461     }
462 
463     uint READ_U32(size_t offset)
464     {
465         return READ_U32_BOUND(offset, moddata_length);
466     }
467 
468     void READ_MEMCPY_BOUND(void* ptr, size_t offset, size_t length, size_t bound)
469     {
470         memcpy_pad(ptr, length, moddata, bound, offset);
471     }
472 
473     void READ_MEMCPY(void* ptr, size_t ffset, size_t length) 
474     {
475         return READ_MEMCPY_BOUND(ptr, offset, length, moddata_length);
476     }
477 
478 
479     num_channels = READ_U16(offset + 8);
480     num_channels = READ_U16(offset + 8);
481 
482     num_patterns = READ_U16(offset + 10);
483     memory_needed += num_patterns * xm_pattern_t.sizeof;
484 
485     num_instruments = READ_U16(offset + 12);
486     memory_needed += num_instruments * xm_instrument_t.sizeof;
487 
488     memory_needed += MAX_NUM_ROWS * READ_U16(offset + 4) * uint8_t.sizeof; /* Module length */
489 
490     /* Header size */
491     offset += READ_U32(offset);
492 
493     /* Read pattern headers */
494     for(uint16_t i = 0; i < num_patterns; ++i) {
495         uint16_t num_rows;
496 
497         num_rows = READ_U16(offset + 5);
498         memory_needed += num_rows * num_channels * xm_pattern_slot_t.sizeof;
499 
500         /* Pattern header length + packed pattern data size */
501         offset += READ_U32(offset) + READ_U16(offset + 7);
502     }
503 
504     /* Read instrument headers */
505     for(uint16_t i = 0; i < num_instruments; ++i) {
506         uint16_t num_samples;
507         uint32_t sample_size_aggregate = 0;
508 
509         num_samples = READ_U16(offset + 27);
510         memory_needed += num_samples * xm_sample_t.sizeof;
511 
512         /* Instrument header size */
513         uint32_t ins_header_size = READ_U32(offset);
514         if (ins_header_size == 0 || ins_header_size > INSTRUMENT_HEADER_LENGTH)
515             ins_header_size = INSTRUMENT_HEADER_LENGTH;
516         offset += ins_header_size;
517 
518         for(uint16_t j = 0; j < num_samples; ++j) {
519             uint32_t sample_size;
520 
521             sample_size = READ_U32(offset);
522             sample_size_aggregate += sample_size;
523             memory_needed += sample_size;
524             offset += 40; /* See comment in xm_load_module() */
525         }
526 
527         offset += sample_size_aggregate;
528     }
529 
530     memory_needed += num_channels * xm_channel_context_t.sizeof;
531     memory_needed += xm_context_t.sizeof;
532 
533     return memory_needed;
534 }
535 
536 /** Populate the context from module data.
537  *
538  * @returns pointer to the memory pool
539  */
540 char* xm_load_module(xm_context_t* ctx, const char* moddata, size_t moddata_length, char* mempool) {
541     size_t offset = 0;
542     xm_module_t* mod = &(ctx.module_);
543 
544     ubyte READ_U8_BOUND(size_t offset, size_t bound)
545     {
546         return (offset < bound) ? *cast(uint8_t*)(moddata + offset) : 0;
547     }
548 
549     ubyte READ_U8(size_t offset)
550     {
551         return READ_U8_BOUND(offset, moddata_length);
552     }
553 
554     ushort READ_U16_BOUND(size_t offset, size_t bound)
555     {
556         return (cast(uint16_t)READ_U8(offset) | (cast(uint16_t)READ_U8((offset) + 1) << 8));
557     }
558 
559     ushort READ_U16(size_t offset)
560     {
561         return READ_U16_BOUND(offset, moddata_length);
562     }
563 
564     uint READ_U32_BOUND(size_t offset, size_t bound)
565     {
566         return (cast(uint32_t)READ_U16(offset) | (cast(uint32_t)READ_U16((offset) + 2) << 16));
567     }
568 
569     uint READ_U32(size_t offset)
570     {
571         return READ_U32_BOUND(offset, moddata_length);
572     }
573 
574     void READ_MEMCPY_BOUND(void* ptr, size_t offset, size_t length, size_t bound)
575     {
576         memcpy_pad(ptr, length, moddata, bound, offset);
577     }
578 
579     void READ_MEMCPY(void* ptr, size_t offset, size_t length) 
580     {
581         return READ_MEMCPY_BOUND(ptr, offset, length, moddata_length);
582     }
583 
584     /* Read XM header */
585     version(XM_STRINGS)
586     {
587         READ_MEMCPY(mod.name.ptr, offset + 17, MODULE_NAME_LENGTH);
588         READ_MEMCPY(mod.trackername.ptr, offset + 38, TRACKER_NAME_LENGTH);
589     }
590     offset += 60;
591 
592     /* Read module header */
593     uint32_t header_size = READ_U32(offset);
594 
595     mod.length = READ_U16(offset + 4);
596     mod.restart_position = READ_U16(offset + 6);
597     mod.num_channels = READ_U16(offset + 8);
598     mod.num_patterns = READ_U16(offset + 10);
599     mod.num_instruments = READ_U16(offset + 12);
600 
601     mod.patterns = cast(xm_pattern_t*)mempool;
602     mempool += mod.num_patterns * xm_pattern_t.sizeof;
603 
604     mod.instruments = cast(xm_instrument_t*)mempool;
605     mempool += mod.num_instruments * xm_instrument_t.sizeof;
606 
607     uint16_t flags = cast(ushort) READ_U32(offset + 14);
608     mod.frequency_type = (flags & (1 << 0)) ? XM_LINEAR_FREQUENCIES : XM_AMIGA_FREQUENCIES;
609 
610     ctx.tempo = READ_U16(offset + 16);
611     ctx.bpm = READ_U16(offset + 18);
612 
613     READ_MEMCPY(mod.pattern_table.ptr, offset + 20, PATTERN_ORDER_TABLE_LENGTH);
614     offset += header_size;
615 
616     /* Read patterns */
617     for(uint16_t i = 0; i < mod.num_patterns; ++i) {
618         uint16_t packed_patterndata_size = READ_U16(offset + 7);
619         xm_pattern_t* pat = mod.patterns + i;
620 
621         pat.num_rows = READ_U16(offset + 5);
622 
623         pat.slots = cast(xm_pattern_slot_t*)mempool;
624         mempool += mod.num_channels * pat.num_rows * xm_pattern_slot_t.sizeof;
625 
626         /* Pattern header length */
627         offset += READ_U32(offset);
628 
629         if(packed_patterndata_size == 0) {
630             /* No pattern data is present */
631             memset(pat.slots, 0, xm_pattern_slot_t.sizeof * pat.num_rows * mod.num_channels);
632         } else {
633             /* This isn't your typical for loop */
634             for(uint16_t j = 0, k = 0; j < packed_patterndata_size; ++k) {
635                 uint8_t note = READ_U8(offset + j);
636                 xm_pattern_slot_t* slot = pat.slots + k;
637 
638                 if(note & (1 << 7)) {
639                     /* MSB is set, this is a compressed packet */
640                     ++j;
641 
642                     if(note & (1 << 0)) {
643                         /* Note follows */
644                         slot.note = READ_U8(offset + j);
645                         ++j;
646                     } else {
647                         slot.note = 0;
648                     }
649 
650                     if(note & (1 << 1)) {
651                         /* Instrument follows */
652                         slot.instrument = READ_U8(offset + j);
653                         ++j;
654                     } else {
655                         slot.instrument = 0;
656                     }
657 
658                     if(note & (1 << 2)) {
659                         /* Volume column follows */
660                         slot.volume_column = READ_U8(offset + j);
661                         ++j;
662                     } else {
663                         slot.volume_column = 0;
664                     }
665 
666                     if(note & (1 << 3)) {
667                         /* Effect follows */
668                         slot.effect_type = READ_U8(offset + j);
669                         ++j;
670                     } else {
671                         slot.effect_type = 0;
672                     }
673 
674                     if(note & (1 << 4)) {
675                         /* Effect parameter follows */
676                         slot.effect_param = READ_U8(offset + j);
677                         ++j;
678                     } else {
679                         slot.effect_param = 0;
680                     }
681                 } else {
682                     /* Uncompressed packet */
683                     slot.note = note;
684                     slot.instrument = READ_U8(offset + j + 1);
685                     slot.volume_column = READ_U8(offset + j + 2);
686                     slot.effect_type = READ_U8(offset + j + 3);
687                     slot.effect_param = READ_U8(offset + j + 4);
688                     j += 5;
689                 }
690             }
691         }
692 
693         offset += packed_patterndata_size;
694     }
695 
696     /* Read instruments */
697     for(uint16_t i = 0; i < ctx.module_.num_instruments; ++i) {
698         xm_instrument_t* instr = mod.instruments + i;
699 
700         /* Original FT2 would load instruments with a direct read into the
701         instrument data structure that was previously zeroed. This means
702         that if the declared length was less than INSTRUMENT_HEADER_LENGTH,
703         all excess data would be zeroed. This is used by the XM compressor
704         BoobieSqueezer. To implement this, bound all reads to the header size. */
705         uint32_t ins_header_size = READ_U32(offset);
706         if (ins_header_size == 0 || ins_header_size > INSTRUMENT_HEADER_LENGTH)
707             ins_header_size = INSTRUMENT_HEADER_LENGTH;
708 
709         version(XM_STRINGS)
710         {
711             READ_MEMCPY_BOUND(instr.name.ptr, offset + 4, INSTRUMENT_NAME_LENGTH, offset + ins_header_size);
712             instr.name[INSTRUMENT_NAME_LENGTH] = 0;
713         }
714         instr.num_samples = READ_U16_BOUND(offset + 27, offset + ins_header_size);
715 
716         if(instr.num_samples > 0) {
717             /* Read extra header properties */
718             READ_MEMCPY_BOUND(instr.sample_of_notes.ptr, offset + 33, NUM_NOTES, offset + ins_header_size);
719 
720             instr.volume_envelope.num_points = READ_U8_BOUND(offset + 225, offset + ins_header_size);
721             if (instr.volume_envelope.num_points > NUM_ENVELOPE_POINTS)
722                 instr.volume_envelope.num_points = NUM_ENVELOPE_POINTS;
723 
724             instr.panning_envelope.num_points = READ_U8_BOUND(offset + 226, offset + ins_header_size);
725             if (instr.panning_envelope.num_points > NUM_ENVELOPE_POINTS)
726                 instr.panning_envelope.num_points = NUM_ENVELOPE_POINTS;
727 
728             for(uint8_t j = 0; j < instr.volume_envelope.num_points; ++j) {
729                 instr.volume_envelope.points[j].frame = READ_U16_BOUND(offset + 129 + 4 * j, offset + ins_header_size);
730                 instr.volume_envelope.points[j].value = READ_U16_BOUND(offset + 129 + 4 * j + 2, offset + ins_header_size);
731             }
732 
733             for(uint8_t j = 0; j < instr.panning_envelope.num_points; ++j) {
734                 instr.panning_envelope.points[j].frame = READ_U16_BOUND(offset + 177 + 4 * j, offset + ins_header_size);
735                 instr.panning_envelope.points[j].value = READ_U16_BOUND(offset + 177 + 4 * j + 2, offset + ins_header_size);
736             }
737 
738             instr.volume_envelope.sustain_point = READ_U8_BOUND(offset + 227, offset + ins_header_size);
739             instr.volume_envelope.loop_start_point = READ_U8_BOUND(offset + 228, offset + ins_header_size);
740             instr.volume_envelope.loop_end_point = READ_U8_BOUND(offset + 229, offset + ins_header_size);
741 
742             instr.panning_envelope.sustain_point = READ_U8_BOUND(offset + 230, offset + ins_header_size);
743             instr.panning_envelope.loop_start_point = READ_U8_BOUND(offset + 231, offset + ins_header_size);
744             instr.panning_envelope.loop_end_point = READ_U8_BOUND(offset + 232, offset + ins_header_size);
745 
746             uint8_t flags_ = READ_U8_BOUND(offset + 233, offset + ins_header_size);
747             instr.volume_envelope.enabled = ( flags_ & (1 << 0) ) != 0;
748             instr.volume_envelope.sustain_enabled = (flags_ & (1 << 1) ) != 0;
749             instr.volume_envelope.loop_enabled = ( flags_ & (1 << 2)  ) != 0;
750 
751             flags_ = READ_U8_BOUND(offset + 234, offset + ins_header_size);
752             instr.panning_envelope.enabled = flags_ & (1 << 0);
753             instr.panning_envelope.sustain_enabled = (flags_ & (1 << 1)) != 0;
754             instr.panning_envelope.loop_enabled =    (flags_ & (1 << 2)) != 0;
755 
756             instr.vibrato_type = READ_U8_BOUND(offset + 235, offset + ins_header_size);
757             if(instr.vibrato_type == 2) {
758                 instr.vibrato_type = 1;
759             } else if(instr.vibrato_type == 1) {
760                 instr.vibrato_type = 2;
761             }
762             instr.vibrato_sweep = READ_U8_BOUND(offset + 236, offset + ins_header_size);
763             instr.vibrato_depth = READ_U8_BOUND(offset + 237, offset + ins_header_size);
764             instr.vibrato_rate = READ_U8_BOUND(offset + 238, offset + ins_header_size);
765             instr.volume_fadeout = READ_U16_BOUND(offset + 239, offset + ins_header_size);
766 
767             instr.samples = cast(xm_sample_t*)mempool;
768             mempool += instr.num_samples * xm_sample_t.sizeof;
769         } else {
770             instr.samples = null;
771         }
772 
773         /* Instrument header size */
774         offset += ins_header_size;
775 
776         for(uint16_t j = 0; j < instr.num_samples; ++j) {
777             /* Read sample header */
778             xm_sample_t* sample = instr.samples + j;
779 
780             sample.length = READ_U32(offset);
781             sample.loop_start = READ_U32(offset + 4);
782             sample.loop_length = READ_U32(offset + 8);
783             sample.loop_end = sample.loop_start + sample.loop_length;
784             sample.volume = cast(float)READ_U8(offset + 12) / cast(float)0x40;
785             sample.finetune = cast(int8_t)READ_U8(offset + 13);
786 
787             /* Fix invalid loop definitions */
788             if (sample.loop_start > sample.length)
789                 sample.loop_start = sample.length;
790             if (sample.loop_end > sample.length)
791                 sample.loop_end = sample.length;
792             sample.loop_length = sample.loop_end - sample.loop_start;
793 
794             uint8_t flags2 = READ_U8(offset + 14);
795             if((flags2 & 3) == 0 || sample.loop_length == 0) {
796                 sample.loop_type = XM_NO_LOOP;
797             } else if((flags2 & 3) == 1) {
798                 sample.loop_type = XM_FORWARD_LOOP;
799             } else {
800                 sample.loop_type = XM_PING_PONG_LOOP;
801             }
802 
803             sample.bits = (flags2 & (1 << 4)) ? 16 : 8;
804 
805             sample.panning = cast(float)READ_U8(offset + 15) / cast(float)0xFF;
806             sample.relative_note = cast(int8_t)READ_U8(offset + 16);
807             version( XM_STRINGS)
808             {
809                 READ_MEMCPY(sample.name.ptr, 18, SAMPLE_NAME_LENGTH);
810             }
811             sample.data8 = cast(int8_t*)mempool;
812             mempool += sample.length;
813 
814             if(sample.bits == 16) {
815                 sample.loop_start >>= 1;
816                 sample.loop_length >>= 1;
817                 sample.loop_end >>= 1;
818                 sample.length >>= 1;
819             }
820 
821             /* Notice that, even if there's a "sample header size" in the
822             instrument header, that value seems ignored, and might even
823             be wrong in some corrupted modules. */
824             offset += 40;
825         }
826 
827         for(uint16_t j = 0; j < instr.num_samples; ++j) {
828             /* Read sample data */
829             xm_sample_t* sample = instr.samples + j;
830             uint32_t length = sample.length;
831 
832             if(sample.bits == 16) {
833                 int16_t v = 0;
834                 for(uint32_t k = 0; k < length; ++k) {
835                     v = cast(short)( v + cast(int16_t)READ_U16(offset + (k << 1)) );
836                     sample.data16[k] = v;
837                 }
838                 offset += sample.length << 1;
839             } else {
840                 int8_t v = 0;
841                 for(uint32_t k = 0; k < length; ++k) {
842                     v = cast(byte)( v + cast(int8_t)READ_U8(offset + k) );
843                     sample.data8[k] = v;
844                 }
845                 offset += sample.length;
846             }
847         }
848     }
849 
850     return mempool;
851 }
852 
853 
854 
855 // context.c -- public API
856 
857 int xm_create_context_safe(xm_context_t** ctxp, const char* moddata, size_t moddata_length, uint32_t rate) 
858 {
859 	size_t bytes_needed;
860 	char* mempool;
861 	xm_context_t* ctx;
862 
863 	if(XM_DEFENSIVE) 
864     {
865 		int ret = xm_check_sanity_preload(moddata, moddata_length);
866 		if (ret != 0) 
867         {
868 			//("xm_check_sanity_preload() returned %i, module is not safe to load", ret);
869 			return 1;
870 		}
871 	}
872 
873 	bytes_needed = xm_get_memory_needed_for_context(moddata, moddata_length);
874 	mempool = cast(char*) malloc(bytes_needed);
875 	if(mempool == null && bytes_needed > 0) {
876 		/* malloc() failed, trouble ahead */
877 		//DEBUG("call to malloc() failed, returned %p", (void*)mempool);
878 		return 2;
879 	}
880 
881 	/* Initialize most of the fields to 0, 0.0f, null or false depending on type */
882 	memset(mempool, 0, bytes_needed);
883 
884 	ctx = (*ctxp = cast(xm_context_t*)mempool);
885 	ctx.ctx_size = bytes_needed; /* Keep original requested size for xmconvert */
886     mempool += xm_context_t.sizeof;
887 
888 	ctx.rate = rate;
889 	mempool = xm_load_module(ctx, moddata, moddata_length, mempool);
890 
891 	ctx.channels = cast(xm_channel_context_t*)mempool;
892 	mempool += ctx.module_.num_channels * (xm_channel_context_t).sizeof;
893 
894 	ctx.global_volume = 1.0f;
895 	ctx.amplification = 0.25f; /* XXX: some bad modules may still clip. Find out something better. */
896     ctx.next_rand = 24492; // see rng
897 
898     version(XM_RAMPING)
899     {
900 	    ctx.volume_ramp = (1.0f / 128.0f);
901     }
902 
903 	for(uint8_t i = 0; i < ctx.module_.num_channels; ++i) {
904 		xm_channel_context_t* ch = ctx.channels + i;
905 
906 		ch.ping = true;
907 		ch.vibrato_waveform = XM_SINE_WAVEFORM;
908 		ch.vibrato_waveform_retrigger = true;
909 		ch.tremolo_waveform = XM_SINE_WAVEFORM;
910 		ch.tremolo_waveform_retrigger = true;
911 
912 		ch.volume = ch.volume_envelope_volume = ch.fadeout_volume = 1.0f;
913 		ch.panning = ch.panning_envelope_panning = .5f;
914 		ch.actual_volume[0] = .0f;
915 		ch.actual_volume[1] = .0f;
916 	}
917 
918 	ctx.row_loop_count = cast(uint8_t*)mempool;
919 	mempool += ctx.module_.length * MAX_NUM_ROWS * uint8_t.sizeof;
920 
921 	if(XM_DEFENSIVE) {
922 		int ret = xm_check_sanity_postload(ctx);
923 		if(ret != 0) 
924         {
925 			//DEBUG("xm_check_sanity_postload() returned %i, module is not safe to play", ret);
926 			xm_free_context(ctx);
927             *ctxp = null;
928 			return 1;
929 		}
930 	}
931 
932 	return 0;
933 }
934 
935 void xm_free_context(xm_context_t* context) {
936 	free(context);
937 }
938 
939 void xm_set_max_loop_count(xm_context_t* context, uint8_t loopcnt) {
940 	context.max_loop_count = loopcnt;
941 }
942 
943 uint8_t xm_get_loop_count(xm_context_t* context) {
944 	return context.loop_count;
945 }
946 
947 
948 
949 void xm_seek(xm_context_t* ctx, uint8_t pot, uint8_t row, uint16_t tick) {
950 	ctx.current_table_index = pot;
951 	ctx.current_row = row;
952 	ctx.current_tick = tick;
953 	ctx.remaining_samples_in_tick = 0;
954 }
955 
956 
957 
958 bool xm_mute_channel(xm_context_t* ctx, uint16_t channel, bool mute) {
959 	bool old = ctx.channels[channel - 1].muted;
960 	ctx.channels[channel - 1].muted = mute;
961 	return old;
962 }
963 
964 bool xm_mute_instrument(xm_context_t* ctx, uint16_t instr, bool mute) {
965 	bool old = ctx.module_.instruments[instr - 1].muted;
966 	ctx.module_.instruments[instr - 1].muted = mute;
967 	return old;
968 }
969 
970 
971 
972 version(XM_STRINGS)
973 {
974     const(char)* xm_get_module_name(xm_context_t* ctx) 
975     {
976 	    return ctx.module_.name.ptr;
977     }
978 
979     const(char)* xm_get_tracker_name(xm_context_t* ctx) 
980     {
981 	    return ctx.module_.trackername.ptr;
982     }
983 }
984 else
985 {
986     const(char)* xm_get_module_name(xm_context_t* ctx) 
987     {
988 	    return null;
989     }
990 
991     const(char)* xm_get_tracker_name(xm_context_t* ctx) 
992     {
993 	    return null;
994     }
995 }
996 
997 uint16_t xm_get_number_of_channels(xm_context_t* ctx) {
998 	return ctx.module_.num_channels;
999 }
1000 
1001 uint16_t xm_get_module_length(xm_context_t* ctx) {
1002 	return ctx.module_.length;
1003 }
1004 
1005 uint16_t xm_get_number_of_patterns(xm_context_t* ctx) {
1006 	return ctx.module_.num_patterns;
1007 }
1008 
1009 uint16_t xm_get_number_of_rows(xm_context_t* ctx, uint16_t pattern) {
1010 	return ctx.module_.patterns[pattern].num_rows;
1011 }
1012 
1013 uint16_t xm_get_number_of_instruments(xm_context_t* ctx) {
1014 	return ctx.module_.num_instruments;
1015 }
1016 
1017 uint16_t xm_get_number_of_samples(xm_context_t* ctx, uint16_t instrument) {
1018 	return ctx.module_.instruments[instrument - 1].num_samples;
1019 }
1020 
1021 void* xm_get_sample_waveform(xm_context_t* ctx, uint16_t i, uint16_t s, size_t* size, uint8_t* bits) {
1022 	*size = ctx.module_.instruments[i - 1].samples[s].length;
1023 	*bits = ctx.module_.instruments[i - 1].samples[s].bits;
1024 	return ctx.module_.instruments[i - 1].samples[s].data8;
1025 }
1026 
1027 
1028 
1029 void xm_get_playing_speed(xm_context_t* ctx, uint16_t* bpm, uint16_t* tempo) {
1030 	if(bpm) *bpm = ctx.bpm;
1031 	if(tempo) *tempo = ctx.tempo;
1032 }
1033 
1034 void xm_get_position(xm_context_t* ctx, uint8_t* pattern_index, uint8_t* pattern, uint8_t* row, uint64_t* samples) {
1035 	if(pattern_index) *pattern_index = ctx.current_table_index;
1036 	if(pattern) *pattern = ctx.module_.pattern_table[ctx.current_table_index];
1037 	if(row) *row = ctx.current_row;
1038 	if(samples) *samples = ctx.generated_samples;
1039 }
1040 
1041 uint64_t xm_get_latest_trigger_of_instrument(xm_context_t* ctx, uint16_t instr) {
1042 	return ctx.module_.instruments[instr - 1].latest_trigger;
1043 }
1044 
1045 uint64_t xm_get_latest_trigger_of_sample(xm_context_t* ctx, uint16_t instr, uint16_t sample) {
1046 	return ctx.module_.instruments[instr - 1].samples[sample].latest_trigger;
1047 }
1048 
1049 uint64_t xm_get_latest_trigger_of_channel(xm_context_t* ctx, uint16_t chn) {
1050 	return ctx.channels[chn - 1].latest_trigger;
1051 }
1052 
1053 bool xm_is_channel_active(xm_context_t* ctx, uint16_t chn) {
1054 	xm_channel_context_t* ch = ctx.channels + (chn - 1);
1055 	return ch.instrument != null && ch.sample != null && ch.sample_position >= 0;
1056 }
1057 
1058 float xm_get_frequency_of_channel(xm_context_t* ctx, uint16_t chn) {
1059 	return ctx.channels[chn - 1].frequency;
1060 }
1061 
1062 float xm_get_volume_of_channel(xm_context_t* ctx, uint16_t chn) {
1063 	return ctx.channels[chn - 1].volume * ctx.global_volume;
1064 }
1065 
1066 float xm_get_panning_of_channel(xm_context_t* ctx, uint16_t chn) {
1067 	return ctx.channels[chn - 1].panning;
1068 }
1069 
1070 uint16_t xm_get_instrument_of_channel(xm_context_t* ctx, uint16_t chn) 
1071 {
1072 	xm_channel_context_t* ch = ctx.channels + (chn - 1);
1073 	if(ch.instrument == null) return 0;
1074 	return cast(ushort)( 1 + (ch.instrument - ctx.module_.instruments) );
1075 }
1076 
1077 
1078 // play.c
1079 
1080 /* Author: Romain "Artefact2" Dalmaso <artefact2@gmail.com> */
1081 /* Contributor: Daniel Oaks <daniel@danieloaks.net> */
1082 
1083 /* This program is free software. It comes without any warranty, to the
1084 * extent permitted by applicable law. You can redistribute it and/or
1085 * modify it under the terms of the Do What The Fuck You Want To Public
1086 * License, Version 2, as published by Sam Hocevar. See
1087 * http://sam.zoy.org/wtfpl/COPYING for more details. */
1088 
1089 /* ----- Other oddities ----- */
1090 
1091 enum XM_TRIGGER_KEEP_VOLUME = (1 << 0);
1092 enum  XM_TRIGGER_KEEP_PERIOD = (1 << 1);
1093 enum  XM_TRIGGER_KEEP_SAMPLE_POSITION = (1 << 2);
1094 enum  XM_TRIGGER_KEEP_ENVELOPE = (1 << 3);
1095 
1096 enum AMIGA_FREQ_SCALE = 1024;
1097 
1098 static immutable uint32_t[13] amiga_frequencies =
1099 [
1100 	1712*AMIGA_FREQ_SCALE, 1616*AMIGA_FREQ_SCALE, 1525*AMIGA_FREQ_SCALE, 1440*AMIGA_FREQ_SCALE, /* C-2, C#2, D-2, D#2 */
1101 	1357*AMIGA_FREQ_SCALE, 1281*AMIGA_FREQ_SCALE, 1209*AMIGA_FREQ_SCALE, 1141*AMIGA_FREQ_SCALE, /* E-2, F-2, F#2, G-2 */
1102 	1077*AMIGA_FREQ_SCALE, 1017*AMIGA_FREQ_SCALE,  961*AMIGA_FREQ_SCALE,  907*AMIGA_FREQ_SCALE, /* G#2, A-2, A#2, B-2 */
1103 	856*AMIGA_FREQ_SCALE,                                                                       /* C-3 */
1104 ];
1105 
1106 static immutable float[16] multi_retrig_add = 
1107 [
1108     0.0f,  -1.0f,  -2.0f,  -4.0f,  /* 0, 1, 2, 3 */
1109 	-8.0f, -16.0f,   0.0f,   0.0f,  /* 4, 5, 6, 7 */
1110     0.0f,   1.0f,   2.0f,   4.0f,  /* 8, 9, A, B */
1111     8.0f,  16.0f,   0.0f,   0.0f   /* C, D, E, F */
1112 ];
1113 
1114 static const float[16] multi_retrig_multiply =
1115 [
1116 	1.0f,   1.0f,  1.0f,        1.0f,  /* 0, 1, 2, 3 */
1117 	1.0f,   1.0f,   .6666667f,  .5f, /* 4, 5, 6, 7 */
1118 	1.0f,   1.0f,  1.0f,        1.0f,  /* 8, 9, A, B */
1119 	1.0f,   1.0f,  1.5f,       2.0f   /* C, D, E, F */
1120 ];
1121 
1122 /*#define XM_CLAMP_UP1F(vol, limit) do {			\
1123 if((vol) > (limit)) (vol) = (limit);	\
1124 } while(0)
1125 
1126 #define XM_CLAMP_UP(vol) XM_CLAMP_UP1F((vol), 1.0f)
1127 
1128 #define XM_CLAMP_DOWN1F(vol, limit) do {		\
1129 if((vol) < (limit)) (vol) = (limit);	\
1130 } while(0)
1131 #define XM_CLAMP_DOWN(vol) XM_CLAMP_DOWN1F((vol), .0f)
1132 
1133 #define XM_CLAMP2F(vol, up, down) do {			\
1134 if((vol) > (up)) (vol) = (up);			\
1135 else if((vol) < (down)) (vol) = (down); \
1136 } while(0)
1137 #define XM_CLAMP(vol) XM_CLAMP2F((vol), 1.0f, .0f)
1138 
1139 */
1140 
1141 void XM_SLIDE_TOWARDS(ref float val, float goal, float incr)
1142 {
1143     if (val > goal)
1144     {
1145         val -= incr;
1146         if (val < goal) val = goal;
1147     }
1148     else if (val < goal)
1149     {
1150         val += incr;
1151         if (val > goal) val = goal;
1152     }
1153 }
1154 
1155 float XM_LERP(float u, float v, float t)
1156 {
1157     return u + t * (v - u);
1158 }
1159 
1160 float XM_INVERSE_LERP(float u, float v, float lerp)
1161 {
1162     return  (lerp - u) / (v - u);
1163 }
1164 
1165 bool NOTE_IS_VALID(int n)
1166 {
1167     return (n > 0) && (n < 97);
1168 }
1169 
1170 /* ----- Function definitions ----- */
1171 
1172 float xm_waveform(xm_context_t* context, xm_waveform_type_t waveform, uint8_t step) {
1173 	step %= 0x40;
1174 	switch(waveform) 
1175     {
1176 
1177         case XM_SINE_WAVEFORM:
1178             /* Why not use a table? For saving space, and because there's
1179             * very very little actual performance gain. */
1180             return -fast_sin(2.0f * 3.141592f * cast(float)step / cast(float)0x40);
1181 
1182         case XM_RAMP_DOWN_WAVEFORM:
1183             /* Ramp down: 1.0f when step = 0; -1.0f when step = 0x40 */
1184             return cast(float)(0x20 - step) / 0x20;
1185 
1186         case XM_SQUARE_WAVEFORM:
1187             /* Square with a 50% duty */
1188             return (step >= 0x20) ? 1.0f : -1.0f;
1189 
1190         case XM_RANDOM_WAVEFORM:
1191             /* Use the POSIX.1-2001 example, just to be deterministic
1192             * across different machines */
1193             context.next_rand = context.next_rand * 1103515245 + 12345;
1194             return cast(float)((context.next_rand >> 16) & 0x7FFF) / cast(float)0x4000 - 1.0f;
1195 
1196         case XM_RAMP_UP_WAVEFORM:
1197             /* Ramp up: -1.0f when step = 0; 1.0f when step = 0x40 */
1198             return cast(float)(step - 0x20) / 0x20;
1199 
1200         default:
1201             break;
1202 
1203 	}
1204 
1205 	return .0f;
1206 }
1207 
1208 void xm_autovibrato(xm_context_t* ctx, xm_channel_context_t* ch) {
1209 	if(ch.instrument == null || ch.instrument.vibrato_depth == 0){
1210 		if (ch.autovibrato_note_offset){
1211 			ch.autovibrato_note_offset = 0.0f;
1212 			xm_update_frequency(ctx, ch);
1213 		}
1214 		return;
1215 	}
1216 	xm_instrument_t* instr = ch.instrument;
1217 	float sweep = 1.0f;
1218 
1219 	if(ch.autovibrato_ticks < instr.vibrato_sweep) {
1220 		/* No idea if this is correct, but it sounds close enough… */
1221 		sweep = XM_LERP(0.0f, 1.0f, cast(float)ch.autovibrato_ticks / cast(float)instr.vibrato_sweep);
1222 	}
1223 
1224 	uint step = ((ch.autovibrato_ticks++) * instr.vibrato_rate) >> 2;
1225 	ch.autovibrato_note_offset = .25f * xm_waveform(ctx, instr.vibrato_type, cast(ubyte)step)
1226 		* cast(float)instr.vibrato_depth / cast(float)0xF * sweep;
1227 	xm_update_frequency(ctx, ch);
1228 }
1229 
1230 void xm_vibrato(xm_context_t* ctx, xm_channel_context_t* ch, uint8_t param) {
1231 	ch.vibrato_ticks += (param >> 4);
1232 	ch.vibrato_note_offset =
1233 		-2.0f
1234 		* xm_waveform(ctx, ch.vibrato_waveform, cast(ubyte)ch.vibrato_ticks)
1235 		* cast(float)(param & 0x0F) / cast(float)0xF;
1236 	xm_update_frequency(ctx, ch);
1237 }
1238 
1239 void xm_tremolo(xm_context_t* ctx, xm_channel_context_t* ch, uint8_t param, uint16_t pos) {
1240 	uint step = pos * (param >> 4);
1241 	/* Not so sure about this, it sounds correct by ear compared with
1242     * MilkyTracker, but it could come from other bugs */
1243 	ch.tremolo_volume = -1.0f * xm_waveform(ctx, ch.tremolo_waveform, cast(ubyte)step)
1244 		* cast(float)(param & 0x0F) / cast(float)0xF;
1245 }
1246 
1247 void xm_arpeggio(xm_context_t* ctx, xm_channel_context_t* ch, uint8_t param, uint16_t tick) {
1248 	switch(tick % 3) {
1249         case 0:
1250             ch.arp_in_progress = false;
1251             ch.arp_note_offset = 0;
1252             break;
1253         case 2:
1254             ch.arp_in_progress = true;
1255             ch.arp_note_offset = param >> 4;
1256             break;
1257         case 1:
1258             ch.arp_in_progress = true;
1259             ch.arp_note_offset = param & 0x0F;
1260             break;
1261 
1262         default:
1263             assert(false);
1264 	}
1265 
1266 	xm_update_frequency(ctx, ch);
1267 }
1268 
1269 void xm_tone_portamento(xm_context_t* ctx, xm_channel_context_t* ch) 
1270 {
1271 	/* 3xx called without a note, wait until we get an actual
1272     * target note. */
1273 	if(ch.tone_portamento_target_period == 0.0f) 
1274         return;
1275 
1276 	if(ch.period != ch.tone_portamento_target_period) 
1277     {
1278 		XM_SLIDE_TOWARDS(ch.period,
1279 		                 ch.tone_portamento_target_period,
1280 		                 (ctx.module_.frequency_type == XM_LINEAR_FREQUENCIES ? 4.0f : 1.0f) * ch.tone_portamento_param);
1281 		xm_update_frequency(ctx, ch);
1282 	}
1283 }
1284 
1285 void xm_pitch_slide(xm_context_t* ctx, xm_channel_context_t* ch, float period_offset) {
1286 	/* Don't ask about the 4.0f coefficient. I found mention of it
1287     * nowhere. Found by ear™. */
1288 	if(ctx.module_.frequency_type == XM_LINEAR_FREQUENCIES) {
1289 		period_offset *= 4.0f;
1290 	}
1291 
1292 	ch.period += period_offset;
1293     if (ch.period < 0) ch.period = 0;
1294 	/* XXX: upper bound of period ? */
1295 
1296 	xm_update_frequency(ctx, ch);
1297 }
1298 
1299 void xm_panning_slide(xm_channel_context_t* ch, uint8_t rawval) {
1300 	float f;
1301 
1302 	if((rawval & 0xF0) && (rawval & 0x0F)) {
1303 		/* Illegal state */
1304 		return;
1305 	}
1306 
1307 	if(rawval & 0xF0) {
1308 		/* Slide right */
1309 		f = cast(float)(rawval >> 4) / cast(float)0xFF;
1310 		ch.panning += f;
1311         if (ch.panning > 1) 
1312             ch.panning = 1;
1313 	} else {
1314 		/* Slide left */
1315 		f = cast(float)(rawval & 0x0F) / cast(float)0xFF;
1316 		ch.panning -= f;
1317         if (ch.panning < 0)
1318             ch.panning = 0;
1319 	}
1320 }
1321 
1322 void xm_volume_slide(xm_channel_context_t* ch, uint8_t rawval) {
1323 	float f;
1324 
1325 	if((rawval & 0xF0) && (rawval & 0x0F)) {
1326 		/* Illegal state */
1327 		return;
1328 	}
1329 
1330 	if(rawval & 0xF0) {
1331 		/* Slide up */
1332 		f = cast(float)(rawval >> 4) / cast(float)0x40;
1333 		ch.volume += f;
1334         if (ch.volume > 1)
1335             ch.volume = 1;
1336 	} else {
1337 		/* Slide down */
1338 		f = cast(float)(rawval & 0x0F) / cast(float)0x40;
1339 		ch.volume -= f;
1340         if (ch.volume < 0)
1341             ch.volume = 0;
1342 	}
1343 }
1344 
1345 float xm_envelope_lerp(xm_envelope_point_t* a, xm_envelope_point_t* b, uint16_t pos) {
1346 	/* Linear interpolation between two envelope points */
1347 	if(pos <= a.frame) return a.value;
1348 	else if(pos >= b.frame) return b.value;
1349 	else {
1350 		float p = cast(float)(pos - a.frame) / cast(float)(b.frame - a.frame);
1351 		return a.value * (1 - p) + b.value * p;
1352 	}
1353 }
1354 
1355 void xm_post_pattern_change(xm_context_t* ctx) {
1356 	/* Loop if necessary */
1357 	if(ctx.current_table_index >= ctx.module_.length) 
1358     {
1359 		ctx.current_table_index = cast(ubyte)(ctx.module_.restart_position);
1360 	}
1361 }
1362 
1363 float xm_linear_period(float note) {
1364 	return 7680.0f - note * 64.0f;
1365 }
1366 
1367 float xm_linear_frequency(float period) {
1368 	return 8363.0f * fast_pow(2.0f, (4608.0f - period) / 768.0f);
1369 }
1370 
1371 float xm_amiga_period(float note) {
1372 	uint intnote = cast(uint)note;
1373 	uint8_t a = intnote % 12;
1374 	int8_t octave = cast(int8_t)(note / 12.0f - 2);
1375 	int32_t p1 = amiga_frequencies[a], p2 = amiga_frequencies[a + 1];
1376 
1377 	if(octave > 0) {
1378 		p1 >>= octave;
1379 		p2 >>= octave;
1380 	} else if(octave < 0) {
1381 		p1 <<= (-cast(int)octave);
1382 		p2 <<= (-cast(int)octave);
1383 	}
1384 
1385 	return XM_LERP(p1, p2, note - intnote) / AMIGA_FREQ_SCALE;
1386 }
1387 
1388 float xm_amiga_frequency(float period) {
1389 	if(period == .0f) return .0f;
1390 
1391 	/* This is the PAL value. No reason to choose this one over the
1392     * NTSC value. */
1393 	return 7093789.2f / (period * 2.0f);
1394 }
1395 
1396 float xm_period(xm_context_t* ctx, float note) 
1397 {
1398 	switch(ctx.module_.frequency_type) 
1399     {
1400         case XM_LINEAR_FREQUENCIES:
1401             return xm_linear_period(note);
1402         case XM_AMIGA_FREQUENCIES:
1403             return xm_amiga_period(note);
1404         default:
1405 	}
1406 	return .0f;
1407 }
1408 
1409 float xm_frequency(xm_context_t* ctx, float period, float note_offset, float period_offset) {
1410 	uint8_t a;
1411 	int8_t octave;
1412 	float note;
1413 	int32_t p1, p2;
1414 
1415 	switch(ctx.module_.frequency_type) 
1416     {
1417 
1418         case XM_LINEAR_FREQUENCIES:
1419             return xm_linear_frequency(period - 64.0f * note_offset - 16.0f * period_offset);
1420 
1421         case XM_AMIGA_FREQUENCIES:
1422             if(note_offset == 0) {
1423                 /* A chance to escape from insanity */
1424                 return xm_amiga_frequency(period + 16.0f * period_offset);
1425             }
1426 
1427             /* FIXME: this is very crappy at best */
1428             a = octave = 0;
1429 
1430             /* Find the octave of the current period */
1431             period *= AMIGA_FREQ_SCALE;
1432             if(period > amiga_frequencies[0]) {
1433                 --octave;
1434                 while(period > (amiga_frequencies[0] << (-cast(int)octave))) --octave;
1435             } else if(period < amiga_frequencies[12]) {
1436                 ++octave;
1437                 while(period < (amiga_frequencies[12] >> octave)) ++octave;
1438             }
1439 
1440             /* Find the smallest note closest to the current period */
1441             for(uint8_t i = 0; i < 12; ++i) {
1442                 p1 = amiga_frequencies[i], p2 = amiga_frequencies[i + 1];
1443 
1444                 if(octave > 0) {
1445                     p1 >>= octave;
1446                     p2 >>= octave;
1447                 } else if(octave < 0) {
1448                     p1 <<= (-cast(int)octave);
1449                     p2 <<= (-cast(int)octave);
1450                 }
1451 
1452                 if(p2 <= period && period <= p1) {
1453                     a = i;
1454                     break;
1455                 }
1456             }
1457 
1458             /*if(XM_DEBUG && (p1 < period || p2 > period)) 
1459             {
1460                 //DEBUG("%" PRId32 " <= %f <= %" PRId32 " should hold but doesn't, this is a bug", p2, period, p1);
1461                 assert(false);
1462             }*/
1463 
1464             note = 12.0f * (octave + 2) + a + XM_INVERSE_LERP(p1, p2, period);
1465 
1466             return xm_amiga_frequency(xm_amiga_period(note + note_offset) + 16.0f * period_offset);
1467 
1468         default:
1469 	}
1470 
1471 	return .0f;
1472 }
1473 
1474 void xm_update_frequency(xm_context_t* ctx, xm_channel_context_t* ch) {
1475 	ch.frequency = xm_frequency(
1476                                  ctx, ch.period,
1477                                  ch.arp_note_offset,
1478                                  ch.vibrato_note_offset + ch.autovibrato_note_offset
1479                                  );
1480 	ch.step = ch.frequency / ctx.rate;
1481 }
1482 
1483 void xm_handle_note_and_instrument(xm_context_t* ctx, xm_channel_context_t* ch,
1484 										  xm_pattern_slot_t* s) {
1485                                             if(s.instrument > 0) {
1486                                                 if(ch.current.HAS_TONE_PORTAMENTO() && ch.instrument != null && ch.sample != null) {
1487                                                     /* Tone portamento in effect, unclear stuff happens */
1488                                                     xm_trigger_note(ctx, ch, XM_TRIGGER_KEEP_PERIOD | XM_TRIGGER_KEEP_SAMPLE_POSITION);
1489                                                 } else if(s.note == 0 && ch.sample != null) {
1490                                                     /* Ghost instrument, trigger note */
1491                                                     /* Sample position is kept, but envelopes are reset */
1492                                                     xm_trigger_note(ctx, ch, XM_TRIGGER_KEEP_SAMPLE_POSITION);
1493                                                 } else if(s.instrument > ctx.module_.num_instruments) {
1494                                                     /* Invalid instrument, Cut current note */
1495                                                     xm_cut_note(ch);
1496                                                     ch.instrument = null;
1497                                                     ch.sample = null;
1498                                                 } else {
1499                                                     ch.instrument = ctx.module_.instruments + (s.instrument - 1);
1500                                                 }
1501                                             }
1502 
1503                                             if(NOTE_IS_VALID(s.note)) {
1504                                                 /* Yes, the real note number is s.note -1. Try finding
1505                                                 * THAT in any of the specs! :-) */
1506 
1507                                                 xm_instrument_t* instr = ch.instrument;
1508 
1509                                                 if(ch.current.HAS_TONE_PORTAMENTO() && instr != null && ch.sample != null) {
1510                                                     /* Tone portamento in effect */
1511                                                     ch.note = s.note + ch.sample.relative_note + ch.sample.finetune / 128.0f - 1.0f;
1512                                                     ch.tone_portamento_target_period = xm_period(ctx, ch.note);
1513                                                 } else if(instr == null || ch.instrument.num_samples == 0) {
1514                                                     /* Bad instrument */
1515                                                     xm_cut_note(ch);
1516                                                 } else {
1517                                                     if(instr.sample_of_notes[s.note - 1] < instr.num_samples) {
1518                                                         version(XM_RAMPING)
1519                                                         {
1520                                                             for(uint z = 0; z < XM_SAMPLE_RAMPING_POINTS; ++z) {
1521                                                                 ch.end_of_previous_sample[z] = xm_next_of_sample(ch);
1522                                                             }
1523                                                             ch.frame_count = 0;
1524                                                         }
1525                                                         ch.sample = instr.samples + instr.sample_of_notes[s.note - 1];
1526                                                         ch.orig_note = ch.note = s.note + ch.sample.relative_note
1527                                                             + ch.sample.finetune / 128.0f - 1.0f;
1528                                                         if(s.instrument > 0) {
1529                                                             xm_trigger_note(ctx, ch, 0);
1530                                                         } else {
1531                                                             /* Ghost note: keep old volume */
1532                                                             xm_trigger_note(ctx, ch, XM_TRIGGER_KEEP_VOLUME);
1533                                                         }
1534                                                     } else {
1535                                                         /* Bad sample */
1536                                                         xm_cut_note(ch);
1537                                                     }
1538                                                 }
1539                                             } else if(s.note == 97) {
1540                                                 /* Key Off */
1541                                                 xm_key_off(ch);
1542                                             }
1543 
1544                                             switch(s.volume_column >> 4) {
1545 
1546                                                 case 0x5:
1547                                                     if(s.volume_column > 0x50) break;
1548                                                     goto case 0x1;
1549 
1550                                                 case 0x1:
1551                                                 case 0x2:
1552                                                 case 0x3:
1553                                                 case 0x4:
1554                                                     /* Set volume */
1555                                                     ch.volume = cast(float)(s.volume_column - 0x10) / cast(float)0x40;
1556                                                     break;
1557 
1558                                                 case 0x8: /* Fine volume slide down */
1559                                                     xm_volume_slide(ch, s.volume_column & 0x0F);
1560                                                     break;
1561 
1562                                                 case 0x9: /* Fine volume slide up */
1563                                                     xm_volume_slide(ch, cast(ubyte)(s.volume_column << 4));
1564                                                     break;
1565 
1566                                                 case 0xA: /* Set vibrato speed */
1567                                                     ch.vibrato_param = (ch.vibrato_param & 0x0F) | ((s.volume_column & 0x0F) << 4);
1568                                                     break;
1569 
1570                                                 case 0xC: /* Set panning */
1571                                                     ch.panning = cast(float)(
1572                                                                           ((s.volume_column & 0x0F) << 4) | (s.volume_column & 0x0F)
1573                                                                           ) / cast(float)0xFF;
1574                                                     break;
1575 
1576                                                 case 0xF: /* Tone portamento */
1577                                                     if(s.volume_column & 0x0F) {
1578                                                         ch.tone_portamento_param = ((s.volume_column & 0x0F) << 4)
1579                                                             | (s.volume_column & 0x0F);
1580                                                     }
1581                                                     break;
1582 
1583                                                 default:
1584                                                     break;
1585 
1586                                             }
1587 
1588                                             switch(s.effect_type) {
1589 
1590                                                 case 1: /* 1xx: Portamento up */
1591                                                     if(s.effect_param > 0) {
1592                                                         ch.portamento_up_param = s.effect_param;
1593                                                     }
1594                                                     break;
1595 
1596                                                 case 2: /* 2xx: Portamento down */
1597                                                     if(s.effect_param > 0) {
1598                                                         ch.portamento_down_param = s.effect_param;
1599                                                     }
1600                                                     break;
1601 
1602                                                 case 3: /* 3xx: Tone portamento */
1603                                                     if(s.effect_param > 0) {
1604                                                         ch.tone_portamento_param = s.effect_param;
1605                                                     }
1606                                                     break;
1607 
1608                                                 case 4: /* 4xy: Vibrato */
1609                                                     if(s.effect_param & 0x0F) {
1610                                                         /* Set vibrato depth */
1611                                                         ch.vibrato_param = (ch.vibrato_param & 0xF0) | (s.effect_param & 0x0F);
1612                                                     }
1613                                                     if(s.effect_param >> 4) {
1614                                                         /* Set vibrato speed */
1615                                                         ch.vibrato_param = (s.effect_param & 0xF0) | (ch.vibrato_param & 0x0F);
1616                                                     }
1617                                                     break;
1618 
1619                                                 case 5: /* 5xy: Tone portamento + Volume slide */
1620                                                     if(s.effect_param > 0) {
1621                                                         ch.volume_slide_param = s.effect_param;
1622                                                     }
1623                                                     break;
1624 
1625                                                 case 6: /* 6xy: Vibrato + Volume slide */
1626                                                     if(s.effect_param > 0) {
1627                                                         ch.volume_slide_param = s.effect_param;
1628                                                     }
1629                                                     break;
1630 
1631                                                 case 7: /* 7xy: Tremolo */
1632                                                     if(s.effect_param & 0x0F) {
1633                                                         /* Set tremolo depth */
1634                                                         ch.tremolo_param = (ch.tremolo_param & 0xF0) | (s.effect_param & 0x0F);
1635                                                     }
1636                                                     if(s.effect_param >> 4) {
1637                                                         /* Set tremolo speed */
1638                                                         ch.tremolo_param = (s.effect_param & 0xF0) | (ch.tremolo_param & 0x0F);
1639                                                     }
1640                                                     break;
1641 
1642                                                 case 8: /* 8xx: Set panning */
1643                                                     ch.panning = cast(float)s.effect_param / cast(float)0xFF;
1644                                                     break;
1645 
1646                                                 case 9: /* 9xx: Sample offset */
1647                                                     if(ch.sample != null && NOTE_IS_VALID(s.note)) {
1648                                                         uint32_t final_offset = s.effect_param << (ch.sample.bits == 16 ? 7 : 8);
1649                                                         if(final_offset >= ch.sample.length) {
1650                                                             /* Pretend the sample dosen't loop and is done playing */
1651                                                             ch.sample_position = -1;
1652                                                             break;
1653                                                         }
1654                                                         ch.sample_position = final_offset;
1655                                                     }
1656                                                     break;
1657 
1658                                                 case 0xA: /* Axy: Volume slide */
1659                                                     if(s.effect_param > 0) {
1660                                                         ch.volume_slide_param = s.effect_param;
1661                                                     }
1662                                                     break;
1663 
1664                                                 case 0xB: /* Bxx: Position jump */
1665                                                     if(s.effect_param < ctx.module_.length) {
1666                                                         ctx.position_jump = true;
1667                                                         ctx.jump_dest = s.effect_param;
1668                                                         ctx.jump_row = 0;
1669                                                     }
1670                                                     break;
1671 
1672                                                 case 0xC: /* Cxx: Set volume */
1673                                                     ch.volume = cast(float)((s.effect_param > 0x40)
1674                                                                          ? 0x40 : s.effect_param) / cast(float)0x40;
1675                                                     break;
1676 
1677                                                 case 0xD: /* Dxx: Pattern break */
1678                                                     /* Jump after playing this line */
1679                                                     ctx.pattern_break = true;
1680                                                     ctx.jump_row = (s.effect_param >> 4) * 10 + (s.effect_param & 0x0F);
1681                                                     break;
1682 
1683                                                 case 0xE: /* EXy: Extended command */
1684                                                     switch(s.effect_param >> 4) {
1685 
1686                                                         case 1: /* E1y: Fine portamento up */
1687                                                             if(s.effect_param & 0x0F) {
1688                                                                 ch.fine_portamento_up_param = s.effect_param & 0x0F;
1689                                                             }
1690                                                             xm_pitch_slide(ctx, ch, -cast(int)(ch.fine_portamento_up_param));
1691                                                             break;
1692 
1693                                                         case 2: /* E2y: Fine portamento down */
1694                                                             if(s.effect_param & 0x0F) {
1695                                                                 ch.fine_portamento_down_param = s.effect_param & 0x0F;
1696                                                             }
1697                                                             xm_pitch_slide(ctx, ch, ch.fine_portamento_down_param);
1698                                                             break;
1699 
1700                                                         case 4: /* E4y: Set vibrato control */
1701                                                             ch.vibrato_waveform = s.effect_param & 3;
1702                                                             ch.vibrato_waveform_retrigger = !((s.effect_param >> 2) & 1);
1703                                                             break;
1704 
1705                                                         case 5: /* E5y: Set finetune */
1706                                                             if(NOTE_IS_VALID(ch.current.note) && ch.sample != null) {
1707                                                                 ch.note = ch.current.note + ch.sample.relative_note +
1708                                                                     cast(float)(((s.effect_param & 0x0F) - 8) << 4) / 128.0f - 1.0f;
1709                                                                 ch.period = xm_period(ctx, ch.note);
1710                                                                 xm_update_frequency(ctx, ch);
1711                                                             }
1712                                                             break;
1713 
1714                                                         case 6: /* E6y: Pattern loop */
1715                                                             if(s.effect_param & 0x0F) {
1716                                                                 if((s.effect_param & 0x0F) == ch.pattern_loop_count) {
1717                                                                     /* Loop is over */
1718                                                                     ch.pattern_loop_count = 0;
1719                                                                     break;
1720                                                                 }
1721 
1722                                                                 /* Jump to the beginning of the loop */
1723                                                                 ch.pattern_loop_count++;
1724                                                                 ctx.position_jump = true;
1725                                                                 ctx.jump_row = ch.pattern_loop_origin;
1726                                                                 ctx.jump_dest = ctx.current_table_index;
1727                                                             } else {
1728                                                                 /* Set loop start point */
1729                                                                 ch.pattern_loop_origin = ctx.current_row;
1730                                                                 /* Replicate FT2 E60 bug */
1731                                                                 ctx.jump_row = ch.pattern_loop_origin;
1732                                                             }
1733                                                             break;
1734 
1735                                                         case 7: /* E7y: Set tremolo control */
1736                                                             ch.tremolo_waveform = s.effect_param & 3;
1737                                                             ch.tremolo_waveform_retrigger = !((s.effect_param >> 2) & 1);
1738                                                             break;
1739 
1740                                                         case 0xA: /* EAy: Fine volume slide up */
1741                                                             if(s.effect_param & 0x0F) {
1742                                                                 ch.fine_volume_slide_param = s.effect_param & 0x0F;
1743                                                             }
1744                                                             xm_volume_slide(ch, cast(ubyte)(ch.fine_volume_slide_param << 4));
1745                                                             break;
1746 
1747                                                         case 0xB: /* EBy: Fine volume slide down */
1748                                                             if(s.effect_param & 0x0F) {
1749                                                                 ch.fine_volume_slide_param = s.effect_param & 0x0F;
1750                                                             }
1751                                                             xm_volume_slide(ch, ch.fine_volume_slide_param);
1752                                                             break;
1753 
1754                                                         case 0xD: /* EDy: Note delay */
1755                                                             /* XXX: figure this out better. EDx triggers
1756                                                             * the note even when there no note and no
1757                                                             * instrument. But ED0 acts like like a ghost
1758                                                             * note, EDx (x ≠ 0) does not. */
1759                                                             if(s.note == 0 && s.instrument == 0) {
1760                                                                 uint flags = XM_TRIGGER_KEEP_VOLUME;
1761 
1762                                                                 if(ch.current.effect_param & 0x0F) {
1763                                                                     ch.note = ch.orig_note;
1764                                                                     xm_trigger_note(ctx, ch, flags);
1765                                                                 } else {
1766                                                                     xm_trigger_note(
1767                                                                                     ctx, ch,
1768                                                                                     flags
1769                                                                                     | XM_TRIGGER_KEEP_PERIOD
1770                                                                                     | XM_TRIGGER_KEEP_SAMPLE_POSITION
1771                                                                                     );
1772                                                                 }
1773                                                             }
1774                                                             break;
1775 
1776                                                         case 0xE: /* EEy: Pattern delay */
1777                                                             ctx.extra_ticks = cast(ushort)( (ch.current.effect_param & 0x0F) * ctx.tempo );
1778                                                             break;
1779 
1780                                                         default:
1781                                                             break;
1782 
1783                                                     }
1784                                                     break;
1785 
1786                                                 case 0xF: /* Fxx: Set tempo/BPM */
1787                                                     if(s.effect_param > 0) {
1788                                                         if(s.effect_param <= 0x1F) {
1789                                                             ctx.tempo = s.effect_param;
1790                                                         } else {
1791                                                             ctx.bpm = s.effect_param;
1792                                                         }
1793                                                     }
1794                                                     break;
1795 
1796                                                 case 16: /* Gxx: Set global volume */
1797                                                     ctx.global_volume = cast(float)((s.effect_param > 0x40)
1798                                                                                  ? 0x40 : s.effect_param) / cast(float)0x40;
1799                                                     break;
1800 
1801                                                 case 17: /* Hxy: Global volume slide */
1802                                                     if(s.effect_param > 0) {
1803                                                         ch.global_volume_slide_param = s.effect_param;
1804                                                     }
1805                                                     break;
1806 
1807                                                 case 21: /* Lxx: Set envelope position */
1808                                                     ch.volume_envelope_frame_count = s.effect_param;
1809                                                     ch.panning_envelope_frame_count = s.effect_param;
1810                                                     break;
1811 
1812                                                 case 25: /* Pxy: Panning slide */
1813                                                     if(s.effect_param > 0) {
1814                                                         ch.panning_slide_param = s.effect_param;
1815                                                     }
1816                                                     break;
1817 
1818                                                 case 27: /* Rxy: Multi retrig note */
1819                                                     if(s.effect_param > 0) {
1820                                                         if((s.effect_param >> 4) == 0) {
1821                                                             /* Keep previous x value */
1822                                                             ch.multi_retrig_param = (ch.multi_retrig_param & 0xF0) | (s.effect_param & 0x0F);
1823                                                         } else {
1824                                                             ch.multi_retrig_param = s.effect_param;
1825                                                         }
1826                                                     }
1827                                                     break;
1828 
1829                                                 case 29: /* Txy: Tremor */
1830                                                     if(s.effect_param > 0) {
1831                                                         /* Tremor x and y params do not appear to be separately
1832                                                         * kept in memory, unlike Rxy */
1833                                                         ch.tremor_param = s.effect_param;
1834                                                     }
1835                                                     break;
1836 
1837                                                 case 33: /* Xxy: Extra stuff */
1838                                                     switch(s.effect_param >> 4) {
1839 
1840                                                         case 1: /* X1y: Extra fine portamento up */
1841                                                             if(s.effect_param & 0x0F) {
1842                                                                 ch.extra_fine_portamento_up_param = s.effect_param & 0x0F;
1843                                                             }
1844                                                             xm_pitch_slide(ctx, ch, -1.0f * ch.extra_fine_portamento_up_param);
1845                                                             break;
1846 
1847                                                         case 2: /* X2y: Extra fine portamento down */
1848                                                             if(s.effect_param & 0x0F) {
1849                                                                 ch.extra_fine_portamento_down_param = s.effect_param & 0x0F;
1850                                                             }
1851                                                             xm_pitch_slide(ctx, ch, ch.extra_fine_portamento_down_param);
1852                                                             break;
1853 
1854                                                         default:
1855                                                             break;
1856 
1857                                                     }
1858                                                     break;
1859 
1860                                                 default:
1861                                                     break;
1862 
1863                                             }
1864                                           }
1865 
1866 void xm_trigger_note(xm_context_t* ctx, xm_channel_context_t* ch, uint flags) {
1867 	if(!(flags & XM_TRIGGER_KEEP_SAMPLE_POSITION)) {
1868 		ch.sample_position = 0.0f;
1869 		ch.ping = true;
1870 	}
1871 
1872 	if(ch.sample != null) {
1873 		if(!(flags & XM_TRIGGER_KEEP_VOLUME)) {
1874 			ch.volume = ch.sample.volume;
1875 		}
1876 
1877 		ch.panning = ch.sample.panning;
1878 	}
1879 
1880 	if(!(flags & XM_TRIGGER_KEEP_ENVELOPE)) {
1881 		ch.sustained = true;
1882 		ch.fadeout_volume = ch.volume_envelope_volume = 1.0f;
1883 		ch.panning_envelope_panning = .5f;
1884 		ch.volume_envelope_frame_count = ch.panning_envelope_frame_count = 0;
1885 	}
1886 	ch.vibrato_note_offset = 0.0f;
1887 	ch.tremolo_volume = 0.0f;
1888 	ch.tremor_on = false;
1889 
1890 	ch.autovibrato_ticks = 0;
1891 
1892 	if(ch.vibrato_waveform_retrigger) {
1893 		ch.vibrato_ticks = 0; /* XXX: should the waveform itself also
1894         * be reset to sine? */
1895 	}
1896 	if(ch.tremolo_waveform_retrigger) {
1897 		ch.tremolo_ticks = 0;
1898 	}
1899 
1900 	if(!(flags & XM_TRIGGER_KEEP_PERIOD)) {
1901 		ch.period = xm_period(ctx, ch.note);
1902 		xm_update_frequency(ctx, ch);
1903 	}
1904 
1905 	ch.latest_trigger = ctx.generated_samples;
1906 	if(ch.instrument != null) {
1907 		ch.instrument.latest_trigger = ctx.generated_samples;
1908 	}
1909 	if(ch.sample != null) {
1910 		ch.sample.latest_trigger = ctx.generated_samples;
1911 	}
1912 }
1913 
1914 void xm_cut_note(xm_channel_context_t* ch) {
1915 	/* NB: this is not the same as Key Off */
1916 	ch.volume = .0f;
1917 }
1918 
1919 void xm_key_off(xm_channel_context_t* ch) {
1920 	/* Key Off */
1921 	ch.sustained = false;
1922 
1923 	/* If no volume envelope is used, also cut the note */
1924 	if(ch.instrument == null || !ch.instrument.volume_envelope.enabled) {
1925 		xm_cut_note(ch);
1926 	}
1927 }
1928 
1929 void xm_row(xm_context_t* ctx) {
1930 	if(ctx.position_jump) {
1931 		ctx.current_table_index = ctx.jump_dest;
1932 		ctx.current_row = ctx.jump_row;
1933 		ctx.position_jump = false;
1934 		ctx.pattern_break = false;
1935 		ctx.jump_row = 0;
1936 		xm_post_pattern_change(ctx);
1937 	} else if(ctx.pattern_break) {
1938 		ctx.current_table_index++;
1939 		ctx.current_row = ctx.jump_row;
1940 		ctx.pattern_break = false;
1941 		ctx.jump_row = 0;
1942 		xm_post_pattern_change(ctx);
1943 	}
1944 
1945 	xm_pattern_t* cur = ctx.module_.patterns + ctx.module_.pattern_table[ctx.current_table_index];
1946 	bool in_a_loop = false;
1947 
1948 	/* Read notes… */
1949 	for(uint8_t i = 0; i < ctx.module_.num_channels; ++i) {
1950 		xm_pattern_slot_t* s = cur.slots + ctx.current_row * ctx.module_.num_channels + i;
1951 		xm_channel_context_t* ch = ctx.channels + i;
1952 
1953 		ch.current = s;
1954 
1955 		if(s.effect_type != 0xE || s.effect_param >> 4 != 0xD) {
1956 			xm_handle_note_and_instrument(ctx, ch, s);
1957 		} else {
1958 			ch.note_delay_param = s.effect_param & 0x0F;
1959 		}
1960 
1961 		if(!in_a_loop && ch.pattern_loop_count > 0) {
1962 			in_a_loop = true;
1963 		}
1964 	}
1965 
1966 	if(!in_a_loop) {
1967 		/* No E6y loop is in effect (or we are in the first pass) */
1968 		ctx.loop_count = (ctx.row_loop_count[MAX_NUM_ROWS * ctx.current_table_index + ctx.current_row]++);
1969 	}
1970 
1971 	ctx.current_row++; /* Since this is an uint8, this line can
1972     * increment from 255 to 0, in which case it
1973     * is still necessary to go the next
1974     * pattern. */
1975 	if(!ctx.position_jump && !ctx.pattern_break &&
1976 	   (ctx.current_row >= cur.num_rows || ctx.current_row == 0)) {
1977 		ctx.current_table_index++;
1978 		ctx.current_row = ctx.jump_row; /* This will be 0 most of
1979         * the time, except when E60
1980         * is used */
1981 		ctx.jump_row = 0;
1982 		xm_post_pattern_change(ctx);
1983        }
1984 }
1985 
1986 void xm_envelope_tick(xm_channel_context_t* ch,
1987 							 xm_envelope_t* env,
1988 							 uint16_t* counter,
1989 							 float* outval) {
1990                                 if(env.num_points < 2) {
1991                                     /* Don't really know what to do… */
1992                                     if(env.num_points == 1) {
1993                                         /* XXX I am pulling this out of my ass */
1994                                         *outval = cast(float)env.points[0].value / cast(float)0x40;
1995                                         if(*outval > 1) {
1996                                             *outval = 1;
1997                                         }
1998                                     }
1999 
2000                                     return;
2001                                 } else {
2002                                     uint8_t j;
2003 
2004                                     if(env.loop_enabled) {
2005                                         uint16_t loop_start = env.points[env.loop_start_point].frame;
2006                                         uint16_t loop_end = env.points[env.loop_end_point].frame;
2007                                         uint16_t loop_length = cast(ushort)(loop_end - loop_start);
2008 
2009                                         if(*counter >= loop_end) {
2010                                             *counter -= loop_length;
2011                                         }
2012                                     }
2013 
2014                                     for(j = 0; j < (env.num_points - 2); ++j) {
2015                                         if(env.points[j].frame <= *counter &&
2016                                            env.points[j+1].frame >= *counter) {
2017                                             break;
2018                                            }
2019                                     }
2020 
2021                                     *outval = xm_envelope_lerp(env.points.ptr + j, env.points.ptr + j + 1, *counter) / cast(float)0x40;
2022 
2023                                     /* Make sure it is safe to increment frame count */
2024                                     if(!ch.sustained || !env.sustain_enabled ||
2025                                        *counter != env.points[env.sustain_point].frame) {
2026                                         (*counter)++;
2027                                        }
2028                                 }
2029                              }
2030 
2031 void xm_envelopes(xm_channel_context_t* ch) {
2032 	if(ch.instrument != null) {
2033 		if(ch.instrument.volume_envelope.enabled) {
2034 			if(!ch.sustained) {
2035 				ch.fadeout_volume -= ch.instrument.volume_fadeout / 32768.0f;
2036 				if(ch.fadeout_volume < 0) ch.fadeout_volume = 0;
2037 			}
2038 
2039 			xm_envelope_tick(ch,
2040 							 &(ch.instrument.volume_envelope),
2041 							 &(ch.volume_envelope_frame_count),
2042 							 &(ch.volume_envelope_volume));
2043 		}
2044 
2045 		if(ch.instrument.panning_envelope.enabled) {
2046 			xm_envelope_tick(ch,
2047 							 &(ch.instrument.panning_envelope),
2048 							 &(ch.panning_envelope_frame_count),
2049 							 &(ch.panning_envelope_panning));
2050 		}
2051 	}
2052 }
2053 
2054 void xm_tick(xm_context_t* ctx) {
2055 	if(ctx.current_tick == 0) {
2056 		xm_row(ctx);
2057 	}
2058 
2059 	for(uint8_t i = 0; i < ctx.module_.num_channels; ++i) {
2060 		xm_channel_context_t* ch = ctx.channels + i;
2061 
2062 		xm_envelopes(ch);
2063 		xm_autovibrato(ctx, ch);
2064 
2065 		if(ch.arp_in_progress && !ch.current.HAS_ARPEGGIO()) {
2066 			ch.arp_in_progress = false;
2067 			ch.arp_note_offset = 0;
2068 			xm_update_frequency(ctx, ch);
2069 		}
2070 		if(ch.vibrato_in_progress && !ch.current.HAS_VIBRATO()) {
2071 			ch.vibrato_in_progress = false;
2072 			ch.vibrato_note_offset = 0.0f;
2073 			xm_update_frequency(ctx, ch);
2074 		}
2075 
2076 		switch(ch.current.volume_column >> 4) {
2077 
2078             case 0x6: /* Volume slide down */
2079                 if(ctx.current_tick == 0) break;
2080                 xm_volume_slide(ch, ch.current.volume_column & 0x0F);
2081                 break;
2082 
2083             case 0x7: /* Volume slide up */
2084                 if(ctx.current_tick == 0) break;
2085                 xm_volume_slide(ch, cast(ubyte)(ch.current.volume_column << 4));
2086                 break;
2087 
2088             case 0xB: /* Vibrato */
2089                 if(ctx.current_tick == 0) break;
2090                 ch.vibrato_in_progress = false;
2091                 xm_vibrato(ctx, ch, ch.vibrato_param);
2092                 break;
2093 
2094             case 0xD: /* Panning slide left */
2095                 if(ctx.current_tick == 0) break;
2096                 xm_panning_slide(ch, ch.current.volume_column & 0x0F);
2097                 break;
2098 
2099             case 0xE: /* Panning slide right */
2100                 if(ctx.current_tick == 0) break;
2101                 xm_panning_slide(ch, cast(ubyte)(ch.current.volume_column << 4));
2102                 break;
2103 
2104             case 0xF: /* Tone portamento */
2105                 if(ctx.current_tick == 0) break;
2106                 xm_tone_portamento(ctx, ch);
2107                 break;
2108 
2109             default:
2110                 break;
2111 
2112 		}
2113 
2114 		switch(ch.current.effect_type) {
2115 
2116             case 0: /* 0xy: Arpeggio */
2117                 if(ch.current.effect_param > 0) {
2118                     char arp_offset = ctx.tempo % 3;
2119                     switch(arp_offset) {
2120                         case 2: /* 0 . x . 0 . y . x . … */
2121                             if(ctx.current_tick == 1) {
2122                                 ch.arp_in_progress = true;
2123                                 ch.arp_note_offset = ch.current.effect_param >> 4;
2124                                 xm_update_frequency(ctx, ch);
2125                                 break;
2126                             }
2127                             /* No break here, this is intended */
2128                             goto case 1;
2129 
2130                         case 1: /* 0 . 0 . y . x . … */
2131                             if(ctx.current_tick == 0) 
2132                             {
2133                                 ch.arp_in_progress = false;
2134                                 ch.arp_note_offset = 0;
2135                                 xm_update_frequency(ctx, ch);
2136                                 break;
2137                             }
2138                             /* No break here, this is intended */
2139                             goto case 0;
2140 
2141                         case 0: /* 0 . y . x . … */
2142                             xm_arpeggio(ctx, ch, ch.current.effect_param, cast(ushort)(ctx.current_tick - arp_offset));
2143                             break;
2144 
2145                         default:
2146                             break;
2147                     }
2148                 }
2149                 break;
2150 
2151             case 1: /* 1xx: Portamento up */
2152                 if(ctx.current_tick == 0) break;
2153                 xm_pitch_slide(ctx, ch, -cast(int)ch.portamento_up_param);
2154                 break;
2155 
2156             case 2: /* 2xx: Portamento down */
2157                 if(ctx.current_tick == 0) break;
2158                 xm_pitch_slide(ctx, ch, ch.portamento_down_param);
2159                 break;
2160 
2161             case 3: /* 3xx: Tone portamento */
2162                 if(ctx.current_tick == 0) break;
2163                 xm_tone_portamento(ctx, ch);
2164                 break;
2165 
2166             case 4: /* 4xy: Vibrato */
2167                 if(ctx.current_tick == 0) break;
2168                 ch.vibrato_in_progress = true;
2169                 xm_vibrato(ctx, ch, ch.vibrato_param);
2170                 break;
2171 
2172             case 5: /* 5xy: Tone portamento + Volume slide */
2173                 if(ctx.current_tick == 0) break;
2174                 xm_tone_portamento(ctx, ch);
2175                 xm_volume_slide(ch, ch.volume_slide_param);
2176                 break;
2177 
2178             case 6: /* 6xy: Vibrato + Volume slide */
2179                 if(ctx.current_tick == 0) break;
2180                 ch.vibrato_in_progress = true;
2181                 xm_vibrato(ctx, ch, ch.vibrato_param);
2182                 xm_volume_slide(ch, ch.volume_slide_param);
2183                 break;
2184 
2185             case 7: /* 7xy: Tremolo */
2186                 if(ctx.current_tick == 0) break;
2187                 xm_tremolo(ctx, ch, ch.tremolo_param, ch.tremolo_ticks++);
2188                 break;
2189 
2190             case 0xA: /* Axy: Volume slide */
2191                 if(ctx.current_tick == 0) break;
2192                 xm_volume_slide(ch, ch.volume_slide_param);
2193                 break;
2194 
2195             case 0xE: /* EXy: Extended command */
2196                 switch(ch.current.effect_param >> 4) {
2197 
2198                     case 0x9: /* E9y: Retrigger note */
2199                         if(ctx.current_tick != 0 && ch.current.effect_param & 0x0F) {
2200                             if(!(ctx.current_tick % (ch.current.effect_param & 0x0F))) {
2201                                 xm_trigger_note(ctx, ch, XM_TRIGGER_KEEP_VOLUME);
2202                                 xm_envelopes(ch);
2203                             }
2204                         }
2205                         break;
2206 
2207                     case 0xC: /* ECy: Note cut */
2208                         if((ch.current.effect_param & 0x0F) == ctx.current_tick) {
2209                             xm_cut_note(ch);
2210                         }
2211                         break;
2212 
2213                     case 0xD: /* EDy: Note delay */
2214                         if(ch.note_delay_param == ctx.current_tick) {
2215                             xm_handle_note_and_instrument(ctx, ch, ch.current);
2216                             xm_envelopes(ch);
2217                         }
2218                         break;
2219 
2220                     default:
2221                         break;
2222 
2223                 }
2224                 break;
2225 
2226             case 17: /* Hxy: Global volume slide */
2227                 if(ctx.current_tick == 0) break;
2228                 if((ch.global_volume_slide_param & 0xF0) &&
2229                    (ch.global_volume_slide_param & 0x0F)) {
2230                     /* Illegal state */
2231                     break;
2232                    }
2233                 if(ch.global_volume_slide_param & 0xF0) {
2234                     /* Global slide up */
2235                     float f = cast(float)(ch.global_volume_slide_param >> 4) / cast(float)0x40;
2236                     ctx.global_volume += f;
2237                     if(ctx.global_volume > 1)
2238                         ctx.global_volume = 1;
2239                 } else {
2240                     /* Global slide down */
2241                     float f = cast(float)(ch.global_volume_slide_param & 0x0F) / cast(float)0x40;
2242                     ctx.global_volume -= f;
2243                     if (ctx.global_volume < 0)
2244                         ctx.global_volume = 0;
2245                 }
2246                 break;
2247 
2248             case 20: /* Kxx: Key off */
2249                 /* Most documentations will tell you the parameter has no
2250                 * use. Don't be fooled. */
2251                 if(ctx.current_tick == ch.current.effect_param) {
2252                     xm_key_off(ch);
2253                 }
2254                 break;
2255 
2256             case 25: /* Pxy: Panning slide */
2257                 if(ctx.current_tick == 0) break;
2258                 xm_panning_slide(ch, ch.panning_slide_param);
2259                 break;
2260 
2261             case 27: /* Rxy: Multi retrig note */
2262                 if(ctx.current_tick == 0) break;
2263                 if(((ch.multi_retrig_param) & 0x0F) == 0) break;
2264                 if((ctx.current_tick % (ch.multi_retrig_param & 0x0F)) == 0) {
2265                     xm_trigger_note(ctx, ch, XM_TRIGGER_KEEP_VOLUME | XM_TRIGGER_KEEP_ENVELOPE);
2266 
2267                     /* Rxy doesn't affect volume if there's a command in the volume
2268                     column, or if the instrument has a volume envelope. */
2269                     if (!ch.current.volume_column && !ch.instrument.volume_envelope.enabled){
2270                         float v = ch.volume * multi_retrig_multiply[ch.multi_retrig_param >> 4]
2271                             + multi_retrig_add[ch.multi_retrig_param >> 4] / cast(float)0x40;
2272                         if (v < 0) v = 0;
2273                         if (v > 1) v = 1;
2274                         ch.volume = v;
2275                     }
2276                 }
2277                 break;
2278 
2279             case 29: /* Txy: Tremor */
2280                 if(ctx.current_tick == 0) break;
2281                 ch.tremor_on = (
2282                                  (ctx.current_tick - 1) % ((ch.tremor_param >> 4) + (ch.tremor_param & 0x0F) + 2)
2283                                  >
2284                                  (ch.tremor_param >> 4)
2285                                  );
2286                 break;
2287 
2288             default:
2289                 break;
2290 
2291 		}
2292 
2293 		float panning, volume;
2294 
2295 		panning = ch.panning +
2296 			(ch.panning_envelope_panning - .5f) * (.5f - fast_fabs(ch.panning - .5f)) * 2.0f;
2297 
2298 		if(ch.tremor_on) {
2299             volume = .0f;
2300 		} else {
2301 			volume = ch.volume + ch.tremolo_volume;
2302 			if (volume < 0) volume = 0;
2303             if (volume > 1) volume = 1;
2304 			volume *= ch.fadeout_volume * ch.volume_envelope_volume;
2305 		}
2306 
2307         version(XM_RAMPING)
2308         {
2309 		    /* See https://modarchive.org/forums/index.php?topic=3517.0
2310             * and https://github.com/Artefact2/libxm/pull/16 */
2311 		    ch.target_volume[0] = volume * fast_sqrt(1.0f - panning);
2312 		    ch.target_volume[1] = volume * fast_sqrt(panning);
2313         }
2314         else
2315         {
2316 		    ch.actual_volume[0] = volume * fast_sqrt(1.0f - panning);
2317 		    ch.actual_volume[1] = volume * fast_sqrt(panning);
2318         }
2319 	}
2320 
2321 	ctx.current_tick++;
2322 	if(ctx.current_tick >= ctx.tempo + ctx.extra_ticks) {
2323 		ctx.current_tick = 0;
2324 		ctx.extra_ticks = 0;
2325 	}
2326 
2327 	/* FT2 manual says number of ticks / second = BPM * 0.4 */
2328 	ctx.remaining_samples_in_tick += cast(float)ctx.rate / (cast(float)ctx.bpm * 0.4f);
2329 }
2330 
2331 float xm_sample_at(xm_sample_t* sample, size_t k) {
2332 	return sample.bits == 8 ? (sample.data8[k] / 128.0f) : (sample.data16[k] / 32768.0f);
2333 }
2334 
2335 float xm_next_of_sample(xm_channel_context_t* ch) {
2336 	if(ch.instrument == null || ch.sample == null || ch.sample_position < 0) {
2337         version(XM_RAMPING)
2338         {
2339 		    if(ch.frame_count < XM_SAMPLE_RAMPING_POINTS) {
2340 			    return XM_LERP(ch.end_of_previous_sample[ch.frame_count], .0f,
2341 			                   cast(float)ch.frame_count / cast(float)XM_SAMPLE_RAMPING_POINTS);
2342 		    }
2343         }
2344 		return .0f;
2345 	}
2346 	if(ch.sample.length == 0) {
2347 		return .0f;
2348 	}
2349 
2350 	float u, v, t;
2351 	uint32_t a, b;
2352 	a = cast(uint32_t)ch.sample_position; /* This cast is fine,
2353     * sample_position will not
2354     * go above integer
2355     * ranges */
2356 	if(XM_LINEAR_INTERPOLATION) {
2357 		b = a + 1;
2358 		t = ch.sample_position - a;
2359 	}
2360 	u = xm_sample_at(ch.sample, a);
2361 
2362 	switch(ch.sample.loop_type) {
2363 
2364         case XM_NO_LOOP:
2365             if(XM_LINEAR_INTERPOLATION) {
2366                 v = (b < ch.sample.length) ? xm_sample_at(ch.sample, b) : .0f;
2367             }
2368             ch.sample_position += ch.step;
2369             if(ch.sample_position >= ch.sample.length) {
2370                 ch.sample_position = -1;
2371             }
2372             break;
2373 
2374         case XM_FORWARD_LOOP:
2375             if(XM_LINEAR_INTERPOLATION) {
2376                 v = xm_sample_at(
2377                                  ch.sample,
2378                                  (b == ch.sample.loop_end) ? ch.sample.loop_start : b
2379                                  );
2380             }
2381             ch.sample_position += ch.step;
2382             while(ch.sample_position >= ch.sample.loop_end) {
2383                 ch.sample_position -= ch.sample.loop_length;
2384             }
2385             break;
2386 
2387         case XM_PING_PONG_LOOP:
2388             if(ch.ping) {
2389                 ch.sample_position += ch.step;
2390             } else {
2391                 ch.sample_position -= ch.step;
2392             }
2393             /* XXX: this may not work for very tight ping-pong loops
2394             * (ie switches direction more than once per sample */
2395             if(ch.ping) {
2396                 if(XM_LINEAR_INTERPOLATION) {
2397                     v = xm_sample_at(ch.sample, (b >= ch.sample.loop_end) ? a : b);
2398                 }
2399                 if(ch.sample_position >= ch.sample.loop_end) {
2400                     ch.ping = false;
2401                     ch.sample_position = (ch.sample.loop_end << 1) - ch.sample_position;
2402                 }
2403                 /* sanity checking */
2404                 if(ch.sample_position >= ch.sample.length) {
2405                     ch.ping = false;
2406                     ch.sample_position -= ch.sample.length - 1;
2407                 }
2408             } else {
2409                 if(XM_LINEAR_INTERPOLATION) {
2410                     v = u;
2411                     u = xm_sample_at(
2412                                      ch.sample,
2413                                      (b == 1 || b - 2 <= ch.sample.loop_start) ? a : (b - 2)
2414                                      );
2415                 }
2416                 if(ch.sample_position <= ch.sample.loop_start) {
2417                     ch.ping = true;
2418                     ch.sample_position = (ch.sample.loop_start << 1) - ch.sample_position;
2419                 }
2420                 /* sanity checking */
2421                 if(ch.sample_position <= .0f) {
2422                     ch.ping = true;
2423                     ch.sample_position = .0f;
2424                 }
2425             }
2426             break;
2427 
2428         default:
2429             v = .0f;
2430             break;
2431 	}
2432 
2433 	float endval = (XM_LINEAR_INTERPOLATION ? XM_LERP(u, v, t) : u);
2434 
2435     version(XM_RAMPING)
2436     {
2437 	    if(ch.frame_count < XM_SAMPLE_RAMPING_POINTS) {
2438 		    /* Smoothly transition between old and new sample. */
2439 		    return XM_LERP(ch.end_of_previous_sample[ch.frame_count], endval,
2440 		                   cast(float)ch.frame_count / cast(float)XM_SAMPLE_RAMPING_POINTS);
2441 	    }
2442     }
2443 
2444 	return endval;
2445 }
2446 
2447 void xm_sample(xm_context_t* ctx, float* left, float* right) {
2448 	if(ctx.remaining_samples_in_tick <= 0) {
2449 		xm_tick(ctx);
2450 	}
2451 	ctx.remaining_samples_in_tick--;
2452 
2453 	*left = 0.0f;
2454 	*right = 0.0f;
2455 
2456 	if(ctx.max_loop_count > 0 && ctx.loop_count >= ctx.max_loop_count) {
2457 		return;
2458 	}
2459 
2460 	for(uint8_t i = 0; i < ctx.module_.num_channels; ++i) {
2461 		xm_channel_context_t* ch = ctx.channels + i;
2462 
2463 		if(ch.instrument == null || ch.sample == null || ch.sample_position < 0) {
2464 			continue;
2465 		}
2466 
2467 		const float fval = xm_next_of_sample(ch);
2468 
2469 		if(!ch.muted && !ch.instrument.muted) {
2470 			*left += fval * ch.actual_volume[0];
2471 			*right += fval * ch.actual_volume[1];
2472 		}
2473 
2474         version(XM_RAMPING)
2475         {
2476 		    ch.frame_count++;
2477 		    XM_SLIDE_TOWARDS(ch.actual_volume[0], ch.target_volume[0], ctx.volume_ramp);
2478 		    XM_SLIDE_TOWARDS(ch.actual_volume[1], ch.target_volume[1], ctx.volume_ramp);
2479         }
2480 	}
2481 
2482 	const float fgvol = ctx.global_volume * ctx.amplification;
2483 	*left *= fgvol;
2484 	*right *= fgvol;
2485 
2486 	/*if(XM_DEBUG) {
2487 		if(fast_fabs(*left) > 1 || fast_fabs(*right) > 1) 
2488         {
2489             assert(false);
2490 			//DEBUG("clipping frame: %f %f, this is a bad module or a libxm bug", *left, *right);
2491 		}
2492 	}*/
2493 }
2494 
2495 void xm_generate_samples(xm_context_t* ctx, float* output, size_t numsamples) {
2496 	ctx.generated_samples += numsamples;
2497 
2498 	for(size_t i = 0; i < numsamples; i++) {
2499 		xm_sample(ctx, output + (2 * i), output + (2 * i + 1));
2500 	}
2501 }