2 (c) 2004: Jelmer Vernooij <jelmer@samba.org>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 //#include <sys/time.h>
25 #include <libxml/xmlmemory.h>
26 #include <libxml/parser.h>
30 # include <libxslt/xslt.h>
31 # include <libxslt/transform.h>
34 #define SMART_ADD_CHILD_STRING(parent, name, contents) xmlNewTextChild(parent, NULL, name, contents)
35 #define SMART_ADD_CHILD_INT(parent, name, contents) { \
37 xmlNodePtr tmp = xmlNewNode(NULL, name); \
38 g_snprintf(tmpc, 100, "%d", contents); \
39 xmlNodeSetContent(tmp, tmpc); \
40 xmlAddChild(parent, tmp); \
43 #define SMART_ADD_CHILD_XINT(parent, name, contents) { \
45 xmlNodePtr tmp = xmlNewNode(NULL, name); \
46 g_snprintf(tmpc, 100, "%x", contents); \
47 xmlNodeSetContent(tmp, tmpc); \
48 xmlAddChild(parent, tmp); \
51 xmlNodePtr xml_write_font(const char *name, struct ptb_font *font)
53 xmlNodePtr xfont = xmlNewNode(NULL, name);
55 g_snprintf(tmp, 100, "%d", font->size); xmlSetProp(xfont, "size", tmp);
56 g_snprintf(tmp, 100, "%d", font->thickness); xmlSetProp(xfont, "thickness", tmp);
57 g_snprintf(tmp, 100, "%d", font->underlined); xmlSetProp(xfont, "underlined", tmp);
58 g_snprintf(tmp, 100, "%d", font->italic); xmlSetProp(xfont, "italic", tmp);
59 xmlSetProp(xfont, "family", font->family);
63 xmlNodePtr xml_write_directions(GList *directions)
65 xmlNodePtr xdirections = xmlNewNode(NULL, "directions");
66 GList *gl = directions;
69 struct ptb_direction *direction = gl->data;
70 xmlNodePtr xdirection = xmlNewNode(NULL, "direction");
71 xmlAddChild(xdirections, xdirection);
78 xmlNodePtr xml_write_rhythmslashes(GList *rhythmslashs)
80 xmlNodePtr xrhythmslashs = xmlNewNode(NULL, "rhythmslashs");
81 GList *gl = rhythmslashs;
84 struct ptb_rhythmslash *rhythmslash = gl->data;
85 xmlNodePtr xrhythmslash = xmlNewNode(NULL, "rhythmslash");
86 xmlAddChild(xrhythmslashs, xrhythmslash);
87 SMART_ADD_CHILD_INT(xrhythmslash, "properties", rhythmslash->properties);
88 SMART_ADD_CHILD_INT(xrhythmslash, "offset", rhythmslash->offset);
89 SMART_ADD_CHILD_INT(xrhythmslash, "dotted", rhythmslash->dotted);
90 SMART_ADD_CHILD_INT(xrhythmslash, "length", rhythmslash->length);
98 xmlNodePtr xml_write_chordtexts(GList *chordtexts)
100 xmlNodePtr xchordtexts = xmlNewNode(NULL, "chordtexts");
101 GList *gl = chordtexts;
104 struct ptb_chordtext *chordtext = gl->data;
105 xmlNodePtr xchordtext = xmlNewNode(NULL, "chordtext");
106 xmlAddChild(xchordtexts, xchordtext);
108 SMART_ADD_CHILD_STRING(xchordtext, "note1", ptb_get_tone(chordtext->name[0]));
109 SMART_ADD_CHILD_STRING(xchordtext, "note2", ptb_get_tone(chordtext->name[1]));
110 SMART_ADD_CHILD_INT(xchordtext, "offset", chordtext->offset);
111 SMART_ADD_CHILD_INT(xchordtext, "additions", chordtext->additions);
112 SMART_ADD_CHILD_INT(xchordtext, "alterations", chordtext->alterations);
113 SMART_ADD_CHILD_INT(xchordtext, "properties", chordtext->properties);
114 SMART_ADD_CHILD_INT(xchordtext, "VII", chordtext->VII);
121 xmlNodePtr xml_write_musicbars(GList *musicbars)
123 xmlNodePtr xmusicbars = xmlNewNode(NULL, "musicbars");
124 GList *gl = musicbars;
127 struct ptb_musicbar *musicbar = gl->data;
128 xmlNodePtr xmusicbar = SMART_ADD_CHILD_STRING(xmusicbars, "musicbar", musicbar->description);
130 if(musicbar->letter != 0x7f) {
132 g_snprintf(tmp, 100, "%c", musicbar->letter);
133 xmlSetProp(xmusicbar, "letter", tmp);
141 xmlNodePtr xml_write_linedatas(GList *linedatas)
143 xmlNodePtr xlinedatas = xmlNewNode(NULL, "linedatas");
144 GList *gl = linedatas;
147 struct ptb_linedata *linedata = gl->data;
148 xmlNodePtr xlinedata = xmlNewNode(NULL, "linedata");
149 xmlAddChild(xlinedatas, xlinedata);
151 SMART_ADD_CHILD_INT(xlinedata, "string", linedata->detailed.string);
152 SMART_ADD_CHILD_INT(xlinedata, "fret", linedata->detailed.fret);
153 SMART_ADD_CHILD_INT(xlinedata, "properties", linedata->properties);
154 SMART_ADD_CHILD_INT(xlinedata, "transcribe", linedata->transcribe);
155 SMART_ADD_CHILD_INT(xlinedata, "conn_to_next", linedata->conn_to_next);
162 xmlNodePtr xml_write_positions(GList *positions)
164 xmlNodePtr xpositions = xmlNewNode(NULL, "positions");
165 GList *gl = positions;
168 struct ptb_position *position = gl->data;
169 xmlNodePtr xposition = xmlNewNode(NULL, "position");
170 xmlAddChild(xpositions, xposition);
172 SMART_ADD_CHILD_INT(xposition, "offset", position->offset);
173 SMART_ADD_CHILD_INT(xposition, "dots", position->dots);
174 SMART_ADD_CHILD_INT(xposition, "length", position->length);
175 SMART_ADD_CHILD_INT(xposition, "properties", position->properties);
176 SMART_ADD_CHILD_INT(xposition, "fermenta", position->fermenta);
178 xmlAddChild(xposition, xml_write_linedatas(position->linedatas));
185 xmlNodePtr xml_write_staffs(GList *staffs)
187 xmlNodePtr xstaffs = xmlNewNode(NULL, "staffs");
192 struct ptb_staff *staff = gl->data;
193 xmlNodePtr xstaff = xmlNewNode(NULL, "staff");
194 xmlAddChild(xstaffs, xstaff);
196 SMART_ADD_CHILD_INT(xstaff, "highest_note", staff->highest_note);
197 SMART_ADD_CHILD_INT(xstaff, "lowest_note", staff->lowest_note);
198 SMART_ADD_CHILD_INT(xstaff, "properties", staff->properties);
200 for(i = 0; i < 2; i++)
201 xmlAddChild(xstaff, xml_write_positions(staff->positions[i]));
202 xmlAddChild(xstaff, xml_write_musicbars(staff->musicbars));
209 xmlNodePtr xml_write_sections(GList *sections)
211 xmlNodePtr sctns = xmlNewNode(NULL, "sections");
212 GList *gl = sections;
215 struct ptb_section *section = gl->data;
216 xmlNodePtr meter_type;
217 xmlNodePtr xsection = xmlNewNode(NULL, "section");
219 xmlAddChild(sctns, xsection);
221 if(section->letter != 0x7f) {
223 g_snprintf(tmp, 100, "%c", section->letter);
224 xmlSetProp(xsection, "letter", tmp);
227 switch(section->end_mark) {
228 case END_MARK_TYPE_NORMAL:
229 SMART_ADD_CHILD_STRING(xsection, "end-mark", "normal");
231 case END_MARK_TYPE_REPEAT:
232 SMART_ADD_CHILD_STRING(xsection, "end-mark", "repeat");
236 meter_type = xmlNewNode(NULL, "meter-type");
237 xmlAddChild(xsection, meter_type);
239 if(section->meter_type & METER_TYPE_BEAM_2) SMART_ADD_CHILD_STRING(meter_type, "beam_2", "");
240 if(section->meter_type & METER_TYPE_BEAM_3) SMART_ADD_CHILD_STRING(meter_type, "beam_3", "");
241 if(section->meter_type & METER_TYPE_BEAM_4) SMART_ADD_CHILD_STRING(meter_type, "beam_4", "");
242 if(section->meter_type & METER_TYPE_BEAM_5) SMART_ADD_CHILD_STRING(meter_type, "beam_5", "");
243 if(section->meter_type & METER_TYPE_BEAM_6) SMART_ADD_CHILD_STRING(meter_type, "beam_6", "");
244 if(section->meter_type & METER_TYPE_COMMON) SMART_ADD_CHILD_STRING(meter_type, "common", "");
245 if(section->meter_type & METER_TYPE_CUT) SMART_ADD_CHILD_STRING(meter_type, "cut", "");
246 if(section->meter_type & METER_TYPE_SHOW) SMART_ADD_CHILD_STRING(meter_type, "show", "");
248 SMART_ADD_CHILD_INT(xsection, "beat", section->detailed.beat);
249 SMART_ADD_CHILD_INT(xsection, "beat-value", section->detailed.beat_value);
250 SMART_ADD_CHILD_INT(xsection, "metronome-pulses-per-measure", section->metronome_pulses_per_measure);
251 SMART_ADD_CHILD_INT(xsection, "properties", section->properties);
252 SMART_ADD_CHILD_INT(xsection, "key-extra", section->key_extra);
253 SMART_ADD_CHILD_INT(xsection, "position-width", section->position_width);
254 SMART_ADD_CHILD_STRING(xsection, "description", section->description);
256 xmlAddChild(xsection, xml_write_chordtexts(section->chordtexts));
257 xmlAddChild(xsection, xml_write_rhythmslashes(section->rhythmslashes));
258 xmlAddChild(xsection, xml_write_directions(section->directions));
259 xmlAddChild(xsection, xml_write_staffs(section->staffs));
267 xmlNodePtr xml_write_guitars(GList *guitars)
269 xmlNodePtr gtrs = xmlNewNode(NULL, "guitars");
275 struct ptb_guitar *gtr = gl->data;
276 xmlNodePtr xgtr = xmlNewNode(NULL, "guitar");
278 xmlAddChild(gtrs, xgtr);
280 g_snprintf(tmp, 100, "%d", gtr->index);
281 xmlSetProp(xgtr, "id", tmp);
283 strings = xmlNewNode(NULL, "strings");
284 xmlAddChild(xgtr, strings);
286 for(i = 0; i < gtr->nr_strings; i++) {
287 SMART_ADD_CHILD_INT(strings, "string", gtr->strings[i]);
290 SMART_ADD_CHILD_STRING(xgtr, "title", gtr->title);
291 SMART_ADD_CHILD_STRING(xgtr, "type", gtr->type);
292 SMART_ADD_CHILD_INT(xgtr, "reverb", gtr->reverb);
293 SMART_ADD_CHILD_INT(xgtr, "chorus", gtr->chorus);
294 SMART_ADD_CHILD_INT(xgtr, "tremolo", gtr->tremolo);
295 SMART_ADD_CHILD_INT(xgtr, "pan", gtr->pan);
296 SMART_ADD_CHILD_INT(xgtr, "capo", gtr->capo);
297 SMART_ADD_CHILD_INT(xgtr, "initial_volume", gtr->initial_volume);
298 SMART_ADD_CHILD_INT(xgtr, "midi_instrument", gtr->midi_instrument);
299 SMART_ADD_CHILD_INT(xgtr, "half_up", gtr->half_up);
300 SMART_ADD_CHILD_INT(xgtr, "simulate", gtr->simulate);
308 xmlNodePtr xml_write_guitarins(GList *guitarins)
310 GList *gl = guitarins;
311 xmlNodePtr xguitarins = xmlNewNode(NULL, "guitarins");
314 struct ptb_guitarin *guitarin = gl->data;
315 xmlNodePtr xguitarin = xmlNewNode(NULL, "guitarin");
316 xmlAddChild(xguitarins, xguitarin);
318 SMART_ADD_CHILD_INT(xguitarin, "offset", guitarin->offset);
319 SMART_ADD_CHILD_INT(xguitarin, "section", guitarin->section);
320 SMART_ADD_CHILD_INT(xguitarin, "staff", guitarin->staff);
321 SMART_ADD_CHILD_INT(xguitarin, "rhythm_slash", guitarin->rhythm_slash);
322 SMART_ADD_CHILD_INT(xguitarin, "staff_in", guitarin->staff_in);
330 xmlNodePtr xml_write_tempomarkers(GList *tempomarkers)
332 GList *gl = tempomarkers;
333 xmlNodePtr xtempomarkers = xmlNewNode(NULL, "tempomarkers");
336 struct ptb_tempomarker *tempomarker = gl->data;
337 xmlNodePtr xtempomarker = SMART_ADD_CHILD_STRING(xtempomarkers, "tempomarker", tempomarker->description);
339 SMART_ADD_CHILD_INT(xtempomarker, "type", tempomarker->type);
340 SMART_ADD_CHILD_INT(xtempomarker, "section", tempomarker->section);
341 SMART_ADD_CHILD_INT(xtempomarker, "offset", tempomarker->offset);
342 SMART_ADD_CHILD_INT(xtempomarker, "bpm", tempomarker->bpm);
347 return xtempomarkers;
350 xmlNodePtr xml_write_dynamics(GList *dynamics)
352 GList *gl = dynamics;
353 xmlNodePtr xdynamics = xmlNewNode(NULL, "dynamics");
356 struct ptb_dynamic *dynamic = gl->data;
357 xmlNodePtr xdynamic = xmlNewNode(NULL, "dynamic");
358 xmlAddChild(xdynamics, xdynamic);
360 SMART_ADD_CHILD_INT(xdynamic, "offset", dynamic->offset);
368 xmlNodePtr xml_write_chorddiagrams(GList *chorddiagrams)
370 GList *gl = chorddiagrams;
371 xmlNodePtr xchorddiagrams = xmlNewNode(NULL, "chorddiagrams");
374 struct ptb_chorddiagram *chorddiagram = gl->data;
376 xmlNodePtr xchorddiagram = xmlNewNode(NULL, "chorddiagram");
377 xmlNodePtr strings = xmlNewNode(NULL, "strings");
378 xmlAddChild(xchorddiagrams, xchorddiagram);
379 xmlAddChild(xchorddiagram, strings);
381 SMART_ADD_CHILD_STRING(xchorddiagram, "note1", ptb_get_tone(chorddiagram->name[0]));
382 SMART_ADD_CHILD_STRING(xchorddiagram, "note2", ptb_get_tone(chorddiagram->name[1]));
383 SMART_ADD_CHILD_INT(xchorddiagram, "frets", chorddiagram->frets);
384 SMART_ADD_CHILD_INT(xchorddiagram, "type", chorddiagram->type);
386 for(i = 0; i < chorddiagram->nr_strings; i++) {
387 SMART_ADD_CHILD_INT(strings, "string", chorddiagram->tones[i]);
393 return xchorddiagrams;
396 xmlNodePtr xml_write_sectionsymbols(GList *sectionsymbols)
398 GList *gl = sectionsymbols;
399 xmlNodePtr xsectionsymbols = xmlNewNode(NULL, "sectionsymbols");
402 struct ptb_sectionsymbol *sectionsymbol = gl->data;
403 xmlNodePtr xsectionsymbol = xmlNewNode(NULL, "sectionsymbol");
404 xmlAddChild(xsectionsymbols, xsectionsymbol);
406 SMART_ADD_CHILD_INT(xsectionsymbol, "repeat-ending", sectionsymbol->repeat_ending);
411 return xsectionsymbols;
414 xmlNodePtr xml_write_floatingtexts(GList *floatingtexts)
416 GList *gl = floatingtexts;
417 xmlNodePtr xfloatingtexts = xmlNewNode(NULL, "floatingtexts");
420 struct ptb_floatingtext *floatingtext = gl->data;
421 xmlNodePtr xfloatingtext = SMART_ADD_CHILD_STRING(xfloatingtexts, "floatingtext", floatingtext->text);
423 SMART_ADD_CHILD_INT(xfloatingtext, "beginpos", floatingtext->beginpos);
425 switch(floatingtext->alignment) {
427 SMART_ADD_CHILD_STRING(xfloatingtext, "alignment", "left");
430 SMART_ADD_CHILD_STRING(xfloatingtext, "alignment", "right");
433 SMART_ADD_CHILD_STRING(xfloatingtext, "alignment", "center");
437 xmlAddChild(xfloatingtext, xml_write_font("font", &floatingtext->font));
442 return xfloatingtexts;
445 xmlNodePtr xml_write_instrument(struct ptbf *bf, int i)
448 xmlNodePtr instrument = xmlNewNode(NULL, "instrument");
449 g_snprintf(tmp, 100, "%d", i);
450 xmlSetProp(instrument, "id", tmp);
452 xmlAddChild(instrument, xml_write_guitars(bf->instrument[i].guitars));
453 xmlAddChild(instrument, xml_write_sections(bf->instrument[i].sections));
454 xmlAddChild(instrument, xml_write_guitarins(bf->instrument[i].guitarins));
455 xmlAddChild(instrument, xml_write_chorddiagrams(bf->instrument[i].chorddiagrams));
456 xmlAddChild(instrument, xml_write_tempomarkers(bf->instrument[i].tempomarkers));
457 xmlAddChild(instrument, xml_write_dynamics(bf->instrument[i].dynamics));
458 xmlAddChild(instrument, xml_write_floatingtexts(bf->instrument[i].floatingtexts));
459 xmlAddChild(instrument, xml_write_sectionsymbols(bf->instrument[i].sectionsymbols));
463 xmlNodePtr xml_write_song_header(struct ptb_hdr *hdr)
465 xmlNodePtr song = xmlNewNode(NULL, "song");
467 SMART_ADD_CHILD_STRING(song, "title", hdr->class_info.song.title);
468 SMART_ADD_CHILD_STRING(song, "artist", hdr->class_info.song.artist);
469 SMART_ADD_CHILD_STRING(song, "words-by", hdr->class_info.song.words_by);
470 SMART_ADD_CHILD_STRING(song, "music-by", hdr->class_info.song.music_by);
471 SMART_ADD_CHILD_STRING(song, "arranged-by", hdr->class_info.song.arranged_by);
472 SMART_ADD_CHILD_STRING(song, "guitar-transcribed-by", hdr->class_info.song.guitar_transcribed_by);
473 SMART_ADD_CHILD_STRING(song, "bass-transcribed-by", hdr->class_info.song.bass_transcribed_by);
474 SMART_ADD_CHILD_STRING(song, "lyrics", hdr->class_info.song.lyrics);
475 SMART_ADD_CHILD_STRING(song, "copyright", hdr->class_info.song.copyright);
477 /* FIXME: Sub stuff */
482 xmlNodePtr xml_write_lesson_header(struct ptb_hdr *hdr)
484 xmlNodePtr lesson = xmlNewNode(NULL, "lesson");
486 SMART_ADD_CHILD_STRING(lesson, "title", hdr->class_info.lesson.title);
487 SMART_ADD_CHILD_STRING(lesson, "artist", hdr->class_info.lesson.artist);
488 SMART_ADD_CHILD_STRING(lesson, "author", hdr->class_info.lesson.author);
489 SMART_ADD_CHILD_STRING(lesson, "copyright", hdr->class_info.lesson.copyright);
491 switch(hdr->class_info.lesson.level) {
492 case LEVEL_BEGINNER: xmlSetProp(lesson, "level", "beginner"); break;
493 case LEVEL_INTERMEDIATE: xmlSetProp(lesson, "level", "intermediate"); break;
494 case LEVEL_ADVANCED: xmlSetProp(lesson, "level", "advanced"); break;
502 xmlNodePtr xml_write_header(struct ptb_hdr *hdr)
504 xmlNodePtr header = xmlNewNode(NULL, "header");
505 switch(hdr->classification) {
506 case CLASSIFICATION_SONG:
507 xmlSetProp(header, "classification", "song");
508 xmlAddChild(header, xml_write_song_header(hdr));
510 case CLASSIFICATION_LESSON:
511 xmlSetProp(header, "classification", "lesson");
512 xmlAddChild(header, xml_write_lesson_header(hdr));
518 int main(int argc, const char **argv)
522 xmlNodePtr root_node;
526 int c, i, musicxml = 0;
528 const char *input = NULL;
532 int format_output = 0;
533 struct poptOption options[] = {
535 {"debug", 'd', POPT_ARG_NONE, &debugging, 0, "Turn on debugging output" },
536 {"outputfile", 'o', POPT_ARG_STRING, &output, 0, "Write to specified file", "FILE" },
537 {"musicxml", 'm', POPT_ARG_NONE, &musicxml, 'm', "Output MusicXML" },
538 {"format", 'f', POPT_ARG_NONE, &format_output, 1, "Format output" },
539 {"quiet", 'q', POPT_ARG_NONE, &quiet, 1, "Be quiet (no output to stderr)" },
540 {"version", 'v', POPT_ARG_NONE, &version, 'v', "Show version information" },
544 pc = poptGetContext(argv[0], argc, argv, options, 0);
545 poptSetOtherOptionHelp(pc, "file.ptb");
546 while((c = poptGetNextOpt(pc)) >= 0) {
549 printf("ptb2ascii Version "PTB_VERSION"\n");
550 printf("(C) 2004 Jelmer Vernooij <jelmer@samba.org>\n");
556 ptb_set_debug(debugging);
558 if(!poptPeekArg(pc)) {
559 poptPrintUsage(pc, stderr, 0);
563 input = poptGetArg(pc);
564 if (!quiet) fprintf(stderr, "Parsing %s...\n", input);
565 ret = ptb_read_file(input);
568 perror("Read error: ");
573 int baselength = strlen(input);
574 if (!strcmp(input + strlen(input) - 4, ".ptb")) {
577 output = malloc(baselength + 6);
578 strncpy(output, input, baselength);
579 strcpy(output + baselength, ".xml");
582 if (!quiet) fprintf(stderr, "Building DOM tree...\n");
584 doc = xmlNewDoc(BAD_CAST "1.0");
585 root_node = xmlNewNode(NULL, BAD_CAST "powertab");
586 xmlDocSetRootElement(doc, root_node);
588 comment = xmlNewComment("\nGenerated by ptb2xml, part of ptabtools. \n"
589 "(C) 2004 by Jelmer Vernooij <jelmer@samba.org>\n"
590 "See http://jelmer.vernstok.nl/oss/ptabtools/ for details\n");
591 xmlAddChild(root_node, comment);
593 xmlAddChild(root_node, xml_write_header(&ret->hdr));
595 for(i = 0; i < 2; i++) {
596 xmlAddChild(root_node, xml_write_instrument(ret, i));
599 fonts = xmlNewNode( NULL, "fonts"); xmlAddChild(root_node, fonts);
601 xmlAddChild(fonts, xml_write_font("default_font", &ret->default_font));
602 xmlAddChild(fonts, xml_write_font("chord_name_font", &ret->chord_name_font));
603 xmlAddChild(fonts, xml_write_font("tablature_font", &ret->tablature_font));
607 if (!quiet) fprintf(stderr, "Converting to MusicXML...\n");
609 xsltStylesheetPtr stylesheet = xsltParseStylesheetFile(MUSICXMLSTYLESHEET);
610 doc = xsltApplyStylesheet(stylesheet, doc, NULL);
611 xsltFreeStylesheet(stylesheet);
613 fprintf(stderr, "Conversion to MusicXML not possible in this version: libxslt not compiled in\n");
618 if (!quiet) fprintf(stderr, "Writing output to %s...\n", output);
620 if (xmlSaveFormatFile(output, doc, format_output) < 0) {