UNPKG

ultrastar2ass

Version:

Convert Ultrastar karaoke files to ASS files

200 lines 7.54 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); class UltrastarParser { config; meta; track; track_duet; first_pass; constructor(config) { this.config = config; this.meta = { title: null, artist: null, mp3: null, bpm: null, gap: 0, duet: false }; this.track = []; this.track_duet = []; this.first_pass = true; } parse(file) { const lines = file.replace(/\r+/g, '').split('\n'); let sentenceID = 1; let trackID = 1; let relative = false; let beatsCount = 0; let beatDuration = null; let currentStart = null; let previousEnd = null; let syllables = []; for (let i = 0; i < lines.length; i++) { const line = lines[i].replace(/^\s*/, ''); if (line.replace(/\s*/g, '').length == 0) { continue; } if (line[0] == '#') { let matches = line.match(/(\w+):(.+)/); if (matches == null || matches.length == 0) { continue; } matches = matches[0].split(':'); const keyword = matches[0].toLowerCase(); let value = matches[1]; if (keyword == 'bpm' || keyword == 'gap') { value = parseFloat(value.replace(',', '.')); } if (keyword == 'bpm') { beatDuration = (60000) / (value * 4); } if (keyword == 'gap') { if (this.config.offset) { value += this.config.offset; } currentStart = value; } if (keyword == 'relative' && value.toLowerCase() == 'yes') { relative = true; } if (value != '') { this.meta[keyword] = value; } continue; } if ((line == 'P2' || line == 'P 2' || line[0] == 'E') && syllables.length > 0) { const sentence = this.makeSentence(sentenceID, syllables, currentStart, null, previousEnd); if (currentStart != null) { currentStart = null; } if (trackID == 1) { this.track.push(sentence); } else { this.track_duet.push(sentence); } sentenceID++; syllables = []; } if (line == 'P2' || line == 'P 2') { trackID = 2; this.meta.duet = true; continue; } if ([':', '*', 'F', 'R', 'G'].indexOf(line[0]) > -1) { let matches = line.match(/^[:*FRG] (-?\d+) (\d+) (-?\d+) (.+)/); if (matches == null || matches.length == 0) { continue; } const syllable = { type: 'normal' }; syllable.text = matches[0].split(' ').splice(4).join(' '); matches = matches[0].split(' ').splice(1, 3); if (!relative) { syllable.start = Math.floor(this.meta.gap + parseInt(matches[0]) * beatDuration); } else { syllable.start = Math.floor(this.meta.gap + (beatsCount + parseInt(matches[0])) * beatDuration); } const matchesAfter = lines[i + 1].replace(/^\s*/, '').match(/^[:*FRG-] (-?\d+)/); syllable.duration = Math.floor((matchesAfter ? (parseInt(matchesAfter[1]) - parseInt(matches[0])) : parseInt(matches[1])) * beatDuration); syllable.end = syllable.start + syllable.duration; syllable.pitch = parseInt(matches[2]); if (this.meta.gap < 0 && syllable.start < 0) { syllable.start = 0; syllable.duration = syllable.end; } if (line[0] == '*' || line[0] == 'G') { syllable.type = 'golden'; } else if (line[0] == 'F') { syllable.type = 'freestyle'; } else if (line[0] == 'R') { syllable.type = 'rap'; } beatsCount += parseInt(matches[1]); syllables.push(syllable); } if (line[0].indexOf('-') > -1 && syllables.length > 0) { let matches = line.match(/^- ?(\d+)\s?(\d+)?/); if (matches == null || matches.length == 0) { continue; } matches = matches[0].split(' '); if (matches[0].length > 1) { matches[0] = matches[0].substr(1, matches[0].length); } else { matches = matches.splice(1); } let currentEnd = null; if (!relative) { currentEnd = Math.floor(this.meta.gap + parseInt(matches[0]) * beatDuration); } else { currentEnd = Math.floor(this.meta.gap + (beatsCount + parseInt(matches[0])) * beatDuration); } if (this.meta.gap < 0 && currentStart < 0) { currentStart = 0; } else if (null !== currentStart && (0 < syllables.length) && this.first_pass) { currentStart = Math.max(currentStart, syllables[0].start); } const sentence = this.makeSentence(sentenceID, syllables, currentStart, currentEnd, previousEnd); if (currentStart != null) { currentStart = null; } previousEnd = sentence.end; this.first_pass = false; if (trackID == 1) { this.track.push(sentence); } else { this.track_duet.push(sentence); } sentenceID++; syllables = []; } if (line[0] == 'E') { break; } } return { meta: this.meta, track: this.track, track_duet: (this.track_duet.length > 0) ? this.track_duet : null }; } makeSentence(id, syllables, start, end, previousEnd) { const sentence = { id: id, start: syllables[0].start, end: syllables[syllables.length - 1].end }; if (this.config.syllable_precision) { sentence.syllables = syllables; } else { sentence.text = ''; for (let j = 0; j < syllables.length; j++) { sentence.text += syllables[j].text; } } if (start != null) { sentence.start = start; } else if (previousEnd != null && this.config.start_as_previous_end) { sentence.start = previousEnd; } if (end != null) { sentence.end = end; } sentence.duration = sentence.end - sentence.start; return sentence; } } exports.default = UltrastarParser; //# sourceMappingURL=ultrastar.js.map