#!/usr/bin/gawk -f # #Id: tune2scot,v 1.1 1992/11/13 18:30:04 putz Exp # # sw2abc # # Converts SongWrite tunes found in the Digital Tradition Database to # ABC score format (but very crudely! some further editing is required!) # # Created by Steve Putz, 17 September 1992 (putz@parc.xerox.com) # # horrifically hacked by Steve Allen (sla@ucolick.org) 1995 June-July # # In the horrific hacking all of the Steve Putz neato work on handling # multi-part tunes has been lost. It looks like it would be straightforward # to put it back in and generate multi-part ABC tunes in the manner used # by the Don Ward PlayABC program. As for the new multi-stave features # of ABC: I have never used them, I do not know if PlayABC can handle them, # and thus I am not qualified to determine whether they are a better solution. # I am currently too swamped to contribute to further development of this. # # Any copyrights on this belong to Steve Putz. I merely ask to be informed # of improved versions after they get polished--sla ######################################## BEGIN { if (nparts == "") { nparts = 4 } else { MaxVoice = nparts } if (nparts < 2) nparts = 2 # avoid division by zero CVoice = 0 pitches["R"] = "z" # rest pitches["x"] = "z" # unpitched/spoken note? (,,c is mostly noise) pitches["X"] = "z" # apparently another kind of rest # apparently SongWright pitches ":" .. "@" are below A pitches[":"] = "A,," pitches[";"] = "B,," pitches["<"] = "C," pitches["="] = "D," pitches[">"] = "E," pitches["?"] = "F," pitches["@"] = "G," pitches["A"] = "A," pitches["B"] = "B," pitches["C"] = "C" # middle C pitches["D"] = "D" pitches["E"] = "E" pitches["F"] = "F" pitches["G"] = "G" pitches["a"] = "A" pitches["b"] = "B" pitches["c"] = "c" pitches["d"] = "d" pitches["e"] = "e" pitches["f"] = "f" pitches["g"] = "g" # apparently SongWright pitches "h" .. are above g pitches["h"] = "a" pitches["i"] = "b" pitches["j"] = "c'" pitches["k"] = "d'" pitches["l"] = "e'" pitches["m"] = "f'" pitches["n"] = "g'" accidentals["-"] = "" # none accidentals["&"] = "_" # flat accidentals["%"] = "=" # natural accidentals["#"] = "^" # sharp # pretend we will do everything in 16th notes durations["1"] = "16" # whole durations["2"] = "8" # half durations["3"] = "12" # dotted half durations["4"] = "4" # quarter durations["5"] = "6" # dotted quarter durations["6"] = "8/3" # apparently triplet quarters (6th note) durations["7"] = "4/3" # apparently triplet eighths (12th note) durations["8"] = "2" # eighth durations["9"] = "3" # dotted eighth durations["0"] = "1" # sixteenth print "% " FILENAME print "% ABC score translated from SongWright by sw2abc" Title = "Null Title" } ######################################## function warning(message) { print "sw2abc: "FILENAME"("NR"): " message | "cat 1>&2" } function voiceadd(voice, str) { VoiceBufs[voice] = VoiceBufs[voice] str } function voiceinsert(voice, str, pos) { VoiceBufs[voice] = substr(VoiceBufs[voice], 1, pos-1) str substr(VoiceBufs[voice], pos) } function voicepos(voice) { return length(VoiceBufs[voice]) } function addbar(voice) { voiceadd(voice, "|") if (voice < MaxVoice) RestLine = RestLine "|" Mbeats = 0 } function newkey(voice, keyname) { voiceadd(voice, "K:" keyname "\n") CurrKey[voice] = keyname } function newtime(voice, beatsPerMeasure, getsOneBeat) { voiceadd(voice, "M:" beatsPerMeasure "/" getsOneBeat "\nL:1/16\n") CurrBperM[voice] = beatsPerMeasure CurrMbeat[voice] = getsOneBeat } function checktime(voice) { if (CurrKey[voice] != KeyName) { # apparently: implicit return to global key for each line newkey(voice, KeyName) } if (CurrBperM[voice] != TimeSig[1] || CurrMbeat[voice] != TimeSig[2]) { # guess: implicit return to global time signature for each line newtime(voice, TimeSig[1], TimeSig[2]) } } function writehead() { # write out all the info at the top of an ABC tune print "X:1" # must be first. I make every tune # 1 print "T:" Title # must be second. print "N:" Comment print "C:" Composer print "S:" Author print "A:" print "O:" print "R:" print "M:" Meter print "K:" KeyName # last in the header if (Tempo != "") print "I:speed " Tempo wrotehead = 1 } function writesofar() { for (v=1; v<=MaxVoice; v++) { if (LineCounts[v] > 0) printf "% voice %d (%d lines, %d notes)\n", v, LineCounts[v], NoteCounts[v] print VoiceBufs[v] LineCounts[v] = 0 NoteCounts[v] = 0 VoiceBufs[v] = "" } CVoice = 0 } function getnote(voice, note, tie) { # bug: wont find combined S commands if in different order then below if (substr(note,1,2) == "SK") { newkey(voice, substr(note,3,2)) note = substr(note,5) } if (substr(note,1,2) == "ST") { voiceadd(voice, "\\\n") newtime(voice, substr(note,3,1), substr(note,4,1)) note = substr(note,5) } if (length(note) > 3) { warning("unknown embedded-code: " substr(note, 1, length(note)-3)) note = substr(note, length(note)-2) } if (note == "S-9") { # fermata (apparently) return } else if (note == "S-6") { # marks location of a bar (apparently) addbar(voice) return } # don't know what "S-1" "S-2" "S-4" "S-5" "S-8" are # probably wrong about "S-6" # don't know what "SU" is (e.g. SUikSU!ka-8 SU!fR-2) # don't know what "SB" is (e.g. b-0_SB4) # don't know what "W-" is (e.g. W-2 W-3) pit = pitches[substr(note,1,1)] sep = substr(note,2,1) acc = accidentals[sep] dur = durations[substr(note,3,1)] if (pit == "") { warning("unknown code: " note) } else if (sep != "-" && acc == "") { warning("unknown accidental: " note) } else if (dur == "") { warning("unknown duration: " note) } else { if (dur == "1") { odur = "" } else { odur = dur } if (tie == "_") { tie = "" } else { tie = " " } acc = accidentals[sep] if (acc == "" && sep != "-") warning("unknown accidental: " note) voiceadd(voice, acc pit odur tie) if (voice < MaxVoice) RestLine = RestLine " " dur "r" bea = dur / getsOneBeat Mbeats += bea if (Mbeats >= CurrBperM[voice]) addbar(voice) NoteCounts[voice] = NoteCounts[voice] + 1 } } ######################################## /^S-/ { # tempo Tempo = substr($1,3) next } /^K-/ { # key signature KeyName = substr($1,3) next } /^B-/ { # time signature n = split(substr($1,3), TimeSig, "/") Meter = substr($1,3) beatPerMeasure = TimeSig[1] getsOneBeat = TimeSig[2] next } /^[Mm]/ { # music line # "M" (treble clef) or "m" (bass clef) melody line # don't know what 2nd char means (usually -, sometimes +) # don't know what 3rd char means (maybe time sig display info) if (substr($1,1,1) == "m") { Bass = 1 } else { Bass = 0 } # trim off initial [Mm][-+][0-9] leaving music $0 = substr($0, 4) CVoice++ if (CVoice > MaxVoice) { MaxVoice = CVoice if (LineCounts[1] > 1) { warning("WARNING: voice " CVoice " added after " LineCounts[1] " lines of voice 1") voiceadd(CVoice, "; WARNING: voice " CVoice " added after " LineCounts[1] " lines of voice 1" ORS) } } LineCounts[CVoice] = LineCounts[CVoice] + 1 checktime(CVoice) RestLine = "" for (i=1; i<=NF; i++) { n = split($i, notes, "_") for (j=1; j