function TeoriaInterval(coord) {
  this.coord = coord;
}

TeoriaInterval.prototype = {
  name: function() {
    return intervalsIndex[this.number() - 1];
  },

  semitones: function() {
    return sum(mul(this.coord, [12, 7]));
  },

  number: function() {
    return Math.abs(this.value());
  },

  value: function() {
    var without = sub(this.coord,
      mul(sharp, Math.floor((this.coord[1] - 2) / 7) + 1))
      , i, val;

    i = intervalFromFifth[without[1] + 5];
    val = kStepNumber[i] + (without[0] - intervals[i][0]) * 7;

    return (val > 0) ? val : val - 2;
  },

  type: function() {
    return intervals[this.base()][0] <= 1 ? 'perfect' : 'minor';
  },

  base: function() {
    var fifth = sub(this.coord, mul(sharp, this.qualityValue()))[1], name;
    fifth = this.value() > 0 ? fifth + 5 : -(fifth - 5) % 7;

    name = intervalFromFifth[fifth];
    if (name === 'unison' && this.number() >= 8)
      name = 'octave';

    return name;
  },

  direction: function(dir) {
    if (dir) {
      var is = this.semitones() >= 0 ? 'up' : 'down';
      if (is !== dir)
        this.coord = mul(this.coord, -1);

      return this;
    }
    else
      return this.semitones() >= 0 ? 'up' : 'down';
  },

  simple: function(ignore) {
    var number = this.value();
    number = number > 8 || number < -8 ?
      ((number % 7) ? number % 7 : 7) : number;

    return this.quality() + (ignore ? Math.abs(number) : number);
  },

  compound: function(ignore) {
    var number = ignore ? this.number() : this.value();

    return this.quality() + number;
  },

  isCompound: function() {
    return this.number() > 8;
  },

  octaves: function() {
    var without = sub(this.coord, mul(sharp, this.qualityValue()));
    var octaves = without[0] - intervals[this.base()][0];

    return octaves;
  },

  invert: function() {
    var i = this.base();
    var qual = this.qualityValue();
    var acc = this.type() === 'minor' ? -(qual - 1) : -qual;
    var coord = intervals[intervalsIndex[9 - kStepNumber[i] - 1]];
    coord = add(coord, mul(sharp, acc));

    return new TeoriaInterval(coord);
  },

  quality: function(lng) {
    var quality = kAlterations[this.type()][this.qualityValue() + 2];

    return lng ? kQualityLong[quality] : quality;
  },

  qualityValue: function() {
    if (this.direction() === 'down')
      return Math.floor((-this.coord[1] - 2) / 7) + 1;
    else
      return Math.floor((this.coord[1] - 2) / 7) + 1;
  },

  equal: function(interval) {
    return sum(sub(this.coord, interval.coord)) === 0;
  },

  greater: function(interval) {
    var semi = this.semitones();
    var isemi = interval.semitones();

    // If equal in absolute size, measure which interval is bigger
    // For example P4 is bigger than A3
    return (semi === isemi) ?
      (this.number() > interval.number()) : (semi > isemi);
  },

  smaller: function(interval) {
    return !this.equal(interval) && !this.greater(interval);
  },

  toString: function() {
    return this.compound();
  }
};


@@ -822,16 +822,82 @@
  5) %25 7;
+%0A    fifth = fifth %3C 0 ? intervalFromFifth.length + fifth : fifth;
 %0A%0A    na

Fix downwards fifth intervals #39