Skip to content

Commit c299b20

Browse files
authored
feat: Implement new bracket/braces/system rendering (#1730)
1 parent f76d628 commit c299b20

File tree

201 files changed

+653
-266
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

201 files changed

+653
-266
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
"test": "mocha",
5959
"test-csharp": "cd src.csharp && dotnet test -c Release",
6060
"test-kotlin": "cd src.kotlin/alphaTab && gradlew testReleaseUnitTest --info",
61-
"test-accept-reference": "node scripts/accept-new-reference-files.mjs"
61+
"test-accept-reference": "tsx scripts/accept-new-reference-files.ts"
6262
},
6363
"devDependencies": {
6464
"@coderline/alphaskia": "^2.3.120",

rollup.plugin.server.ts

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ import fs from 'fs';
44
import path from 'path';
55
import cors from 'cors';
66
import url from 'url';
7+
import { acceptOne } from './scripts/accept-new-reference-files.common'
78

89
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
910

1011
export interface ServerOptions {
11-
port: number,
12-
openPage: string
12+
port: number;
13+
openPage: string;
1314
}
1415

1516
let app: express.Express;
@@ -21,16 +22,9 @@ export default function server(options: ServerOptions) {
2122
app = express();
2223

2324
app.use(cors());
24-
25-
const exposedFolders = [
26-
'dist',
27-
'src',
28-
'font',
29-
'img',
30-
'playground',
31-
'playground-template',
32-
'test-data'
33-
];
25+
app.use(express.json());
26+
27+
const exposedFolders = ['dist', 'src', 'font', 'img', 'playground', 'playground-template', 'test-data'];
3428

3529
for (const exposedFolder of exposedFolders) {
3630
app.use('/' + exposedFolder, express.static(exposedFolder));
@@ -41,15 +35,15 @@ export default function server(options: ServerOptions) {
4135
const response: any = [];
4236

4337
async function crawl(d: string, name: string) {
44-
console.log('Crawling ', d);
38+
// console.log('Crawling ', d);
4539
const dir = await fs.promises.opendir(d);
4640
try {
4741
while (true) {
4842
const entry = await dir.read();
4943
if (!entry) {
5044
break;
5145
} else if (entry.isDirectory() && entry.name !== '.' && entry.name !== '..') {
52-
await crawl(path.join(d, entry.name), name + '/' + entry.name)
46+
await crawl(path.join(d, entry.name), name + '/' + entry.name);
5347
} else if (entry.isFile()) {
5448
if (entry.name.endsWith('.new.png')) {
5549
response.push({
@@ -60,38 +54,64 @@ export default function server(options: ServerOptions) {
6054
}
6155
}
6256
}
63-
}
64-
finally {
57+
} finally {
6558
await dir.close();
6659
}
6760
}
6861

6962
const testDataPath = path.join(__dirname, 'test-data');
70-
console.log('will crawl: ', testDataPath)
63+
// console.log('will crawl: ', testDataPath);
7164
await crawl(testDataPath, 'test-data');
7265

7366
res.json(response);
67+
} catch (e) {
68+
res.json({
69+
message: (e as Error).message,
70+
stack: (e as Error).stack
71+
});
7472
}
75-
catch (e) {
73+
});
74+
75+
app.post('/accept-test-result', async (req, res) => {
76+
try {
77+
const body = req.body;
78+
// basic validation that nothing bad happens
79+
if(typeof body.originalFile !== 'string'){
80+
res.sendStatus(400);
81+
return;
82+
}
83+
const newFile = path.normalize(path.resolve(path.join(__dirname, body.newFile)));
84+
const testDataPath = path.normalize(path.resolve(path.join(__dirname, 'test-data')));
85+
86+
if(!newFile.startsWith(testDataPath)){
87+
res.sendStatus(400);
88+
return;
89+
}
90+
91+
await acceptOne(newFile);
92+
res.json({
93+
message: 'Accepted'
94+
});
95+
} catch (e) {
7696
res.json({
7797
message: (e as Error).message,
7898
stack: (e as Error).stack
7999
});
80100
}
81-
})
101+
});
82102

83103
app.listen(options.port, () => {
84104
console.log('Server listening on port ' + options.port);
85105
});
86106

87-
let first = true
107+
let first = true;
88108
return {
89109
name: 'server',
90110
generateBundle() {
91111
if (first) {
92-
first = false
93-
opener(`http://localhost:${options.port}` + options.openPage)
112+
first = false;
113+
opener(`http://localhost:${options.port}` + options.openPage);
94114
}
95115
}
96116
};
97-
}
117+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import path from 'path';
2+
import fs from 'fs';
3+
4+
export async function acceptOne(newFile: string) {
5+
console.log('Accepting ', newFile);
6+
await fs.promises.rename(newFile, newFile.replace('.new.png', '.png'));
7+
8+
const diff = newFile.replace('.new.png', '.diff.png');
9+
if (fs.existsSync(diff)) {
10+
await fs.promises.unlink(diff);
11+
}
12+
console.log('Accepted ', newFile);
13+
}
14+
15+
export async function acceptAll(d: string) {
16+
const dir = await fs.promises.opendir(d);
17+
try {
18+
while (true) {
19+
const entry = await dir.read();
20+
if (!entry) {
21+
break;
22+
} else if (entry.isDirectory() && entry.name !== '.' && entry.name !== '..') {
23+
await acceptAll(path.join(d, entry.name));
24+
} else if (entry.isFile()) {
25+
if (entry.name.endsWith('.new.png')) {
26+
acceptOne(path.join(entry.parentPath, entry.name));
27+
} else if (entry.name.endsWith('.diff.png')) {
28+
fs.promises.unlink(path.join(entry.parentPath, entry.name));
29+
}
30+
}
31+
}
32+
} finally {
33+
await dir.close();
34+
}
35+
}

scripts/accept-new-reference-files.mjs

Lines changed: 0 additions & 32 deletions
This file was deleted.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import url from 'url';
2+
import path from 'path';
3+
import { acceptAll } from './accept-new-reference-files.common';
4+
5+
async function run() {
6+
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
7+
const testDataPath = path.join(__dirname, '..', 'test-data');
8+
await acceptAll(testDataPath);
9+
}
10+
11+
run();

src/DisplaySettings.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,16 @@ export class DisplaySettings {
135135
*/
136136
public effectStaffPaddingBottom: number = 0;
137137

138+
/**
139+
* Gets or sets the left padding applied between the left line and the first glyph in the first staff in a system.
140+
*/
141+
public firstStaffPaddingLeft: number = 6;
142+
143+
/**
144+
* Gets or sets the left padding applied between the left line and the first glyph in the following staff in a system.
145+
*/
146+
public staffPaddingLeft: number = 2;
147+
138148
/**
139149
* Gets how the systems should be layed out.
140150
*/

src/generated/DisplaySettingsJson.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,14 @@ export interface DisplaySettingsJson {
104104
* Gets or sets the bottom padding applied to effect annotation staffs.
105105
*/
106106
effectStaffPaddingBottom?: number;
107+
/**
108+
* Gets or sets the left padding applied between the left line and the first glyph in the first staff in a system.
109+
*/
110+
firstStaffPaddingLeft?: number;
111+
/**
112+
* Gets or sets the left padding applied between the left line and the first glyph in the following staff in a system.
113+
*/
114+
staffPaddingLeft?: number;
107115
/**
108116
* Gets how the systems should be layed out.
109117
*/

src/generated/DisplaySettingsSerializer.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ export class DisplaySettingsSerializer {
4343
o.set("notationstaffpaddingbottom", obj.notationStaffPaddingBottom);
4444
o.set("effectstaffpaddingtop", obj.effectStaffPaddingTop);
4545
o.set("effectstaffpaddingbottom", obj.effectStaffPaddingBottom);
46+
o.set("firststaffpaddingleft", obj.firstStaffPaddingLeft);
47+
o.set("staffpaddingleft", obj.staffPaddingLeft);
4648
o.set("systemslayoutmode", obj.systemsLayoutMode as number);
4749
return o;
4850
}
@@ -111,6 +113,12 @@ export class DisplaySettingsSerializer {
111113
case "effectstaffpaddingbottom":
112114
obj.effectStaffPaddingBottom = v! as number;
113115
return true;
116+
case "firststaffpaddingleft":
117+
obj.firstStaffPaddingLeft = v! as number;
118+
return true;
119+
case "staffpaddingleft":
120+
obj.staffPaddingLeft = v! as number;
121+
return true;
114122
case "systemslayoutmode":
115123
obj.systemsLayoutMode = JsonHelper.parseEnum<SystemsLayoutMode>(v, SystemsLayoutMode)!;
116124
return true;

src/generated/model/RenderStylesheetSerializer.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// </auto-generated>
66
import { RenderStylesheet } from "@src/model/RenderStylesheet";
77
import { JsonHelper } from "@src/io/JsonHelper";
8+
import { BracketExtendMode } from "@src/model/RenderStylesheet";
89
export class RenderStylesheetSerializer {
910
public static fromJson(obj: RenderStylesheet, m: unknown): void {
1011
if (!m) {
@@ -18,13 +19,21 @@ export class RenderStylesheetSerializer {
1819
}
1920
const o = new Map<string, unknown>();
2021
o.set("hidedynamics", obj.hideDynamics);
22+
o.set("bracketextendmode", obj.bracketExtendMode as number);
23+
o.set("usesystemsignseparator", obj.useSystemSignSeparator);
2124
return o;
2225
}
2326
public static setProperty(obj: RenderStylesheet, property: string, v: unknown): boolean {
2427
switch (property) {
2528
case "hidedynamics":
2629
obj.hideDynamics = v! as boolean;
2730
return true;
31+
case "bracketextendmode":
32+
obj.bracketExtendMode = JsonHelper.parseEnum<BracketExtendMode>(v, BracketExtendMode)!;
33+
return true;
34+
case "usesystemsignseparator":
35+
obj.useSystemSignSeparator = v! as boolean;
36+
return true;
2837
}
2938
return false;
3039
}

src/importer/BinaryStylesheet.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { GpBinaryHelpers } from '@src/importer/Gp3To5Importer';
55
import { BendPoint } from '@src/model/BendPoint';
66
import { Bounds } from '@src/rendering/utils/Bounds';
77
import { Color } from '@src/model/Color';
8+
import { BracketExtendMode } from '@src/model/RenderStylesheet';
89

910
enum DataType {
1011
Boolean,
@@ -111,11 +112,17 @@ export class BinaryStylesheet {
111112
}
112113

113114
public apply(score: Score): void {
114-
for(const [key, value] of this.raw) {
115+
for (const [key, value] of this.raw) {
115116
switch (key) {
116117
case 'StandardNotation/hideDynamics':
117118
score.stylesheet.hideDynamics = value as boolean;
118119
break;
120+
case 'System/bracketExtendMode':
121+
score.stylesheet.bracketExtendMode = (value as number) as BracketExtendMode;
122+
break;
123+
case 'Global/useSystemSignSeparator':
124+
score.stylesheet.useSystemSignSeparator = value as boolean;
125+
break;
119126
}
120127
}
121128
}
@@ -126,9 +133,11 @@ export class BinaryStylesheet {
126133

127134
public static writeForScore(score: Score): Uint8Array {
128135
const writer = ByteBuffer.withCapacity(128);
129-
IOHelper.writeInt32BE(writer, 1); // entry count
136+
IOHelper.writeInt32BE(writer, 3); // entry count
130137

131138
BinaryStylesheet.writeBooleanEntry(writer, 'StandardNotation/hideDynamics', score.stylesheet.hideDynamics);
139+
BinaryStylesheet.writeNumberEntry(writer, 'System/bracketExtendMode', score.stylesheet.bracketExtendMode as number);
140+
BinaryStylesheet.writeBooleanEntry(writer, 'Global/useSystemSignSeparator', score.stylesheet.useSystemSignSeparator);
132141

133142
return writer.toArray();
134143
}
@@ -138,4 +147,10 @@ export class BinaryStylesheet {
138147
writer.writeByte(DataType.Boolean as number);
139148
writer.writeByte(value ? 1 : 0);
140149
}
150+
151+
private static writeNumberEntry(writer: ByteBuffer, key: string, value: number) {
152+
GpBinaryHelpers.gpWriteString(writer, key);
153+
writer.writeByte(DataType.Integer as number);
154+
IOHelper.writeInt32BE(writer, value)
155+
}
141156
}

0 commit comments

Comments
 (0)