Skip to content

Commit 9fc46f1

Browse files
Interface 4.0 + stacking
1 parent f599b96 commit 9fc46f1

17 files changed

Lines changed: 1153 additions & 152 deletions

File tree

WONT_FIX.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Won't Fix List
2+
3+
This file tracks limitations, design constraints, and bug reports that are classified as "Won't Fix" because they are deeply rooted in the architecture of Augustinus or represent intentional trade-offs.
4+
5+
## 1. The use of `@` and `#` characters in the text treatment
6+
- **Description**: The core lyric-to-music processing engine uses `@` as a syllable boundary/GABC note placeholder and `#` as a marker for tonic (stressed) syllables.
7+
- **Consequence**: If the input lyrics contain literal `@` or `#` characters, they will be treated as control characters. They will be stripped or replaced, potentially breaking the musical mapping logic.
8+
- **Workaround**: Avoid using literal `@` or `#` characters in the source text, or pre-process them/escape them before submitting to Augustinus.
9+
- **Reason**: The app expects liturgical text as input, which shouldn't have these characters anyways.
10+
11+
## 2. Debounced Auto-Generation of GABC (Live Updates)
12+
- **Description**: Automatically generating the score in real-time as the user types.
13+
- **Reason for Won't Fix**: Keeping score generation manual (requiring a click on the "Gerar" button) is preferred to avoid constant recalculations/rendering lag while typing large chants, ensuring a more stable user editing experience.
14+

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"scripts": {
77
"test": "bun test",
88
"test:visual": "bun test/visual-report.ts",
9+
"build:cli": "bun run --filter=@augustinus/cli build",
910
"start:frontend": "bun run --filter=augustinus-frontend dev",
1011
"start:cli": "bun run --filter=@augustinus/cli start",
1112
"start:api": "bun run --filter=@augustinus/api start"

packages/cli/out.txt

Whitespace-only changes.

packages/cli/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
},
1111
"scripts": {
1212
"start": "bun run src/cli.ts",
13+
"build": "tsc && chmod +x dist/cli.js",
1314
"prepublishOnly": "tsc"
1415
},
1516
"dependencies": {

packages/cli/src/cli.ts

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,36 +15,66 @@ const yargsOptions: any = {
1515
text: { type: 'string', alias: 't', description: 'Texto de entrada para converter para GABC' },
1616
input: { type: 'string', alias: 'i', description: 'Caminho do arquivo de entrada' },
1717
output: { type: 'string', alias: 'o', description: 'Caminho do arquivo de saída' },
18-
model: { type: 'string', demandOption: true, alias: 'm', description: 'Nome do modelo a ser usado' },
18+
model: { type: 'string', alias: 'm', description: 'Nome do modelo a ser usado' },
19+
'list-models': { type: 'boolean', description: 'Lista todos os modelos disponíveis' },
1920
};
2021

2122
// Automatically add all parameters from core schema
2223
parameterDefinitions.forEach(param => {
23-
if (param.group === 'hidden') return;
24-
25-
yargsOptions[param.key] = {
24+
const option: any = {
2625
type: param.type === 'boolean' ? 'boolean' : 'string',
2726
default: param.defaultValue,
2827
description: param.label
2928
};
29+
30+
yargsOptions[param.key] = option;
3031
});
3132

32-
const argv: any = yargs(hideBin(process.argv))
33+
const yargsInstance = yargs(hideBin(process.argv))
3334
.options(yargsOptions)
3435
.check((argv: any) => {
36+
if (argv['list-models']) return true;
37+
if (!argv.model) {
38+
throw new Error('É necessário fornecer --model.');
39+
}
3540
if (!argv.text && !argv.input) {
3641
throw new Error('É necessário fornecer --text ou --input.');
3742
}
3843
return true;
3944
})
45+
.group(['text', 'input', 'output', 'model', 'list-models'], 'Opções Principais');
46+
47+
// Add groups from parameter definitions
48+
const groups = [...new Set(parameterDefinitions.map(p => p.group))];
49+
groups.forEach(groupName => {
50+
const keys = parameterDefinitions
51+
.filter(p => p.group === groupName)
52+
.map(p => p.key);
53+
54+
// Capitalize group name for display
55+
const displayName = groupName.charAt(0).toUpperCase() + groupName.slice(1);
56+
yargsInstance.group(keys, displayName);
57+
});
58+
59+
const argv: any = yargsInstance
4060
.help()
4161
.alias('help', 'h')
4262
.parseSync();
4363

44-
const modelObject = defaultModels.find((m: Model) => m.name === argv.model);
64+
if (argv['list-models']) {
65+
console.log('Modelos disponíveis:');
66+
defaultModels.forEach((m: Model) => {
67+
console.log(` - ${m.name} (${m.type}${m.tom ? ', ' + m.tom : ''})`);
68+
});
69+
process.exit(0);
70+
}
71+
72+
const modelName = argv.model.toLowerCase();
73+
const modelObject = defaultModels.find((m: Model) => m.name.toLowerCase() === modelName);
4574

4675
if (!modelObject) {
4776
console.error(`Modelo '${argv.model}' não encontrado.`);
77+
console.log('Use --list-models para ver os modelos disponíveis.');
4878
process.exit(1);
4979
}
5080

packages/core/src/augustinus.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { Model, Parameters } from "./types/index.js";
1+
import { Model, Parameters, getDefaultParameters } from "./types/index.js";
22
import { preprocessInput, handleCustomModel } from "./core/parameters.js";
33
import { applyModel } from "./modules/apply-model.js";
44
import defaultModels from '../assets/models.json' with { type: 'json' };
55

6-
export default function generateGabc(input: string, modelObject: Model, parametersObject: Parameters): string {
6+
export default function generateGabc(input: string, modelObject: Model, partialParameters: Partial<Parameters> = {}): string {
7+
const parametersObject = { ...getDefaultParameters(), ...partialParameters };
78
let model = handleCustomModel(modelObject, parametersObject);
89
let psalm = model.type === "salmo" ? true : false;
910

packages/core/src/modules/apply-model.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ export function applyModel(lyrics: string, gabcModel: string, psalm: boolean, do
2424
return placeholder;
2525
});
2626

27+
const stackedParts: string[] = [];
28+
const stackedPlaceholder = "||STACKEDPART||";
29+
30+
deTaggedLyrics = deTaggedLyrics.replace(/\[([^\]]+)\]/g, (match, content) => {
31+
const lines = content.split('/');
32+
const stackedContent = lines.map(line => `\\vphantom{dp}${line}`).join('&');
33+
stackedParts.push(`<v>\\stacktext{${stackedContent}}</v>`);
34+
return stackedPlaceholder;
35+
});
36+
2737
let wordsWithNotePlaceholders: string[] = deTaggedLyrics.split(/\s+/).filter(w => w).map(word => {
2838
const processToken = (token: string) => {
2939
if (token === placeholder) {
@@ -32,13 +42,17 @@ export function applyModel(lyrics: string, gabcModel: string, psalm: boolean, do
3242
if (token === specialPlaceholder) {
3343
return specialTaggedParts.shift() || "";
3444
}
45+
if (token === stackedPlaceholder) {
46+
return (stackedParts.shift() || "") + "@";
47+
}
3548
if (!/[a-zA-Z\u00C0-\u00FF]/i.test(token)) {
3649
return token;
3750
}
3851
const syllableArray = syllable(token).split(/(?<=@)/);
3952
const tonicIndex = syllableArray.length - tonic(syllableArray);
4053
const result = syllableArray.map((s, i) => {
41-
const isUnstressed = unstressedMonosyllables.includes(s);
54+
const cleanSyllable = s.replace(/[^a-zA-Z\u00C0-\u00FF]/g, "").toLowerCase();
55+
const isUnstressed = unstressedMonosyllables.includes(cleanSyllable);
4256
let processedSyllable = (i === tonicIndex && !isUnstressed) ? "#" + s : s;
4357
if (curlyDiphthongs) {
4458
processedSyllable = processedSyllable.replace(diphthongRegex, "{$1$2}");
@@ -48,8 +62,8 @@ export function applyModel(lyrics: string, gabcModel: string, psalm: boolean, do
4862
return result;
4963
}
5064

51-
if (word.includes(placeholder) || word.includes(specialPlaceholder)) {
52-
return word.split(/(\|\|TAGGEDPART\|\||\|\|SPECIALTAGGEDPART\|\|)/).filter(t => t).map(processToken).join("");
65+
if (word.includes(placeholder) || word.includes(specialPlaceholder) || word.includes(stackedPlaceholder)) {
66+
return word.split(/(\|\|TAGGEDPART\|\||\|\|SPECIALTAGGEDPART\|\||\|\|STACKEDPART\|\|)/).filter(t => t).map(processToken).join("");
5367
}
5468
return processToken(word);
5569
});

packages/core/src/types/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@ export type ParameterType = 'boolean' | 'string' | 'select';
2323
export const parameterDefinitions = [
2424
// GENERAL - OBLIGATORY/COMMON FIRST
2525
{ key: 'separator', label: 'Separador', type: 'string', group: 'general', defaultValue: '.' },
26-
{ key: 'addOptionalStart', label: 'Adicionar começo', type: 'boolean', group: 'general', defaultValue: true },
27-
{ key: 'addOptionalEnd', label: 'Adicionar final', type: 'boolean', group: 'general', defaultValue: true },
26+
{ key: 'addOptionalStart', label: 'Adicionar começo', type: 'boolean', group: 'general', defaultValue: false },
27+
{ key: 'addOptionalEnd', label: 'Adicionar final', type: 'boolean', group: 'general', defaultValue: false },
2828
{ key: 'removeNumbers', label: 'Remover números', type: 'boolean', group: 'general', defaultValue: true },
2929
{ key: 'removeParenthesis', label: 'Remover parênteses', type: 'boolean', group: 'general', defaultValue: true },
3030
{ key: 'removeSeparator', label: 'Remover separador', type: 'boolean', group: 'general', defaultValue: false },
3131
{ key: 'quelisma', label: 'Quelisma no prefácio (experimental)', type: 'boolean', group: 'general', defaultValue: false },
3232
{ key: 'includeBarredVParenthesis', label: 'Incluir () após o ℣ barrado', type: 'boolean', group: 'general', defaultValue: false },
33-
{ key: 'curlyDiphthongs', label: 'Incluir {} em ditongos', type: 'boolean', group: 'general', defaultValue: true },
33+
{ key: 'curlyDiphthongs', label: 'Incluir {} em ditongos', type: 'boolean', group: 'general', defaultValue: false },
3434

3535
// PSALMS
3636
{ key: 'repeatIntonation', label: 'Repetir entonação', type: 'boolean', group: 'psalm', defaultValue: true },

0 commit comments

Comments
 (0)