-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
116 lines (99 loc) · 3.29 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/**
* Export `ModParser`.
*/
exports = module.exports = ModParser;
/**
* Channel count by identifier table.
*/
var channelCountByIdentifier = exports.channelCountByIdentifier = {
'TDZ1': 1, '1CHN': 1, 'TDZ2': 2, '2CHN': 2, 'TDZ3': 3, '3CHN': 3,
'M.K.': 4, 'FLT4': 4, 'M!K!': 4, '4CHN': 4, 'TDZ4': 4, '5CHN': 5, 'TDZ5': 5,
'6CHN': 6, 'TDZ6': 6, '7CHN': 7, 'TDZ7': 7, '8CHN': 8, 'TDZ8': 8, 'OCTA': 8, 'CD81': 8,
'9CHN': 9, 'TDZ9': 9,
'10CH': 10, '11CH': 11, '12CH': 12, '13CH': 13, '14CH': 14, '15CH': 15, '16CH': 16, '17CH': 17,
'18CH': 18, '19CH': 19, '20CH': 20, '21CH': 21, '22CH': 22, '23CH': 23, '24CH': 24, '25CH': 25,
'26CH': 26, '27CH': 27, '28CH': 28, '29CH': 29, '30CH': 30, '31CH': 31, '32CH': 32
}
/**
* ModParser class.
*
* @param {String} mod
* @api public
*/
function ModParser(mod){
this.data = mod;
this.samples = [];
this.sampleData = [];
this.positions = [];
this.patternCount = 0;
this.patterns = [];
this.title = trimNulls(mod.substr(0, 20))
this.sampleCount = 31;
for (var i = 0; i < this.sampleCount; i++) {
var sampleInfo = mod.substr(20 + i*30, 30);
var sampleName = trimNulls(sampleInfo.substr(0, 22));
this.samples[i] = {
name: sampleName,
length: getWord(sampleInfo, 22) * 2,
finetune: sampleInfo.charCodeAt(24),
volume: sampleInfo.charCodeAt(25),
repeatOffset: getWord(sampleInfo, 26) * 2,
repeatLength: getWord(sampleInfo, 28) * 2,
}
}
this.positionCount = mod.charCodeAt(950);
this.positionLoopPoint = mod.charCodeAt(951);
for (var i = 0; i < 128; i++) {
this.positions[i] = mod.charCodeAt(952+i);
if (this.positions[i] >= this.patternCount) {
this.patternCount = this.positions[i]+1;
}
}
var identifier = mod.substr(1080, 4);
this.channelCount = channelCountByIdentifier[identifier];
if (!this.channelCount) {
this.channelCount = 4;
}
var patternOffset = 1084;
for (var pat = 0; pat < this.patternCount; pat++) {
this.patterns[pat] = [];
for (var row = 0; row < 64; row++) {
this.patterns[pat][row] = [];
for (var chan = 0; chan < this.channelCount; chan++) {
b0 = mod.charCodeAt(patternOffset);
b1 = mod.charCodeAt(patternOffset + 1);
b2 = mod.charCodeAt(patternOffset + 2);
b3 = mod.charCodeAt(patternOffset + 3);
var eff = b2 & 0x0f;
this.patterns[pat][row][chan] = {
sample: (b0 & 0xf0) | (b2 >> 4),
period: ((b0 & 0x0f) << 8) | b1,
effect: eff,
effectParameter: b3
};
if (eff == 0x0E) {
this.patterns[pat][row][chan].extEffect = (b3 & 0xF0) >> 4;
this.patterns[pat][row][chan].extEffectParameter = (b3 & 0x0F);
}
patternOffset += 4;
}
}
}
var sampleOffset = patternOffset;
for (var s = 0; s < this.sampleCount; s++) {
this.samples[s].startOffset = sampleOffset;
this.sampleData[s] = new Uint8Array(this.samples[s].length);
var i = 0;
for (var o = sampleOffset, e = sampleOffset + this.samples[s].length; o < e; o++) {
this.sampleData[s][i] = mod.charCodeAt(o);
i++;
}
sampleOffset += this.samples[s].length;
}
}
function trimNulls(str){
return str.replace(/\x00+$/, '');
}
function getWord(str, pos){
return (str.charCodeAt(pos) << 8) + str.charCodeAt(pos+1);
}