Source: index.js

#!/usr/bin/env node

var program = require('commander');
var chalk = require('chalk');
var fs = require('fs');
var nconf = require('nconf');

nconf.argv()
  .env()
  .file({ file: 'config.json' });

var mode;
var inputFile;
var outputFile;
var circleOfFifths = nconf.get('circleOfFifths');
var accidental = nconf.get('accidental');
var pitches = nconf.get('pitches');

program
  .version('0.0.1')
  .arguments('<input> [output]')
  .action(function onAction(input, output) {
    inputFile = input;
    outputFile = output;
  });

program.on('--help', function() {
  console.log('  Examples:');
  console.log('');
  console.log('    $ musicjson2abc input.json output.abc');
  console.log('    $ musicjson2abc example.json example.abc');
  console.log('');
  console.log('  Hint:');
  console.log('');
  console.log('    The input file should be a valid musicJSON file');
  console.log('    The output file will become a valid abc file.')
  console.log('    This may overwrite existing files.');
  console.log('');
});

program.parse(process.argv);

if (typeof inputFile === 'undefined') {
  console.error(chalk.bold.red('ERROR: No input file specified.'));
  console.info(chalk.cyan('Run musicjson2abc -h for further information.'));
  process.exit(1);
}
if (typeof outputFile === 'undefined') {
  outputFile = inputFile.replace(/\.[^/.]+$/, "")
    + ".abc";
  console.info(chalk.cyan('INFO: No output file specified.'));
  console.info(chalk.cyan('Defaults to', outputFile));
}

readInput(inputFile);

/**
 * Reads the JSON eoncoded data from the specified input file
 * @param {string} file - The path to the specified input file
 */
function readInput(file) {
  fs.readFile(file, 'utf8', function(err, data) {
    if (err) {
      console.error(chalk.bold.red('ERROR:', err));
      process.exit(1);
    }
    convert(JSON.parse(data));
  });
}

/**
 * Writes the abc notated string to the specified output file
 * @param {string} file - The path to the specified output file
 * @param {string} data - The data that should be written to the file
 */
function writeOutput(file, data) {
  fs.writeFile(file, data, function(err) {
    if(err) {
      console.error(chalk.bold.red('ERROR:', err));
      process.exit(1);
    }

    console.info(chalk.cyan('Output written to', outputFile));
  });
}

/**
 * Converts input from JSON to abc notation and saves to output file
 * @param {input} input - The parsed input from input file
 */
function convert(input) {
  console.log(input);

  var output = getAbcString(input);
  console.log(output);

  writeOutput(outputFile, output);
}

/**
 * Returns the abc notation string from given input
 * @param {object} input - The parsed input from input file
 * @retruns {string}
 */
function getAbcString(input) {
  var outputData = "";
  outputData += "X:"
    + input.id
    + "\n";
  outputData += "T:"
    + input.id
    + "\n";
  outputData += "M:"
    + input.attributes.time.beats
    + "/"
    + input.attributes.time["beat-type"]
    + "\n";
  outputData += "L:"
    + "1/"
    + (input.attributes.divisions * input.attributes.time["beat-type"])
    + "\n";
  outputData += "K:"
    + getAbcKey(input.attributes.key.fifths, input.attributes.key.mode)
    + "\n";

  for (var i = 0; i < input.measures.length; i++) {
    var measure = input.measures[i];
    if (measure.attributes.repeat.left) {
      outputData += "\n"
        + "|:";
    } else {
      //outputData += "|";
    }

    for (var j = 0; j < measure.notes.length; j++) {

      outputData += " "
        + getAbcNote(measure.notes[j]);
    }

    if (measure.attributes.repeat.right) {
      outputData += ":|"
        + "\n";
    } else {
      outputData += "|";
    }

  }

  return outputData;
}

/**
 * Returns the key for abc notation from given fifths
 * @param {number} fifths - The position inside the circle of fifths
 * @param {string|undefined} mode - The mode (major / minor)
 * @retruns {string}
 */
function getAbcKey(fifths, mode) {
  if (typeof mode === 'undefined') mode = 'major';
  return circleOfFifths[mode][fifths];
}

/**
 * Returns a note in abc notation from given note object (JSON)
 * @param {object} note - The note that should be transformed to abc
 * @returns {string}
 */
function getAbcNote(note) {
  // check if rest
  if (note.rest) {
    // return rest as abc
    return "z" + note.duration;
  } else {
    // return note as abc
    return accidental[note.pitch.accidental]
      + pitches[note.pitch.octave][note.pitch.step]
      + note.duration;
  }
}


/**
 * Returns a string in abc notation from given data
 * @param {object} data - The JSON data that should be transformed to abc
 * @returns {string}
 */
exports.convert2Abc = function(data) {
  return getAbcString(data);
}

// Run with: musicjson2abc example.json

// Run jsdoc with: jsdoc index.js -d doc -R README.md