// Copyright 2016 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

syntax = "proto3";

package tensorflow.magenta;

// A message containing a symbolic music sequence. The design is largely
// based on MIDI but it should be able to represent any music sequence.
// For details see https://www.midi.org/specifications.
message NoteSequence {
  // Unique id.
  string id = 1;
  // The path of the file relative to the root of the collection.
  string filename = 2;
  // The collection from which the file comes. This can be shorthand e.g.
  // "bach". One purpose is to allow for easy selection of all or some files
  // from a particular source.
  string collection_name = 3;

  // MIDI ticks per quarter note, also known as resolution or PPQ ("pulses per
  // quarter").
  // There is no widely-used default. A default of 220 is assumed per the choice
  // made in third_party/py/pretty_midi.
  int32 ticks_per_quarter = 4;
  // Lacking a time signature, 4/4 is assumed per MIDI standard.
  repeated TimeSignature time_signatures = 5;
  // Lacking a key signature, C Major is assumed per MIDI standard.
  repeated KeySignature key_signatures = 6;
  // Lacking a tempo change, 120 qpm is assumed per MIDI standard.
  repeated Tempo tempos = 7;
  // A Note combines a MIDI NoteOn and NoteOff into one event with duration.
  repeated Note notes = 8;
  // The total time of the Sequence in seconds.
  double total_time = 9;

  // MIDI-specific events that are generally relevant for performance, metadata
  // storage or re-synthesis but not for processing the music score.
  repeated PitchBend pitch_bends = 10;
  repeated ControlChange control_changes = 11;

  // Score-related information about parts.
  repeated PartInfo part_infos = 12;

  // Source-related information.
  SourceInfo source_info = 13;

  // Arbitrary textual annotations.
  repeated TextAnnotation text_annotations = 14;

  message Note {
    // MIDI pitch; see en.wikipedia.org/wiki/MIDI_Tuning_Standard for details.
    int32 pitch = 1;
    // The notated pitch spelling in the score.
    PitchName pitch_name = 11;
    // Velocity ranging between 0 and 127.
    int32 velocity = 2;
    // Start and end time in seconds.
    double start_time = 3;
    double end_time = 4;
    // Score-relative note length. E.g. a quarter note is 1/4.
    int32 numerator = 5;
    int32 denominator = 6;
    // For MIDI source data, an instrument stores all events in a track having
    // the same program and channel, as done by pretty-midi.
    int32 instrument = 7;
    // A program selects an instrument's sound. E.g. program 12 is vibraphone in
    // General MIDI. See www.midi.org/specifications/item/gm-level-1-sound-set.
    int32 program = 8;
    // When true, the event is on an instrument that is a drum (MIDI channel 9).
    bool is_drum = 9;
    // The part or voice index if this came from a score. Otherwise, just 0.
    // For example, a score may have separate voices for Soprano, Alto, Tenor,
    // Bass. This field allows that information to be retained.
    int32 part = 10;
  }

  // Adopted from Musescore with start enum shifted to 0; see
  // https://musescore.org/en/plugin-development/tonal-pitch-class-enum
  // for details.
  enum PitchName {
    UNKNOWN_PITCH_NAME = 0;
    F_FLAT_FLAT = 1;
    C_FLAT_FLAT = 2;
    G_FLAT_FLAT = 3;
    D_FLAT_FLAT = 4;
    A_FLAT_FLAT = 5;
    E_FLAT_FLAT = 6;
    B_FLAT_FLAT = 7;
    F_FLAT = 8;
    C_FLAT = 9;
    G_FLAT = 10;
    D_FLAT = 11;
    A_FLAT = 12;
    E_FLAT = 13;
    B_FLAT = 14;
    F = 15;
    C = 16;
    G = 17;
    D = 18;
    A = 19;
    E = 20;
    B = 21;
    F_SHARP = 22;
    C_SHARP = 23;
    G_SHARP = 24;
    D_SHARP = 25;
    A_SHARP = 26;
    E_SHARP = 27;
    B_SHARP = 28;
    F_SHARP_SHARP = 29;
    C_SHARP_SHARP = 30;
    G_SHARP_SHARP = 31;
    D_SHARP_SHARP = 32;
    A_SHARP_SHARP = 33;
    E_SHARP_SHARP = 34;
    B_SHARP_SHARP = 35;
  }

  message TimeSignature {
    // Time in seconds.
    double time = 1;
    int32 numerator = 2;
    int32 denominator = 3;
  }

  message KeySignature {
    // Time in seconds.
    double time = 1;
    Key key = 2;
    Mode mode = 3;

    enum Key {
      option allow_alias = true;
      C = 0;
      C_SHARP = 1;
      D_FLAT = 1;
      D = 2;
      D_SHARP = 3;
      E_FLAT = 3;
      E = 4;
      F = 5;
      F_SHARP = 6;
      G_FLAT = 6;
      G = 7;
      G_SHARP = 8;
      A_FLAT = 8;
      A = 9;
      A_SHARP = 10;
      B_FLAT = 10;
      B = 11;
    }

    enum Mode {
      MAJOR = 0;
      MINOR = 1;
      NOT_SPECIFIED = 2;
    }
  }

  message Tempo {
    // Time in seconds when tempo goes into effect.
    double time = 1;
    // Tempo in quarter notes per minute.
    double qpm = 2;
  }

  // Stores MIDI PitchBend data. See the MIDI specification for details.
  message PitchBend {
    // Time in seconds.
    double time = 1;
    // Pitch bend amount in the range (-8192, 8191).
    int32 bend = 2;
    int32 instrument = 3;
    int32 program = 4;
    bool is_drum = 5;
  }

  // Stores MIDI Control Change data. See the MIDI specification for details.
  message ControlChange {
    // Time in seconds.
    double time = 1;
    // Control (or "controller") number e.g. 0x4 = Foot Controller.
    int32 control_number = 2;
    // The value for that controller in the range (0, 127).
    int32 control_value = 3;
    int32 instrument = 4;
    int32 program = 5;
    bool is_drum = 6;
  }

  // Stores score-related information about a particular part (sometimes also
  // called track or voice).
  message PartInfo {
    // The part index.
    int32 part = 1;
    // The name of the part. Examples: "Soprano" or "Trumpet".
    string name = 2;
  }

  // Stores source-related information.
  message SourceInfo {
    // The type of source, if it was score-based or performance-based.
    SourceType source_type = 1;
    // The encoding type used in the source file.
    EncodingType encoding_type = 2;

    // That parser that was used to parse the source file.
    Parser parser = 3;

    // The type of source that was encoded in the original file.
    enum SourceType {
      UNKNOWN_SOURCE_TYPE = 0;
      // If the source was some kind of score (e.g., MusicXML, ABC, etc.).
      // We can expect perfect timing alignment with measures and complete
      // TimeSignature and KeySignature information.
      SCORE_BASED = 1;
      PERFORMANCE_BASED = 2;
    }

    // Enum for all encoding types, both score_based and performance_based.
    enum EncodingType {
      UNKNOWN_ENCODING_TYPE = 0;
      MUSIC_XML = 1;
      ABC = 2;
      MIDI = 3;
    }

    // Name of parser used to parse the source file.
    enum Parser {
      UNKNOWN_PARSER = 0;
      MUSIC21 = 1;
      PRETTY_MIDI = 2;
    }
  }

  // Stores an arbitrary text annotation associated with a point in time.
  message TextAnnotation {
    // Time in seconds.
    double time = 1;
    // Text of the annotation.
    string text = 2;
    // Type of the annotation, to assist with automated interpretation.
    TextAnnotationType annotation_type = 3;

    enum TextAnnotationType {
      // Unknown annotation type.
      UNKNOWN = 0;
      // Chord symbol as used in lead sheets.
      CHORD_SYMBOL = 1;
    }
  }
}
