Skip to main content

Topics

This section allows you to view all Topics made by this member. Note that you can only see Topics made in areas you currently have access to.

Topics - Brian Maskell

1
General Discussion / Skipping a section of music
My choir is rehearsing Borodin's Polovtsian Dances and I am using Richard Woodroffe's version (http://nwc-scriptorium.org/db/classical/b/boropold.nwc). However we are not singing all 629 bars! (That's a lot of notes Richard.)

I don't want actually to remove the cut sections, just skip over them, so I added on each stave:
at bar 233 a special ending (D) and the text 'cut to 369'
at bar 369 a special ending (1)
at bar 433 a special ending (D) and the text 'cut to 571'
at bar 571 a special ending (1)

The second cut works fine but in the first, play resumes at bar 321. If I add:
at bar 321 a special ending (D)
that cures the problem; play now resumes as required at 369 but what was going wrong at bar 321 initially and is there a better way to do this?

The working version is attached.
2
User Tools / Tools to favour sharps or flats in chords
These two user tools make it easier to adjust the spelling of accidentals, where the NWC default is not what is required. It is usually safest to Force Accidentals before using these tools.

Copy the code and save it in your Scripts folder as: brm_FavourSharps.php
Code: [Select · Download]
<?php
/*******************************************************************************
brm_FavourSharps 1.00

Brian Maskell

History:
[2010-09-29] Version 1.00 - Initial version
*******************************************************************************/
require_once("lib/nwc2clips.inc");

$clip = new NWC2Clip('php://stdin');

// MAIN PROGRAM

echo $clip->GetClipHeader()."\n";

foreach ($clip->Items as $item) {
    $o = new NWC2ClipItem($item);

    if (($o->GetObjType()=="Note")||($o->GetObjType()=="Chord")) {
$opts = $o->GetOpts();
$pos = $opts["Pos"];
if (is_array($pos)) {
   for ($i=0; $i<count($pos); $i++) {
        $n = new NWC2NotePitchPos($pos[$i]);
if ($n->Accidental=="b") {
   $n->Accidental="#";
      $n->Position--;
      $pos[$i]=$n->ReconstructClipText();
      unset($n);
}
   }
} else {
        $n = new NWC2NotePitchPos($pos);
if ($n->Accidental=="b") {
   $n->Accidental="#";
      $n->Position--;
      $pos=$n->ReconstructClipText();
      unset($n);
}
}
$o->Opts["Pos"] = $pos;
    } elseif ($o->GetObjType()=="RestChord") {
$opts = $o->GetOpts();
$pos = $opts["Pos2"];
if (is_array($pos)) {
   for ($i=0; $i<count($pos); $i++) {
        $n = new NWC2NotePitchPos($pos[$i]);
if ($n->Accidental=="b") {
   $n->Accidental="#";
      $n->Position--;
      $pos[$i]=$n->ReconstructClipText();
      unset($n);
}
   }
} else {
        $n = new NWC2NotePitchPos($pos);
if ($n->Accidental=="b") {
   $n->Accidental="#";
      $n->Position--;
      $pos=$n->ReconstructClipText();
      unset($n);
}
}
$o->Opts["Pos2"] = $pos;
    } else {
       // just echo the item unchanged
    }
    echo $o->ReconstructClipText()."\n";
}
echo NWC2_ENDCLIP."\n";

exit(NWC2RC_SUCCESS);
// exit(NWC2RC_REPORT); // alternative for debugging

?>

Copy the code and save it in your Scripts folder as: brm_FavourFlats.php
Code: [Select · Download]
<?php
/*******************************************************************************
brm_FavourFlats 1.00

Brian Maskell

History:
[2010-01-22] Version 1.00 - Initial version
*******************************************************************************/
require_once("lib/nwc2clips.inc");

$clip = new NWC2Clip('php://stdin');

// MAIN PROGRAM

echo $clip->GetClipHeader()."\n";

foreach ($clip->Items as $item) {
    $o = new NWC2ClipItem($item);

    if (($o->GetObjType()=="Note")||($o->GetObjType()=="Chord")) {
$opts = $o->GetOpts();
$pos = $opts["Pos"];
if (is_array($pos)) {
   for ($i=0; $i<count($pos); $i++) {
        $n = new NWC2NotePitchPos($pos[$i]);
if ($n->Accidental=="#") {
   $n->Accidental="b";
      $n->Position++;
      $pos[$i]=$n->ReconstructClipText();
      unset($n);
}
   }
} else {
        $n = new NWC2NotePitchPos($pos);
if ($n->Accidental=="#") {
   $n->Accidental="b";
      $n->Position++;
      $pos=$n->ReconstructClipText();
      unset($n);
}
}
$o->Opts["Pos"] = $pos;
    } elseif ($o->GetObjType()=="RestChord") {
$opts = $o->GetOpts();
$pos = $opts["Pos2"];
if (is_array($pos)) {
   for ($i=0; $i<count($pos); $i++) {
        $n = new NWC2NotePitchPos($pos[$i]);
if ($n->Accidental=="#") {
   $n->Accidental="b";
      $n->Position++;
      $pos[$i]=$n->ReconstructClipText();
      unset($n);
}
   }
} else {
        $n = new NWC2NotePitchPos($pos);
if ($n->Accidental=="#") {
   $n->Accidental="b";
      $n->Position++;
      $pos=$n->ReconstructClipText();
      unset($n);
}
}
$o->Opts["Pos2"] = $pos;
    } else {
       // just echo the item unchanged
    }
    echo $o->ReconstructClipText()."\n";
}
echo NWC2_ENDCLIP."\n";

exit(NWC2RC_SUCCESS);
// exit(NWC2RC_REPORT); // alternative for debugging

?>

3
General Discussion / Grace notes exported to NWC 1.75
I use NWC (v2.5.5) to prepare music as a note-bashing aid to my choir. Because some choir members still use NWC1, I export to v1.75 before publishing. So I am concerned with the way the lyrics fit the notes but not about the appearance.

Stave 1 of the attached file shows examples of grace notes with and without slurs; all notes have the attribute Lyric:Default.

Stave 2 shows what happens when this is exported to a v1.75 file. The middle notes in bars 2 and 4 now have the attribute Lyric:Never and the slur in bar 3 is missing.

Stave 3 has been doctored by modifying the Lyric attribute of three notes as indicated by the text notes.

Stave 4 confirms that, when this is exported, the lyrics are correct, although the slur in bar 3 is still missing.

Is there a good reason why export from NWC2 behaves in this way?
4
General Discussion / Overlaying parts
I use NWC mostly for SATB choral works. If two parts share a stave, NWC does the right thing with visual conflicts, eg position of notes that are close in pitch or stem lengths of quavers etc.. However for learning parts it is more helpful to have each part on its own stave but overlay them; now I have to resolve the conflicts manually by adjusting stem lengths (sometimes to zero) or adding note spacing where required.

It is of course possible to have two sets of staves - one visible but muted, the other undisplayed but audible - but that makes editing tedious and there is a danger of discrepancies creeping in between the two sets.

Does anyone have ideas of how to capture NWC's musical intelligence, for example by deleting one note in a chord but retaining any special treatment given to the other?

-- Brian Maskell
5
User Tools / Imported triplets
When NWC imports a MIDI file it does not faithfully represent triplets; correcting them manually is a tedious business so I have written a User Tool to do this.

It depends on correctly recognising the approximations that NWC generates during the import process. My current understanding of these is based on examples that I have exported and re-imported. I invite those who know NWC from the inside to help me to do better.

-- Brian

Code: [Select · Download]
<?php
/*******************************************************************************
brm_Triplify Version 1.00

This script will seek sequences that NWC has created from importing a MIDI file containing
triplets and convert those sequences into triplets.

History:
[2009-02-12] Version 1.00 - Initial version
*******************************************************************************/
require_once("lib/nwc2clips.inc");

$clip = new NWC2Clip('php://stdin');

// we shall need to assess the lengths of several notes etc, including tied notes, in units of ticks
$ticks_per_crotchet = 16; // as small as possible, since we will not be representing triplets
$tickLength = array(
"Whole"=> $ticks_per_crotchet *4,
"Half" => $ticks_per_crotchet *2,
"4th"  => $ticks_per_crotchet,
"8th"  => $ticks_per_crotchet /2,
"16th" => $ticks_per_crotchet /4,
"32nd" => $ticks_per_crotchet /8,
"64th" => $ticks_per_crotchet /16
);

// NWC's efforts in terms of representing a triplet come from examples. There may be more to come.
// When adding to this array, always insert sub-array elements in descending size
$validLengthGroup = array (
array(6,5,5),
array(3,3,2),
array(8,5,3), // a very poor and problematic representation of a triplet, but it does occur e.g.
      // with triplet (crotchet, crotchet rest, crotchet)=(8,3,5). However, in the quaver version of this
      // example the rest has disappeared altogether (3,NULL,1). so we have no chance!
array(11,5),
array(5,3)
);


function is_valid_group ($lengthSet) {
   global $validLengthGroup;

  // first reduce the array by its HCF
  if (sizeof($lengthSet) <= 1) return false;
  $factor = true;
  while($factor) {
    foreach($lengthSet as $v) $factor &= !($v % 2);
    if ($factor) foreach($lengthSet as $i=>$v) $lengthSet[$i] /= 2;
  }
  $factor = true;
  while($factor) {
    foreach($lengthSet as $v) $factor &= !($v % 3);
    if ($factor) foreach($lengthSet as $i=>$v) $lengthSet[$i] /= 3;
  }

  // then sort the array descending to match the convention in definition of validLengthGroup
  rsort($lengthSet);

  // now we are ready to check for a valid group of lengths
  foreach ($validLengthGroup as $thisgroup) {
    $result = false; // in case the last group has different length to the array under test
    if (sizeof($lengthSet) != sizeof($thisgroup)) continue;
    $result = true; // assume a match until a mis-match is found
    foreach($lengthSet as $i=>$v) if ($lengthSet[$i] != $thisgroup[$i]) $result=false;
    if ($result) break; // found the winner, no need to go on searching
  }
  return $result;
}

function isTiedNote($arg)
{
// if ($arg->GetObjType() == "Rest") return false; // this is caught anyway
$opts = $arg->GetOpts();
if (isset($opts["Pos"])) {
$pos = $opts["Pos"];
   if ($arg->GetObjType() == "Note") {
$n = new NWC2NotePitchPos($pos);
$ret = false;
if ($n->Tied) $ret = true;
unset($n);
} else { // must be a Chord, so Pos is not a string but an array of strings
       $ret = false;
       foreach($opts["Pos"] as $k=>$v) {
       $n = new NWC2NotePitchPos($v);
       if ($n->Tied) $ret = true; // in practice, expect all or none to be tied
       unset($n);
}
}
} else $ret=false;
return ($ret);
}

// Track the number of conversions
$numConvertedTriplets = 0;

//

echo $clip->GetClipHeader()."\n";

// Use arrays $TripletQ and $lengthSet to hold candidates
$TripletQ = array();
$lengthSet = array();
$tied_note_pending=false;

foreach ($clip->Items as $item) {
$o = new NWC2ClipItem($item);
$opts = $o->GetOpts();

$is_note = in_array($o->GetObjType(), array("Chord","Note","Rest","RestChord")); // but there won't be a RestChord!
$is_grace = isset($o->Opts["Dur"]["Grace"]);
$is_triplet = isset($o->Opts["Dur"]["Triplet"]); // check this
$is_tied = isTiedNote($o) ;
$is_dotted = isset($o->Opts["Dur"]["Dotted"]);
$is_dbldotted = isset($o->Opts["Dur"]["DblDotted"]);

if ($is_note && !$is_grace && !$is_triplet) {
   if ($TripletQ) array_push($TripletQ,$o); else $TripletQ = array($o); // whatever happens, remember the note
   // evaluate its length
   foreach ($tickLength as $notename => $value) {
      if (isset($opts["Dur"][$notename])) {
      $length = $value;
}
   }

   if ($is_dotted) $length *= 3/2;
   elseif ($is_dbldotted) $length *= 7/4;

   // there is at least one candidate in the queue, record length and check for triplet
   if($tied_note_pending) { // add its length to that stored for the previous note
   $last_element = sizeof($lengthSet)-1;
$lengthSet[$last_element] += $length;
   } else {
array_push($lengthSet, $length);
   }

   if ($tied_note_pending = $is_tied) continue; // yes, really not "=="! this is ready for the next lap

   // check if we have a triplet
   while (true) { // start a loop so we can retest having discarded one note
if (is_valid_group($lengthSet)) { //we have a triplet, output the notes in modified form
   $numConvertedTriplets++;
   $length = array_sum($lengthSet)/2; // this is the un-triplet-ised length of a single element
//    $dur = array_search($tickLength, $length); WHY DOESN'T THIS WORK? use alternative code
   foreach($tickLength as $key => $value) if ($value == $length) {$dur = $key; break; }
//    $durxtwo = array_search($tickLength, $length*2); WHY DOESN'T THIS WORK?

   foreach($tickLength as $key => $value) if ($value == $length *2) {$durxtwo = $key; break; }
   // Output the triplet, being two or three notes/rests/chords
$output_tied_note_pending = false; $length_index = 0;
foreach($TripletQ as $this) {
   if ($output_tied_note_pending) {
$output_tied_note_pending = isTiedNote($this);
continue; // dumping this note and processing the next item in the queue
   }
   if (isset($this->Opts["Opts"]["Beam"])) unset($this->Opts["Opts"]["Beam"]);
   if (isset($this->Opts["Opts"]["Stem"])) unset($this->Opts["Opts"]["Stem"]); // triplet stems don't need to be aligned
   // can't get rid of Opts altogether - a rest might have Opts["VertOffset"] set - not likely though

   if (isset($this->Opts["Dur"]["Dotted"])) unset($this->Opts["Dur"]["Dotted"]); // a dotted triplet makes no sense
   if (isset($this->Opts["Dur"]["DblDotted"])) unset($this->Opts["Dur"]["DblDotted"]); // nor does this!

   if (sizeof($lengthSet)==3) $this->Opts["Dur"] = array($dur => "","Triplet" => "");
   elseif ($lengthSet[0] > $lengthSet[1]) { // first note is of double duration
$this->Opts["Dur"] = array ((($length_index == 0) ? $durxtwo : $dur)=> "","Triplet" => "");
   } else { // second note is of double duration
$this->Opts["Dur"] = array ((($length_index == 0) ? $dur : $durxtwo)=> "","Triplet" => "");
   }

   if ($length_index == 0) $this->Opts["Dur"]["Triplet"] = "First";
   if ($length_index == (sizeof($lengthSet)-1)) $this->Opts["Dur"]["Triplet"] = "End";

   $output_tied_note_pending = isTiedNote($this);
   // un-tie the note/chord if it is tied
   if (isset($this->Opts["Pos"]) && $output_tied_note_pending) { // i.e. not a rest
      if ($this->GetObjType() == "Note") {
      $pos = new NWC2NotePitchPos($this->Opts["Pos"]);
     $pos->Tied=false;
     $this->Opts["Pos"] = $pos->ReconstructClipText();
     unset($pos);
      } else { // a Chord, must deal with all the Pos elements
foreach($this->Opts["Pos"] as $k=>$v) {
       $pos = new NWC2NotePitchPos($v);
       $pos->Tied = false;
     $this->Opts["Pos"][$k] = $pos->ReconstructClipText();
       unset($pos);
}
      }
   }
   if ($this->GetObjType() == "Rest") unset($this->Opts["Pos"]);
   echo $this->ReconstructClipText()."\n";

   $length_index++;
}
$TripletQ = array(); $lengthSet = array(); $tied_note_pending=false;
break; // out of the while loop
} elseif (sizeof($lengthSet)<3) { // not a triplet yet but there is still time so store data
   continue 2; // breaking out of the while loop to get a new item from the clip   
} else { // not a triplet so output the first note, drop it from the stored queue and retest
$output_tied_note_pending = true;
while ($output_tied_note_pending) {
   $this = array_shift($TripletQ);
   $output_tied_note_pending = isTiedNote($this);
   echo $this->ReconstructClipText()."\n";
}
$this = array_shift($lengthSet); // dump its length too
// Now we must retest because the remaining notes, if any, could be a (2 note) triplet
if ($TripletQ) continue; // repeat the while loop
} // end if triplet, maybe triplet or not triplet
   } // end while(true)loop
} else { // not a note, sequence is spoiled so output everything in the queue, plus this non-note item and start afresh
   if ($TripletQ) foreach($TripletQ as $this) {
echo $this->ReconstructClipText()."\n";
   }
   echo $o->ReconstructClipText()."\n";
   $TripletQ = array(); $lengthSet = array(); $tied_note_pending=false;
} // end if is_note else
} // end for each clip

if ($TripletQ) foreach($TripletQ as $this) {
   echo $this->ReconstructClipText()."\n";
}

echo NWC2_ENDCLIP."\n";

if (!$numConvertedTriplets) {
fputs(STDERR,"No valid triplets were found within the selection");
exit(NWC2RC_ERROR);
}

exit(NWC2RC_SUCCESS);

?>
6
User Tools / Documentation for the User Tools API
Is there a detailed and comprehensive document describing the User Tools Application Programming Interface?

I am slowly getting the hang of it but I keep encountering new (to me) elements; ArticulationsOnStem is the my latest and in this case I still havn't worked out when it occurs and what effect it has.

On this basis, writing robust User Tool code is a rather uncertain business.

-- Brian