adamrenklint/bap

View on GitHub
lib/Pattern.js

Summary

Maintainability
A
0 mins
Test Coverage
C
73%
var PlayableModel = require('./PlayableModel');
var Channel = require('./Channel');
var Collection = require('./Collection');
var overloadedAccessor = require('./mixins/overloadedAccessor');
var volumeParams = require('./mixins/volumeParams');
var Kit = require('./Kit');
var numberInRangeType = require('./types/numberInRange');
var Sequence = require('./Sequence');
var sequenceActions = require('./utils/sequenceActions');

var Pattern = PlayableModel.extend(volumeParams, {

  type: 'pattern',

  props: {
    bars: ['positiveNumber', true, 1],
    beatsPerBar: ['positiveNumber', true, 4],
    tempo: ['positiveNumber', true, 120],
    loop: ['boolean', true, true],
    pitch: 'number'
  },

  dataTypes: {
    positiveNumber: numberInRangeType('positiveNumber', 1, Infinity),
    volumeRange: numberInRangeType('volumeRange', 0, 999)
  },

  collections: {
    channels: Collection.extend({
      model: Channel
    }),
    kits: Collection.extend({
      model: Kit
    })
  },

  initialize: function () {
    PlayableModel.prototype.initialize.apply(this, arguments);

    this.listenTo(this.channels, 'start', this._start);
    this.listenTo(this.channels, 'stop', this._stop);

    this.cacheMethodUntilEvent('notes', 'change:channels');
  },

  notes: function (bar, beat, tick) {
    var notes = [];
    this.channels.forEach(function (channel) {
      notes.push.apply(notes, channel.notes(bar, beat, tick));
    });
    return notes;
  },

  then: function () {
    var sequences = sequenceActions.then(this, arguments);
    return new Sequence({ sequences: sequences });
  },

  after: function () {
    var sequences = sequenceActions.after(this, arguments);
    return new Sequence({ sequences: sequences });
  },

  and: function () {
    var sequences = sequenceActions.and(this, arguments);
    return new Sequence({ sequences: sequences });
  },

  _start: function (time, note, channel) {
    this._runEvent('start', time, note, channel);
  },

  _stop: function (time, note, channel) {
    this._runEvent('stop', time, note, channel);
  },

  _runEvent: function (event, time, note, channel) {
    var kitId = parseInt(note.target.slice(0, 1), 10);
    var slotId = note.target.slice(1);
    var kit = this.kit(kitId);
    if (kit) {
      if (kit.mute) return;
      kit.slot(slotId)[event](time, note, channel, this, kit);
    }
    else {
      console.warn('No kit found for ' + note.target, note);
    }
  }

}, overloadedAccessor('channel', Channel), overloadedAccessor('kit', Kit));

module.exports = Pattern;