diff --git a/src/voice.ts b/src/voice.ts index c012d9a..4c5ee2a 100644 --- a/src/voice.ts +++ b/src/voice.ts @@ -1,4 +1,4 @@ - +import path from 'path'; interface Voice { directory: string; @@ -7,4 +7,167 @@ interface Voice { type Voices = { [name: string]: Voice }; +const LINES = { + NEGATIVE: 'negative', + POINT: 'point', + ZERO: 'zero', + ONE: 'one', + TWO: 'two', + THREE: 'three', + FOUR: 'four', + FIVE: 'five', + SIX: 'six', + SEVEN: 'seven', + EIGHT: 'eight', + NINE: 'nine', + TEN: 'ten', + ELEVEN: 'eleven', + TWELVE: 'twelve', + THIRTEEN: 'thirteen', + FIFTEEN: 'fifteen', + TEEN: 'teen', + TWENTY: 'twenty', + THIRTY: 'thirty', + FORTY: 'forty', + FIFTY: 'fifty', + SIXTY: 'sixty', + SEVENTY: 'seventy', + EIGHTY: 'eighty', + NINETY: 'ninety', + HUNDRED: 'hundred', + THOUSAND: 'thousand', + MILLION: 'million', + BILLION: 'billion', + TRILLION: 'trillion' +} + +function formatNumber(num: number): string { + const parts = num.toString().split("."); + parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","); + return parts.join("."); +} + +function digitByDigit(str: string): string[] { + const tokens: string[] = []; + const input = str.replaceAll(',', ''); + const map = [ + LINES.ZERO, + LINES.ONE, + LINES.TWO, + LINES.THREE, + LINES.FOUR, + LINES.FIVE, + LINES.SIX, + LINES.SEVEN, + LINES.EIGHT, + LINES.NINE + ] + for (let i = 0; i < input.length; i++) { + tokens.push(map[parseInt(input.charAt(i))]); + } + return tokens; +} + +function tens(str: string): string[] { + if (str === '0') { + return [LINES.ZERO]; + } + const tokens: string[] = []; + const num = parseInt(str); + const map = { + '2': LINES.TWENTY, + '3': LINES.THIRTY, + '4': LINES.FORTY, + '5': LINES.FIFTY, + '6': LINES.SIXTY, + '7': LINES.SEVENTY, + '8': LINES.EIGHTY, + '9': LINES.NINETY + }; + const ones = str.charAt(str.length - 1); + if (num === 0) { + return []; + } + else if (num >= 20) { + tokens.push(map[str.charAt(0)]); + if (ones !== '0') { + tokens.push(...digitByDigit(ones)); + } + } + else if (num < 10) { + tokens.push(...digitByDigit(ones)); + } + else { + const weirdoNumberMap = [ + [LINES.TEN], + [LINES.ELEVEN], + [LINES.TWELVE], + [LINES.THIRTEEN], + [LINES.FOUR, LINES.TEEN], + [LINES.FIFTEEN], + [LINES.SIX, LINES.TEEN], + [LINES.SEVEN, LINES.TEEN], + [LINES.EIGHT, LINES.TEEN], + [LINES.NINE, LINES.TEEN], + ] + tokens.push(...weirdoNumberMap[num - 10]); + } + return tokens; +} + +function hundreds(str: string): string[] { + const tokens: string[] = []; + if (str.length === 3 && str.charAt(0) !== '0') { + tokens.push(...digitByDigit(str.charAt(0))); + tokens.push(LINES.HUNDRED); + str = str.substring(1); + } + tokens.push(...tens(str)); + return tokens; +} + +function integer(str: string): string[] { + const tokens: string[] = []; + const numGroups = str.split(','); + const seperators = [LINES.TRILLION, LINES.BILLION, LINES.MILLION, LINES.THOUSAND]; + if (numGroups.length > 5) { + return digitByDigit(str); + } + seperators.splice(0, seperators.length - numGroups.length + 1); + numGroups.forEach(g => { + if (g !== '000') { + tokens.push(...hundreds(g)); + } + if (seperators.length === 0) { + return; + } + const sep = seperators.shift(); + if (g !== '000') { + tokens.push(sep); + } + }); + return tokens; +} + +function voiceLines(voice: Voice, num: number): string[] { + if (Math.abs(num) > 999999999999999 || isNaN(num)) { + return []; + } + const tokens: string[] = []; + const str = formatNumber(num); + const parts = str.split('.'); + if (parts[0].startsWith('-')) { + tokens.push(LINES.NEGATIVE); + parts[0] = parts[0].substring(1); + } + tokens.push(...integer(parts[0])); + if (parts.length > 1) { + tokens.push(LINES.POINT); + tokens.push(...digitByDigit(parts[1])); + } + return tokens.map(l => path.join(voice.directory, `${l}.${voice.extension}`)); +} + +export default voiceLines; +export { voiceLines }; export type { Voice, Voices };