Feature Extraction
Transformers
Safetensors
sheetsage2
audio
music
music-transcription
midi
abc-notation
custom_code
Instructions to use rAVEUK/SheetSage2 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use rAVEUK/SheetSage2 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("feature-extraction", model="rAVEUK/SheetSage2", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("rAVEUK/SheetSage2", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
File size: 7,203 Bytes
cecd352 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | "use strict";
// These display adaptations leave the saved ABC unchanged.
function expandRests(abc) {
let header = true, voice = null, meter = [4, 4], unit = [1, 8];
const meters = new Map();
return abc.split(/\r?\n/).map(line => {
const field = line.match(/^([A-Za-z]):\s*(.*)$/);
if (field) {
const [, key, value] = field;
if (key === "V") {
voice = value.split(/\s/)[0];
if (!meters.has(voice)) meters.set(voice, meter);
}
if (key === "M") {
const match = value.match(/^(\d+)\/(\d+)$/);
if (match) {
const next = match.slice(1).map(Number);
if (header || !voice) meter = next;
else meters.set(voice, next);
}
}
if (key === "L") unit = value.split("/").map(Number);
if (key === "K") header = false;
return line;
}
if (header || line.startsWith("%")) return line;
return line.replace(/"[^"\n]*"|\[[^\]\n]*\]|Z(\d*)\|/g, (token, count) => {
if (count === undefined) return token;
const [n, d] = meters.get(voice) || meter;
return (`z${n * unit[1] / (d * unit[0])}|`).repeat(Number(count || 1));
});
}).join("\n");
}
function fixSystemKeys(tune) {
for (const line of tune.lines) for (const staff of line.staff || []) {
for (const voice of staff.voices) {
for (let i = 0; i < voice.length && voice[i].el_type !== "note";) {
const event = voice[i];
if (event.el_type === "key" || event.el_type === "keySignature") {
staff.key = {...event, accidentals: event.accidentals.map(a => ({...a}))};
delete staff.key.impliedNaturals;
voice.splice(i, 1);
} else i++;
}
}
}
}
window.renderScore = async abc => {
document.body.innerHTML = '<div id="source"></div><main id="pages"></main>';
const fontStyle = document.createElement("style");
fontStyle.textContent = '#source text, #source span, #pages text {font-family:SheetSageSans !important}';
document.head.append(fontStyle);
const source = document.getElementById("source");
source.style.cssText = "position:absolute;left:-2000px;width:714px";
const tunes = ABCJS.renderAbc(source, expandRests(abc), {
staffwidth: 674, paddingtop: 12, paddingbottom: 12, paddingleft: 20, paddingright: 20,
oneSvgPerLine: true, print: true, add_classes: true,
wrap: {minSpacing: 1.8, maxSpacing: 2.7, preferredMeasuresPerLine: 4},
afterParsing: fixSystemKeys,
});
if (!tunes.length || !tunes.some(t => t.lines.some(l => l.staff?.length)))
throw new Error("ABC contains no music to render.");
const warnings = tunes.flatMap(t => t.warnings || []);
if (warnings.length) throw new Error("Invalid ABC: " + warnings.join("; "));
await document.fonts.ready;
const ns = "http://www.w3.org/2000/svg";
const pages = [];
let page, content, used = 0, systems = 0;
function addPage() {
page = document.createElementNS(ns, "svg");
for (const [k, v] of Object.entries({xmlns:ns, width:794, height:1123, viewBox:"0 0 794 1123"}))
page.setAttribute(k,v);
page.setAttribute("class", "score-page");
const fontStyle = document.createElementNS(ns, "style");
fontStyle.textContent = '@font-face{font-family:SheetSageSans;src:url(data:font/ttf;base64,' + window.renderFontData + ')}text{font-family:SheetSageSans !important}';
page.append(fontStyle);
const license = document.createElementNS(ns, "metadata");
license.textContent = window.renderFontLicense;
page.append(license);
const background = document.createElementNS(ns, "rect");
for (const [k,v] of Object.entries({width:794,height:1123,fill:"white"})) background.setAttribute(k,v);
page.append(background);
content = document.createElementNS(ns, "g");
content.setAttribute("transform", "translate(40 40)");
page.append(content);
document.getElementById("pages").append(page);
pages.push(page);
used = 0;
}
for (const svg of source.querySelectorAll("svg")) {
const box = svg.getBoundingClientRect();
if (!(box.width > 0 && box.height > 0)) continue;
const scale = Math.min(1, 714 / box.width);
const height = box.height * scale;
if (height > 1043) throw new Error("A staff system is taller than one page.");
if (!page || used + height > 1043) addPage();
const group = document.createElementNS(ns, "g");
group.setAttribute("transform", `translate(0 ${used}) scale(${scale})`);
const clone = svg.cloneNode(true);
clone.setAttribute("width",box.width);
clone.setAttribute("height",box.height);
clone.style.overflow = "visible";
group.append(clone);
content.append(group);
used += height;
systems++;
}
source.remove();
if (!pages.length) throw new Error("No score pages were produced.");
return {pages:pages.map(p => new XMLSerializer().serializeToString(p)), systems, warnings};
};
window.renderAudio = async ({tracks, duration}) => {
const context = new AudioContext({sampleRate:44100});
await context.resume();
const sequence = new ABCJS.synth.SynthSequence();
for (const track of tracks) {
const id = sequence.addTrack();
sequence.setInstrument(id, 0);
for (const note of track.notes) sequence.tracks[id].push({
cmd:"note", instrument:0, pitch:note.pitch, volume:note.velocity,
start:note.start, duration:note.end-note.start, gap:0,
});
}
sequence.totalDuration = duration;
const synth = new ABCJS.synth.CreateSynth();
const loaded = await synth.init({audioContext:context, sequence, millisecondsPerMeasure:1000,
options:{soundFontUrl:"https://render.invalid/soundfonts/", fadeLength:35,
programOffsets:{acoustic_grand_piano:0}, soundFontVolumeMultiplier:1}});
if (loaded.error?.length) throw new Error("Could not load piano samples: " + loaded.error.join(", "));
await synth.prime();
const buffer = synth.getAudioBuffer();
if (!buffer) throw new Error("The renderer returned no audio.");
// Simultaneous voices retain their balance; a peak guard avoids PCM clipping.
let peak = 0;
for (let c=0; c<buffer.numberOfChannels; c++) {
const channel = buffer.getChannelData(c);
for (let i=0; i<channel.length; i++) peak = Math.max(peak, Math.abs(channel[i]));
}
const gain = Math.min(0.7, peak > 0 ? 0.98 / peak : 0.7);
window.renderedAudio = {buffer, gain};
await context.close();
return {frames:buffer.length, sample_rate:buffer.sampleRate, channels:buffer.numberOfChannels, gain};
};
window.audioBlock = ({start, count}) => {
const {buffer, gain} = window.renderedAudio;
const frames = Math.min(count, buffer.length-start);
const bytes = new Uint8Array(frames*buffer.numberOfChannels*2);
const view = new DataView(bytes.buffer);
for (let c=0; c<buffer.numberOfChannels; c++) {
const channel = buffer.getChannelData(c);
for (let i=0; i<frames; i++) {
const sample = Math.max(-1,Math.min(1,channel[start+i]*gain));
view.setInt16((i*buffer.numberOfChannels+c)*2, Math.round(sample*32767), true);
}
}
let binary="";
for (let offset=0; offset<bytes.length; offset+=8192)
binary += String.fromCharCode(...bytes.subarray(offset,offset+8192));
return btoa(binary);
};
|