Skip to content

Support number notation jianpu - #31626

Open
songzhenke wants to merge 34 commits into
musescore:mainfrom
songzhenke:jianpu
Open

songzhenke wants to merge 34 commits into
musescore:mainfrom
songzhenke:jianpu

Conversation

@songzhenke

@songzhenke songzhenke commented Jan 1, 2026 •

Copy link
Copy Markdown

Resolves: #25919

This PR adds Jianpu support. A new Jianpu staff type can be selected to display number notation. No new failures are introduced in existing unit tests.

The implementation follows the guidance in this comment by not introducing new fonts and by reusing existing rendering for lines and dots.

Features added

  • New Jianpu staff type
  • Render Jianpu digits using a dedicated Jianpu font
  • Support chord notes with vertically stacked Jianpu digits
  • Render octave dots above/below digits
  • Render duration lines to the right of digits
  • Use beams for diminution lines
  • Adjust slur rendering for Jianpu
  • Show Jianpu digits above/below the shadow note during note entry
  • Configuration for Jianpu font
  • Configurable size and spacing for octave dots and duration lines
  • Configurable beam placement for Indonesian Not Angka which lines above shorten duration and slur below
  • Unit tests added

Notes

  • The visual test will be submitted in a separate PR 12 which still in forked branch, since upstream main cannot generate reference PNGs for Jianpu.

Snapshots

5-line staff with a linked Jianpu staff
Screenshot_20260101_224505

  • I signed the CLA
  • The title of the PR describes the problem it addresses
  • Each commit's message describes its purpose and effects, and references the issue it resolves
  • If changes are extensive, there is a sequence of easily reviewable commits
  • The code in the PR follows the coding rules
  • There are no unnecessary changes
  • The code compiles and runs on my machine, preferably after each commit individually
  • I created a unit test or vtest to verify the changes I made (if applicable)

@songzhenke
songzhenke force-pushed the jianpu branch 2 times, most recently from 5e4513c to 8c172ff Compare January 2, 2026 01:13
@songzhenke
songzhenke marked this pull request as draft January 2, 2026 01:27
@songzhenke
songzhenke force-pushed the jianpu branch 4 times, most recently from 132d688 to 6034690 Compare January 2, 2026 08:58
@songzhenke
songzhenke marked this pull request as ready for review January 2, 2026 10:20
@songzhenke
songzhenke force-pushed the jianpu branch 3 times, most recently from e4f52e9 to 28182e9 Compare January 4, 2026 02:04
@AndreaHu3299

Copy link
Copy Markdown

Love this work! Can't wait for it to be natively supported in MuseScore 4! Keep up the good work @songzhenke !

@songzhenke

Copy link
Copy Markdown
Author

Love this work! Can't wait for it to be natively supported in MuseScore 4! Keep up the good work @songzhenke !

Thanks @AndreaHu3299 . My pleasure. Once basic features are merged, i will gradually improve jianpu and fix bugs.

@songzhenke

Copy link
Copy Markdown
Author

This is opened for a while, could someone please review when you have time? @Tantacrul @cbjeukendrup

@cbjeukendrup

Copy link
Copy Markdown
Contributor

It has been added to our review queue, but the queue is a bit full at the moment, especially for larger pull requests. But we'll get to it!

@songzhenke
songzhenke force-pushed the jianpu branch 3 times, most recently from bf9cc8b to 8c848b8 Compare January 17, 2026 08:30
@leonchensax

Copy link
Copy Markdown

Hi @songzhenke , thank you so much for your hard work on this Jianpu support! As a saxophone player and blogger, I’ve been testing this PR and would like to share some feedback to help improve it.

First, I found that certain articulations like "Scoop" and "Slide in below" cannot be added or displayed in the Jianpu staff.

Second, it would be great to have options to customize the appearance, such as changing the font and size of the digits, as well as the scale of the octave dots for better readability.

Lastly, there is a critical issue with transposing instruments (e.g., Alto Saxophone, Trumpet): the Jianpu is not currently following the "Movable Do" system relative to the instrument's written key, resulting in incorrect pitch relationships.

I hope these suggestions are helpful for the next steps of development. Looking forward to this feature!

Best regards,
Leon.

@songzhenke

Copy link
Copy Markdown
Author

Thanks @leonchensax for testing.

This PR is just a beginning for Jianpu support, and I’m sure it still needs a lot of improvement. I’ll keep working on it if the current approach is on the right track.

I plan to experiment with things like Scoop, Slide in below, and transposing instruments to see how they should be handled. The articulation code is quite hard to understand.

Custom configuration mainly needs some UI work, so I’ll spend time on that only after the basic features are working.

Anyway, still a long way to go.

@leonchensax

Copy link
Copy Markdown

Thanks @leonchensax for testing.

This PR is just a beginning for Jianpu support, and I’m sure it still needs a lot of improvement. I’ll keep working on it if the current approach is on the right track.

I plan to experiment with things like Scoop, Slide in below, and transposing instruments to see how they should be handled. The articulation code is quite hard to understand.

Custom configuration mainly needs some UI work, so I’ll spend time on that only after the basic features are working.

Anyway, still a long way to go.

Thanks for the amazing work! As a sheet music publisher and wind instrument player, I’m thrilled to see Jianpu support coming to life—it's a huge milestone for my workflow.

I’m fully committed to helping speed this up. Please let me know if there's any way I can support your development, whether through professional testing or by sponsoring your time to expedite the process.

Is there a way we could connect further? I'd love to discuss how we might collaborate more closely to make this a success. (Do you have a Buy Me a Coffee link or a preferred way to chat?)

Looking forward to it!

@songzhenke

Copy link
Copy Markdown
Author

Hi @leonchensax
The scoop and transposing instrument should be fixed in latest PR. Thanks for help from AI as i have 0 knowledge of those. I am not using Buy Me a Coffee link :( . The latest PR also supports multiple notes for jianpu in a chord. Unforturnately it breaks some unit tests. Hope you can play with it. I am going to fix unit test failures later when having time.

@songzhenke
songzhenke force-pushed the jianpu branch 4 times, most recently from 009b015 to 43cf484 Compare February 25, 2026 13:17
@songzhenke

songzhenke commented Feb 26, 2026 •

Copy link
Copy Markdown
Author

The unit test failures are fixed. My next goal:

  • Use existing beam for duration line
  • Add setting for jianpu
  • Add unit test for jianpu

@rchangl

rchangl commented Mar 6, 2026

Copy link
Copy Markdown

Looking forward to it!

@songzhenke

Copy link
Copy Markdown
Author

The current feedback is already keeping me busy enough :). I’m working on the multi-voice layout issue now, which isn’t easy. I still need to address the beam and grace note issues reported above, as well as the octave dot issue in la-based minor reported in fork PR #11.

I’ll need some time to work through these, as I’m also busy with my day job ;)

@Gravifer

Copy link
Copy Markdown
Contributor

Hope you find some subproblem that's worth delegating :D
Definitely happy to pay my two-cents worth of brain into it

@songzhenke

Copy link
Copy Markdown
Author

The issue "3. Octave Dot Spacing" is fixed by PR 11.
There was an issue that voice 1 and 2 are mixed and hard to read. Now the voice 2 will be aligned separatedly under voice 1 with double gaps. Like this:
image

@FreeCodeCampXYG

Copy link
Copy Markdown

Hi! Thanks for fixing the overlap issue between two voices in Jianpu on the same staff — that's great!
However, I noticed that the vertical spacing between the two voices now seems a bit too large (see the attached screenshot). This sometimes causes layout issues, like unnecessary page breaks for multi-page scores. Would it be possible to make this spacing adjustable, so users can fine-tune it to fit their layout needs?
Also, the font in your screenshots looks a bit different from what I'm getting in my tests. Are you using a specific font for Jianpu? If so, could you share which one it is? Thanks!
image

@songzhenke

Copy link
Copy Markdown
Author

I changed default gap a little bit smaller and added a new setting in Format - Style - Jianpu - Voice vertical distance to allow you custom the gap between 2 voices.

For font, you can change jianpu font in Format - Style - Text style - Jianpu number. My snapshot is from Linux, the default font is FreeSans. Maybe Windows has different font?

* add tonic for jianpu

* replace hardcode octave based note C3 by score key

* add jianpu tonic setting to key signature properties instead of score wide style

* show jianpu label 1=C to replace sharp and flat

* default to major when staff mode is unknown or none

* display jianpu accidetal instead of standard note accidental

* fix coding format

* rename setting name in properties

* fix jianpu vertical display for multi voice

* fix jianpu vertical display for muti voice - handle dot and beam

* fix jianpu vertical display for muti voice - use up note

* fix jianpu vertical display for muti voice - handle slur

* fix jianpu octave dot for custom tonic

* add new setting for voice vertical distance

* qml use defined jianpu tonic mode in engraving
@songzhenke

Copy link
Copy Markdown
Author

My forked PR #11 has been merged into this branch. It mainly adds custom tonic settings and multi-voice layout support, and fixes several bugs, including accidentals.

Remaining issues:

  1. Single grace note does not have a duration line underneath because MuseScore doesn't create a beam for a single grace note.
  2. If have 2+ linked Jianpu staves, cannot have different tonic settings for each.
  3. Incorrect beam display in Jianpu. @FreeCodeCampXYG, I haven't been able to reproduce the issue shown in your fourth snapshot. Could you provide detailed steps to reproduce it? Please attach a sample score if needed.

@FreeCodeCampXYG

FreeCodeCampXYG commented Oct 22, 2026 •

Copy link
Copy Markdown
  1. If have 2+ linked Jianpu staves, cannot have different tonic settings for each.

That's a pity! Independent tonic settings for linked Jianpu staves would be extremely useful for polytonal or modulating passages. Is this something that might be considered for a future update?

  1. Incorrect beam display in Jianpu. @FreeCodeCampXYG, I haven't been able to reproduce the issue shown in your fourth snapshot. Could you provide detailed steps to reproduce it? Please attach a sample score if needed.

I'm not entirely sure which snapshot corresponds to the "fourth" one mentioned, so I've attached both score files just to be safe. Hopefully one of them can help reproduce the beam display issue. Please let me know if you need anything else!
But,I'm currently away from my device and can't attach the files right now. I'll upload both score files as soon as I'm back online to help with debugging. Thanks for your patience!

测试样本.zip
小步舞曲.zip

Format - Style - Text style - Jianpu number. My snapshot is from Linux, the default font is FreeSans.

I suspect this might be a cross-platform font rendering difference. You mentioned your snapshot is from Linux with FreeSans, but I'm on Windows and cannot see the exact same rendering on my end.
I have explicitly enabled bold via Format > Style > Text Styles > Jianpu number, and it works as expected on Windows. It's highly likely that the bold weight behaves differently between Windows and Linux (e.g., how FreeSans Bold is resolved), which could explain the discrepancy. I'll attach both score files once I'm back at my device so you can verify the styling settings directly.
image

Maybe is a bug, but it's not Jianpu's bug !

I'm windows 11 Arm

@songzhenke

Copy link
Copy Markdown
Author
  1. If have 2+ linked Jianpu staves, cannot have different tonic settings for each.

That's a pity! Independent tonic settings for linked Jianpu staves would be extremely useful for polytonal or modulating passages. Is this something that might be considered for a future update?

yes. I will look to see if possible.

  1. Incorrect beam display in Jianpu.

It is because you dragged the duration line (beam), then it has custom format. The jianpu layout will leave it as it is. You can reset it by this step:

  1. create a linked staff
  2. delete original staff
  3. save
  4. reopen
  5. the linked staff will show as nomal as the custom formats are dropped by step 2

@songzhenke

Copy link
Copy Markdown
Author

Another easy option is to reset the beam height individually in the Properties panel:
image

@miiizen
miiizen removed the request for review from mike-spa October 23, 2026 11:00
@songzhenke

Copy link
Copy Markdown
Author
  1. If have 2+ linked Jianpu staves, cannot have different tonic settings for each.

That's a pity! Independent tonic settings for linked Jianpu staves would be extremely useful for polytonal or modulating passages. Is this something that might be considered for a future update?

yes. I will look to see if possible.

It is supported now.

There is one special aspect of the UI to be aware of. When you select a key signature, the Properties panel shows the Jianpu settings for all staves. To change the settings for a single staff, click an empty area to deselect everything, then Ctrl+click the key signature on the desired Jianpu staff and adjust its Jianpu numbering settings.

@songzhenke

Copy link
Copy Markdown
Author

In the highlighted passage, the grace note should be an eighth note, shown with a single underline beneath the number. However, the underline is missing in the current output.

  1. Single grace note does not have a duration line underneath because MuseScore doesn't create a beam for a single grace note.

It is fixed. PR is updated.

@songzhenke

Copy link
Copy Markdown
Author

In the highlighted passage, the grace note should be an eighth note, shown with a single underline beneath the number. However, the underline is missing in the current output.

  1. Single grace note does not have a duration line underneath because MuseScore doesn't create a beam for a single grace note.

It is fixed. PR is updated.

Changed further to apply the same fix to standard jianpu notation. When a custom beam break is applied, the duration line underneath a jianpu number may be missing.

@songzhenke

Copy link
Copy Markdown
Author

Incorrect beam display in Jianpu.

It is because you dragged the duration line (beam), then it has custom format. The jianpu layout will leave it as it is. You can reset it by this step:

  1. create a linked staff
  2. delete original staff
  3. save
  4. reopen
  5. the linked staff will show as nomal as the custom formats are dropped by step 2

Another easy option is to reset the beam height individually in the Properties panel

I added a change to prevent incorrect beam rendering. Dragging a duration line (beam) now preserves its Jianpu styling and keeps it horizontal unless you untick Force horizontal in the beam properties.

@songzhenke

Copy link
Copy Markdown
Author

Hi @miiizen @davidstephengrant,

Just wondering if there has been any progress on the code review for this PR.

I noticed that the linked issue #25919 was assigned to you a couple of months ago, but the PR itself hasn't been assigned yet, so I thought I'd check if there might be any updates.

I understand the team has a lot on its plate. I'd really appreciate any update when you have a chance.

Thanks for your time!

@bamb3r

bamb3r commented Oct 30, 2026

Copy link
Copy Markdown

Hello! Thank you so much for all your work on this, we are really excited about adding jianpu to MuseScore Studio 🔥

We discussed this as a team and we think the best approach is to review the PR over the next week or so, and then to merge this in but keep the functionality hidden behind dev tools until after 5.0. This means that it will be accessible through the dev tools menu, but we won't officially support scores containing jianpu for all users until a little later (most likely when we do the 5.1 release) as we need to make sure we test support thoroughly across all aspects of engraving. @miiizen and @mathesoncalum will follow up with their initial reviews shortly - thanks again, we believe this will be a great addition 😀

@Gravifer

Copy link
Copy Markdown
Contributor

Really glad to hear about that! Now there is a roadmap to look forward to :D

@songzhenke

Copy link
Copy Markdown
Author

Thanks @bamb3r. I'm really pleased to hear this, and I completely understand the approach of keeping Jianpu behind Dev Tools initially while allowing more time for thorough testing.

I really appreciate the team's support and look forward to receiving the initial reviews and working through any feedback.

Thanks again! 😀

@miiizen miiizen left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking good! Lots of comments (sorry) but I have no problems at all with the fundamentals of this.

* MuseScore Studio
* Music Composition & Notation
*
* Copyright (C) 2021 MuseScore Limited

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Copyright (C) 2021 MuseScore Limited
* Copyright (C) 2026 MuseScore Limited and others

Likewise for all new files please


Note* note() const;

double len() const { return m_len; }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

len and above are only ever set during layout and cannot be edited by the user, so these values should go in LayoutData. Then, we can also remove spatiumChanged

ChordRest* chordRest() const;
double mag() const;

double len() const { return m_len; }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be moved to LayoutData and spatiumChanged removed.


void DurationLine::spatiumChanged(double oldValue, double newValue)
{
if (oldValue != 0.0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove this whole function, but for future reference use muse::RealIsNull to check doubles are 0.

}

if (item->jianpuNumbering() != JianpuTonicMode::FOLLOW_SCORE_KEY) {
xml.tag("jianpuNumbering", int(item->jianpuNumbering()));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want to avoid serialising enums as ints - please add the necessary functions to TConv so we can read and write in the same way as jianpuTonicMode


auto notes = item->notes();
if (isJianpuStaff) {
std::sort(notes.begin(), notes.end(), [](const Note* n1, const Note* n2) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just reverse the vector here? They should already be sorted lowest to highest.

TLayout::layoutNote(note, ldata);

if (isJianpuStaff) {
std::vector<OctaveDot*> dots = note->octaveDots();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::vector<OctaveDot*> dots = note->octaveDots();
const std::vector<OctaveDot*>& dots = note->octaveDots();

jianpuKeyMapping(ks, mode, tonicTpc);

for (Note* note : item->notes()) {
int dots = 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can move this to below octave and do:

Suggested change
int dots = 0;
int dots = std::abs(octave);

if (!measure) {
return;
}
Fraction tick = measure->ticks();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Fraction tick = measure->ticks();
Fraction tick = measure->tick();

We want position not duration here

}

if (item->isJianpuStaff() && item->isStyled(Pid::BEAM_NO_SLOPE)) {
item->setNoSlope(true);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary? The slope is set to 0 later on in layout2 anyway.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for numbered musical notation (Jianpu)