rendering abcjs music notation in tiddlywiki

726 views
Skip to first unread message

vpl

unread,
Dec 4, 2015, 4:10:11 AM12/4/15
to TiddlyWiki
Hi,

I'm trying to render abcjs music notation in tiddlywiki
Bopland.org is closed now and Vexflow licensing model is not adapted.
abcjs (http://abcjs.net/) looks very interesting and maintained.

Looking at other thread I understand that 
 - I have to create a tiddler containing the abcjs_basic_latest-min.js content (available here https://raw.githubusercontent.com/paulrosen/abcjs/master/bin/abcjs_basic_2.2-min.js)
 - tag it with systemConfig

Then I block as I don't understand how to render the music content using abcjs

I've tested on a html page the following code and it works
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>abcjs basic demo</title>
<script src="abcjs_basic_latest-min.js" type="text/javascript"></script>
</head>
<body>
<h1>abcjs basic demo page</h1>
<div id="notation"></div>

<script type="text/javascript">
var chorus = '%%staffwidth 500\nX: 1\nT: Chorus\nV: T1 clef=treble name="Soprano"\nV: T2 clef=treble name="Alto"\nV: B1 clef=bass name="Tenor"\nV: B2 clef=bass name="Bass"\nL:1/8\nK:G\nP:First Part\n[V: T1]"C"ed"Am"ed "F"cd"G7"gf |\n[V: T2]GGAA- A2BB |\n[V: B1]C3D- DF,3 |\n[V: B2]C,2A,,2 F,,2G,,2 |';
</script>

<div>
<script type="text/javascript">
ABCJS.renderAbc('notation', chorus);
</script>
</div>

</body>
</html>

As you see, abcjs renders the content using ABCJS.renderAbc(). 
But we have to pass to this method a string content (in our case a javascript variable) representing the music I want to render.


Could somebody help me here, 
I'm block on tiddly and need an expert to unlock me ..

With regards

Vpl

Jed Carty

unread,
Dec 4, 2015, 5:10:53 AM12/4/15
to TiddlyWiki
If you are willing to switch to tiddlywiki5 than it shouldn't be too hard. If you need/want to stick with tiddlywiki classic than hopefully someone else can help can help.

vpl

unread,
Dec 4, 2015, 5:32:58 AM12/4/15
to TiddlyWiki
Hi

I'm already on tiddlywiki5 for 1 year now and very happy with it !

How can I do that with TW5 ?

Thanks very much for your guidance

Vpl

Jed Carty

unread,
Dec 4, 2015, 6:00:19 AM12/4/15
to TiddlyWiki
I need to run off to work sometime soon, so I can't give a detailed answer now, but the quick answer is you put either the text of the full script of <script src="abcjs_basic_latest-min.js" type="text/javascript"></script> into a tiddler and tag that tiddler with $:/tags/RawMarkup to add the script to the wiki, then the best way would probably be to make a javascript macro (or widget, but since the music probably won't change too often a macro should be enough).

This is the simplest javascript macro example I can think of off the top of my head http://inmysocks.tiddlyspot.com/#%24%3A%2Finmysocks%2Fmacros%2Fadd-time.js
and this is how I put the snap.js library into a wiki http://ooktech.com/jed/ExampleWikis/SnapSVG/#%24%3A%2Fplugins%2Finmysocks%2FSnapJS%2FSnap.js

If you need more let me know, but I probably won't be able to help much until sunday.

BJ

unread,
Dec 4, 2015, 1:29:57 PM12/4/15
to TiddlyWiki
Hi vpl,
I have put a widget together that could be used as a starting point:

http://abcmusic.tiddlyspot.com/

view it in ff (chrome won't load the lib from github)

Feel free to use this if you want to develop abc as a plugin, if you don't then maybe I will push it forward a bit more.

cheers
BJ

vpl

unread,
Dec 6, 2015, 12:16:08 AM12/6/15
to TiddlyWiki
Hi BJ,

This is exactly what I was looking for.
How did you do that ?
On my side I was blocked at the following stage 
I'm not a plugin expert and much more confortable at the moment with the macro option (at least I can make running a small one..)
It seems that you developed a plugin to solve that ?
Will appreciate any description as I need to use this capabilities now and would like to understand how it is integrated with tiddlyWiki

Regards


--------------------------------------------------------------------------------------------
What I've done
- copy the abcjs_basic_latest-min.js file in the same directory as my tiddlywiki
- created a "abcjs_basic_latest-min.js" tiddler, tagged with $:/tags/RawMarkup and containing
<script src="abcjs_basic_latest-min.js" type="text/javascript"></script>
- created a tiddly called "$:/inmysocks/macros/render-abc.js" 
   - of type application/javascript 
   - with an attribute module-type called macro
   - containing
/*
Run the macro
*/
exports.run = function(music) {
//Make each date object.
var result;
result = ABCJS.renderAbc('notation', music);

//result = 'ABC';
return result;

- created a test-abc tiddler containing
<<render-abc "%%staffwidth 500\nX: 1\nT: Chorus\nV: T1 clef=treble name="Soprano"\nV: T2 clef=treble name="Alto"\nV: B1 clef=bass name="Tenor"\nV: B2 clef=bass name="Bass"\nL:1/8\nK:G\nP:First Part\n[V: T1]"C"ed"Am"ed "F"cd"G7"gf |\n[V: T2]GGAA- A2BB |\n[V: B1]C3D- DF,3 |\n[V: B2]C,2A,,2 F,,2G,,2 |">>

- the macro is running in the sense that when I comment the result = ABCJS.renderAbc ... and uncomment the result = 'ABC' I get the ABC display
- But when I do the reverse I don't have anything displayed.

The Dev tools does nott give me any error ...

I've also tried to copy paste the full content of abcjs_basic_latest-min.js file into bcjs_basic_latest-min.js tiddler. 
  In this case, when I close and re-open tiddlyWiki I get the content of the .js displayed just below the getting-start tiddler ...

-----------------------------------------------

vpl

unread,
Dec 6, 2015, 3:29:33 AM12/6/15
to TiddlyWiki
Hi BJ,

I was able to make it running based on your contribution. THanks a lot !
The issue I see here is that the rendering size is not reduced according to the window size (when I reduce the tiddly size).
FOr example
When we display the tt1 of your example and reduce the browser windows, below a certain size the music sheet is not reduced correctly.
Where does it come from ?

Regards

BJ

unread,
Dec 6, 2015, 4:17:19 AM12/6/15
to TiddlyWiki
I am not sure what you are referring to, if its the width of the music image then this is controlled by (eg)

%%staffwidth 500

vpl

unread,
Dec 6, 2015, 5:12:46 AM12/6/15
to TiddlyWiki

Hi,


Look at the below example.

The music sheet size is exeeding the tiddler normal frame


VIncent



BJ

unread,
Dec 6, 2015, 6:47:49 AM12/6/15
to TiddlyWiki
The music is an svg image with a fixed width determined by  %%staffwidth (if used) within the abc notation, If the staffwidth is set greater than the width of the tiddler then it will overflow the tiddler. (actually overflow the containing html element)

I have no idea how it chooses a default width, maybe it is in the abc documentation?

You could also have on the github of abc - do a search of the issues... ,maybe there is some css that can be set?

vpl

unread,
Dec 6, 2015, 7:03:57 PM12/6/15
to TiddlyWiki
I've found in the documentation that a default width of the music is set to 740 pixels.
Search for Basic abcjs


I've found in your widget how you invoke the renderAbc
ABCJS.renderAbc(this.pNode, this.tid);
Is there a way to retrieve the current tiddler size from the widget code such as I could pass it to the rederAbc ?

But will it solve the issue as I guess that tiddly will not invoke the widget each time the tiddler size is changed, won't it ?

Vpl

BJ

unread,
Dec 7, 2015, 4:28:21 AM12/7/15
to tiddl...@googlegroups.com
you could use this as a starting point:

	this.parentDomNode = parent;
var width = parent.clientWidth*2/3;
	this.computeAttributes();
	this.execute();
	this.pNode = this.document.createElement("div");
	parent.insertBefore(this.pNode,nextSibling);
	if (this.source) {
		this.tid  = $tw.wiki.getTiddlerText(this.source)
		ABCJS.renderAbc(this.pNode, "%%staffwidth "+width+"\n"+this.tid);


to make it reactive to the resize there's this event:

object.addEventListener("resize", myScript);

vpl

unread,
Dec 7, 2015, 3:49:40 PM12/7/15
to TiddlyWiki
Hi,.

Thanks very much

I've updated the javascript.
No need to say that I'm blocking on the addEventListener

Here is the code I've updated which generates an internal error when I open the tiddly

Here is what I did
  • Created 2 variables (widgetParent, widgetNextSib) to save the parameters passed to the render fct
  • Created a myScript fct which does what you have coded in the render but using the (widgetParent, widgetNextSib) variables
  • Added the listener and invoking the MyScript
No need to say that I'm a dummy tiddly développer ...

Thanks for your help
Vpl

\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

var Widget = require("$:/core/modules/widgets/widget.js").widget;

var ABCWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
};

// vpl variables
var widgetParent;
var widgetNextSib;

/*
Inherit from the base widget class
*/
ABCWidget.prototype = new Widget();

/*
Render this widget into the DOM
*/
ABCWidget.prototype.render = function(parent,nextSibling) {
       // vpl
       widgetParent = parent;
       widgetNextSib = nextSibling;

this.parentDomNode = parent;
        var width = parent.clientWidth*2/3;
this.computeAttributes();
this.execute();
this.pNode = this.document.createElement("div");
parent.insertBefore(this.pNode,nextSibling);
if (this.source) {
this.tid  = $tw.wiki.getTiddlerText(this.source)
ABCJS.renderAbc(this.pNode, "%%staffwidth "+width+"\n"+this.tid);
}
this.domNodes.push(this.pNode);
};

/*
Compute the internal state of the widget
*/
ABCWidget.prototype.execute = function() {
this.source = this.getAttribute("source");
};

/*
Refresh the widget by ensuring our attributes are up to date
*/
ABCWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes["source"]||changedTiddlers[this.source]) {
this.refreshSelf();
return true;
}
return false;
};

exports["abc"] = ABCWidget;

var myScript = function() {
this.parentDomNode = widgetParent;
        var width = parent.clientWidth*2/3;
this.computeAttributes();
this.execute();
this.pNode = this.document.createElement("div");
parent.insertBefore(this.pNode,widgetNextSib);
if (this.source) {
this.tid  = $tw.wiki.getTiddlerText(this.source)
ABCJS.renderAbc(this.pNode, this.tid);
}
this.domNodes.push(this.pNode);


};

ABCWidget.prototype.addEventListener("resize", myScript);

})();

Tobias Beer

unread,
Dec 7, 2015, 4:53:30 PM12/7/15
to tiddl...@googlegroups.com
Hi vpl,

Not sure, but can't you simply use:

ABCWidget.prototype.addEventListener("resize", this.refreshSelf());

? ...instead of any of your variables / scriptiness?

Best wishes,

Tobias.

BJ

unread,
Dec 7, 2015, 6:00:22 PM12/7/15
to tiddl...@googlegroups.com
I think that the code should  be

ABCWidget.prototype.render = function(parent,nextSibling) {
    var self  = this;
    this.parentDomNode = parent;

    this.computeAttributes();
    this.execute();
    this.pNode = this.document.createElement("div");
    parent.insertBefore(this.pNode,nextSibling);
    if (this.source) {
        this.tid  = $tw.wiki.getTiddlerText(this.source)
        ABCJS.renderAbc(this.pNode, this.tid);
        var width = parent.clientWidth*2/3;
        this.parentwidth = parent.clientWidth;

        ABCJS.renderAbc(this.pNode, "%%staffwidth "+width+"\n"+this.tid);
    }
    this.domNodes.push(this.pNode);
    self.parentDomNode.addEventListener("resize",function (event) {
        if (self.parentwidth != self.parentDomNode.clientWidth) {
            var width = parent.clientWidth*2/3;
            self.parentwidth = parent.clientWidth;
            ABCJS.renderAbc(self.pNode, "%%staffwidth "+width+"\n"+self.tid);
        }
        return true;
    },false)
};

but it does not work on ff 42 - probably a browser bug
Message has been deleted

Sean Boyle

unread,
Feb 14, 2016, 12:35:45 AM2/14/16
to TiddlyWiki
Did this end up in something easily usable?  It would be great if it were bundled up as a plugin.

BJ

unread,
Feb 16, 2016, 3:11:25 AM2/16/16
to TiddlyWiki
Hi Sean,
The basic display seemed to work, so it should not be a lot of work for someone to release the code as a plugin.

@vpl are you planning on developing/releasing a abc plugin?

all the best
BJ
Reply all
Reply to author
Forward
0 new messages