-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathParser.js
145 lines (139 loc) · 4.65 KB
/
Parser.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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
const TmLoader = require('./Loader')
const { TmSetting } = require('./Object')
const { TrackParser } = require('./Track')
const TmError = require('./Error')
const EPSILON = 0.0000000001
const defaultInstrument = {
Name: 'Piano',
Spec: [],
Dict: [
{ Name: '1', Pitches: 0 },
{ Name: '2', Pitches: 2 },
{ Name: '3', Pitches: 4 },
{ Name: '4', Pitches: 5 },
{ Name: '5', Pitches: 7 },
{ Name: '6', Pitches: 9 },
{ Name: '7', Pitches: 11 }
]
}
class Parser {
/**
* Tm Parser
* @param {data} data 经过tok的JSON对象
* @example
* new Parser(tokenizedData)
*/
constructor(data) {
this.Sections = data.Sections
this.Library = new TmLoader(data.Syntax)
this.sectionContext = {
Settings: new TmSetting(),
PrevFin: undefined
}
}
parse() {
let homonym = {}
const result = []
this.expandSection()
this.Library.proGlobal(this)
this.Sections.forEach(token => {
if (token.Type === 'Section') {
const dict = {}, data = this.parseSection(token)
result.push(data)
data.Tracks.forEach(track => {
dict[track.Name] = track
if (track.Name in homonym) {
this.Library.proMerge(homonym[track.Name], track)
}
homonym = dict
})
} else {
this.Library.Package.applyFunction({
Settings: this.sectionContext.Settings
}, token)
}
})
return result.filter(section => section.Tracks.length > 0)
}
expandSection() {
const result = []
for (let index = 0; index < this.Sections.length; index++) {
const section = this.Sections[index]
section.Index = index
section.Type = 'Section'
result.push(...section.Prolog, section, ...section.Epilog)
delete section.Prolog
delete section.Epilog
}
this.Sections = result
}
/**
* parse section
* @param {Tm.Section} section
*/
parseSection(section) {
const settings = this.sectionContext.Settings.extend()
for (const setting of section.Settings) {
for (const token of setting.Spec) {
if (token.Type === 'Function') {
this.Library.Package.applyFunction({ Settings: settings }, token)
}
}
}
const result = [], warnings = [], statistics = {}
section.Tracks.forEach(track => {
if (track.Name !== undefined) {
this.Library.Track[track.Name] = track.Content
}
if (track.Play) {
const trackResult = []
if (track.Instruments.length === 0) {
track.Instruments.push(defaultInstrument)
}
for (const inst of track.Instruments) {
const data = new TrackParser(track, inst, settings, this.Library).parse()
if (inst.Name in statistics) {
statistics[inst.Name] += 1
} else {
statistics[inst.Name] = 1
}
data.Name += '.' + String(statistics[inst.Name])
data.Index = track.Index
trackResult.push(data)
}
result.push(...trackResult)
}
})
const max = Math.max(...result.map((track) => track.Meta.Duration))
if (!result.every((track) => Math.abs(track.Meta.Duration - max) < EPSILON)) {
warnings.push(new TmError('Section::DiffDuration', [], {
Expected: result.map(() => max),
Actual: result.map(track => track.Meta.Duration)
}))
}
// const maxBarIni = Math.max(...result.map((track) => track.Meta.BarFirst))
// const maxBarFin = Math.max(...result.map((track) => track.Meta.BarLast))
// const ini = result.every((track) => track.Meta.BarFirst === maxBarIni)
// const fin = result.every((track) => track.Meta.BarLast === maxBarFin)
// FIXME: ini & fin
// if (!ini) {
// warnings.push(new TmError(TmError.Types.Section.InitiativeBar, [], { Expected: maxBarIni, Actual: sec.Tracks.map((l) => l.Meta.BarFirst) }))
// }
// if (!fin && !Number.isNaN(maxBarFin)) {
// warnings.push(new TmError(TmError.Types.Section.FinalBar, [], { Expected: maxBarFin, Actual: sec.Tracks.map((l) => l.Meta.BarLast) }))
// }
// if (fin && this.sectionContext.PrevFin === undefined) {
// this.sectionContext.PrevFin = maxBarFin
// } else if (fin && ini && maxBarIni !== settings.Bar && this.sectionContext.PrevFin + maxBarIni !== settings.Bar) {
// const expected = settings.Bar - this.sectionContext.PrevFin
// warnings.push(new TmError(TmError.Types.Section.Mismatch, [], { Expected: expected, Actual: sec.Tracks.map((l) => l.Meta.BarFirst) }))
// this.sectionContext.PrevFin = maxBarFin
// }
return {
Tracks: result,
Warnings: warnings,
Index: section.Index
}
}
}
module.exports = Parser