/// <summary> /// Just generate a cloud of points within the given sphere /// </summary> /// <param name="engine"></param> public static void GenerateAFuckTonneOfCubes(Engine.Engine engine, ChannelAndInstrument ci, Note scaleNote, int numberOfCubes, Point3D point, double radius, double cubeRadius) { Scale scale = new Scale(scaleNote, Scale.Major); Random random = new Random(); OutputDevice device = OutputDevice.InstalledDevices[0]; Channel channel = ci.Channel; Instrument instrument = ci.Instrument; int rootOctave = 3; int thisOctave = rootOctave; for (int i = 0; i < numberOfCubes; i++) { double x = point.X + (random.NextDouble() - 0.5) * radius; double y = point.Y + (random.NextDouble() - 0.5) * radius; double z = point.Z + (random.NextDouble() - 0.5) * radius; Point3D cubePoint = new Point3D(x * radius, y * radius, z * radius); Pitch thisPitch; // limit it to 3 octaves if (i % 21 == 0) thisOctave = rootOctave; thisPitch = scale.NoteSequence[i % 7].PitchInOctave(thisOctave); // increment the octave if we have run out of notes if (i % 7 == 0) thisOctave++; SingleNoteCube a = new Cubes.SingleNoteCube(cubePoint, cubeRadius, thisPitch, instrument, App.OutputDevice, channel); engine.AddCube(a); } }
public static void PlayTact(Note root, Pattern pattern, OutputDevice outputDevice) { PlayAccord(root, pattern, Direction.Down, outputDevice); Thread.Sleep(400); PlayAccord(root, pattern, Direction.Down, outputDevice); Thread.Sleep(150); PlayAccord(root, pattern, Direction.Up, outputDevice); Thread.Sleep(400); PlayAccord(root, pattern, Direction.Up, outputDevice); Thread.Sleep(200); PlayAccord(root, pattern, Direction.Down, outputDevice); Thread.Sleep(150); PlayAccord(root, pattern, Direction.Up, outputDevice); Thread.Sleep(200); PlayAccord(root, pattern, Direction.Down, outputDevice); Thread.Sleep(400); PlayAccord(root, pattern, Direction.Down, outputDevice); Thread.Sleep(150); PlayAccord(root, pattern, Direction.Up, outputDevice); Thread.Sleep(400); PlayAccord(root, pattern, Direction.Up, outputDevice); Thread.Sleep(200); PlayAccord(root, pattern, Direction.Down, outputDevice); //Thread.Sleep(150); //PlayAccord(root, pattern, Direction.Up, outputDevice); Thread.Sleep(400); }
public void PlayNote(Note note) { var noteOn = new NoteOnMessage(this._outputDevice, this.PlayerParameters.Channel, note, this._velocity, this._clock.BeatTime); var noteOff = new NoteOffMessage(this._outputDevice, this.PlayerParameters.Channel, note, this._velocity, this._clock.BeatTime + 1); this._clock.Schedule(noteOn); this._clock.Schedule(noteOff); }
/// <summary> /// Encodes a Note On short message. /// </summary> /// <param name="channel">The channel.</param> /// <param name="note">The note.</param> /// <param name="velocity">The velocity 0..127.</param> /// <returns>A value that can be passed to midiOutShortMsg.</returns> public static UInt32 EncodeNoteOn(Channel channel, Note note, int velocity) { channel.Validate(); note.Validate(); if (velocity < 0 || velocity > 127) { throw new ArgumentOutOfRangeException("Velocity is out of range."); } return (UInt32)(0x90 | ((int)channel) | ((int)note << 8) | (velocity << 16)); }
/// <summary> /// Decodes a Note On short message. /// </summary> /// <param name="dwParam1">The dwParam1 arg passed to MidiInProc.</param> /// <param name="dwParam2">The dwParam2 arg passed to MidiInProc.</param> /// <param name="channel">Filled in with the channel.</param> /// <param name="note">Filled in with the note.</param> /// <param name="velocity">Filled in with the velocity, 0.127</param> /// <param name="timestamp">Filled in with the timestamp in microseconds since /// midiInStart().</param> public static void DecodeNoteOn(UIntPtr dwParam1, UIntPtr dwParam2, out Channel channel, out Note note, out int velocity, out UInt32 timestamp) { if (!IsNoteOn(dwParam1, dwParam2)) { throw new ArgumentException("Not a Note On message."); } channel = (Channel)((int)dwParam1 & 0x0f); note = (Note)(((int)dwParam1 & 0xff00) >> 8); velocity = (((int)dwParam1 & 0xff0000) >> 16); timestamp = (UInt32)dwParam2; }
public static Pitch PitchFromString(string pitchString) { var parsePos = 0; var note = Note.ParseNote(pitchString, ref parsePos); var octave = int.Parse(pitchString.Substring(parsePos)); // Support B#. if (note.Letter == 'B' && note.Accidental == 1) { note = new Note('C'); octave++; } // Do not allow flats and double accidentals (YAGNI). if (note.Accidental < 0 || note.Accidental > 1) { throw new ArgumentException("Flats and double accidentals are not supported."); } return note.PitchInOctave(octave); }
public static Button FindButtonAndChangeColor(Note note, Button[,] buttons, Note[,] grifNotes, out bool visible) { for (int i = 0; i < 6; i++) { for (int j = 0; j < 16; j++) { if (grifNotes[i, j] == note) { buttons[i, j].BackColor = System.Drawing.Color.Red; visible = buttons[i, j].Visible; if(buttons[i,j].InvokeRequired) buttons[i,j].Invoke(new Action(() => {buttons[i,j].Visible = true;})); //buttons[i, j].Visible = true; if (Form1.ActiveForm != null && Form1.ActiveForm.InvokeRequired) Form1.ActiveForm.Invoke(new Action(() => { Form1.ActiveForm.Refresh(); })); return buttons[i, j]; } } } visible = false; return buttons[0, 0]; }
public static void PlayAccord(Note root, Pattern pattern, Direction direction, OutputDevice outputDevice) { if (pattern == Pattern.Minor)//тоника на 5 струне { if (direction == Direction.Down) { outputDevice.SendNoteOn(Channel.Channel1, root, 80); Thread.Sleep(15);//20 outputDevice.SendNoteOn(Channel.Channel1, (Note)((int)root + 7), 80); Thread.Sleep(15); outputDevice.SendNoteOn(Channel.Channel1, (Note)((int)root + 12), 80); Thread.Sleep(15); outputDevice.SendNoteOn(Channel.Channel1, (Note)((int)root + 12 + 3), 80); Thread.Sleep(15); outputDevice.SendNoteOn(Channel.Channel1, (Note)((int)root + 12 + 7), 80); } else { outputDevice.SendNoteOn(Channel.Channel1, (Note)((int)root + 12 + 7), 80); Thread.Sleep(15); outputDevice.SendNoteOn(Channel.Channel1, (Note)((int)root + 12 + 3), 80); Thread.Sleep(15); outputDevice.SendNoteOn(Channel.Channel1, (Note)((int)root + 12), 80); Thread.Sleep(15); outputDevice.SendNoteOn(Channel.Channel1, (Note)((int)root + 7), 80); Thread.Sleep(15); outputDevice.SendNoteOn(Channel.Channel1, root, 80); } } else //Мажор, тоника на 6 струне { if (direction == Direction.Down) { outputDevice.SendNoteOn(Channel.Channel1, root, 80); Thread.Sleep(15); outputDevice.SendNoteOn(Channel.Channel1, (Note)((int)root + 7), 80); Thread.Sleep(15); outputDevice.SendNoteOn(Channel.Channel1, (Note)((int)root + 12), 80); Thread.Sleep(15); outputDevice.SendNoteOn(Channel.Channel1, (Note)((int)root + 12 + 4), 80); Thread.Sleep(15); outputDevice.SendNoteOn(Channel.Channel1, (Note)((int)root + 12 + 7), 80); Thread.Sleep(15); outputDevice.SendNoteOn(Channel.Channel1, (Note)((int)root + 24), 80); } else { outputDevice.SendNoteOn(Channel.Channel1, (Note)((int)root + 24), 80); Thread.Sleep(15); outputDevice.SendNoteOn(Channel.Channel1, (Note)((int)root + 12 + 7), 80); Thread.Sleep(15); outputDevice.SendNoteOn(Channel.Channel1, (Note)((int)root + 12 + 4), 80); Thread.Sleep(15); outputDevice.SendNoteOn(Channel.Channel1, (Note)((int)root + 12), 80); Thread.Sleep(15); outputDevice.SendNoteOn(Channel.Channel1, (Note)((int)root + 7), 80); Thread.Sleep(15); outputDevice.SendNoteOn(Channel.Channel1, root, 80); } } }
/// <summary> /// Проигрывает мелодию в указанном ритме от указанной ноты. /// С фиксированной продолжительностью такта. /// Играется столько нот, сколько звучащих /// нот в ритме(столько, сколько единиц в массиве ритма) /// </summary> /// <param name="sd">Aggregates OutputDevice and Channel</param> /// <param name="notes">Массив нот</param> /// <param name="rhythm">Массив, описывающий ритм</param> /// <param name="tonica">Нота, от которой играется мелодия</param> /// <param name="duration">Продолжительность такта в секундах с точностью до тысячных</param> public static void PlayMelodyWithRhythm(SoundDevices sd, int[] notes, int[] rhythm, Note tonica, double duration, Note[,] grifNotes, Button[,] buttons, CancellationToken ct) { /* Продолжительность такта в миллисекундах */ int dur = (int)(duration * 1000); int divisor = 0, k = 0, l = 0; while(k < notes.Length && l < rhythm.Length) { divisor++; if (rhythm[l] == 1) k++; l++; } /* Продолжительность звучания одной ноты(или паузы) */ int oneNoteDur = dur / divisor; Note note = Note.A0; int j = 0; for (int i = 0; i < rhythm.Length; i++) { if (ct.IsCancellationRequested) return; if (rhythm[i] == 0) { System.Threading.Thread.Sleep(oneNoteDur); } else { /* 40 - E2, * 79 - G5 */ int n = ((int)tonica - 1 + notes[j]); while (n > 79) n = n - 12; while (n < 40) n = n + 12; sd.output.SendNoteOff(sd.channel, note, 80); note = (Note)n; sd.output.SendNoteOn(sd.channel, note, 80); bool visible; Button button = FindButtonAndChangeColor(note, buttons, grifNotes, out visible); System.Threading.Thread.Sleep(oneNoteDur); button.BackColor = default(System.Drawing.Color); if (!visible && button.InvokeRequired) button.Invoke(new Action(() => { button.Visible = false; })); if (Form1.ActiveForm != null && Form1.ActiveForm.InvokeRequired) Form1.ActiveForm.Invoke(new Action(() => { Form1.ActiveForm.Refresh(); })); j++; if (j == notes.Length) return; } } sd.output.SendNoteOff(sd.channel, note, 80); }
public static void PlayMelodyWithRhythm(SoundDevices sd, Melody melody, Note tonica, double duration, Note[,] grifNotes, Button[,] buttons, CancellationToken ct) { sd.output.SilenceAllNotes(); int[] notes = melody.Notes; int[] rhythm = melody.Rhythm; PlayMelodyWithRhythm(sd, notes, rhythm, tonica, duration, grifNotes, buttons, ct); }
/// <summary> /// Returns true if note would be in this scale when decending through the note. /// </summary> /// <param name="note">The note</param> /// <returns>True if note is included when decending.</returns> /// <exception cref="ArgumentOutOfRangeException">note is out-of-range.</exception> public bool ContainsWhenDescending(Note note) { return descendingMask[note.SemitonesAbove(Tonic)]; }
/// <summary> /// Sends a Note Off message to this MIDI output device. /// </summary> /// <param name="channel">The channel.</param> /// <param name="note">The note.</param> /// <param name="velocity">The velocity 0..127.</param> /// <exception cref="ArgumentOutOfRangeException">channel, note, or velocity is /// out-of-range.</exception> /// <exception cref="InvalidOperationException">The device is not open.</exception> /// <exception cref="DeviceException">The message cannot be sent.</exception> public void SendNoteOff(Channel channel, Note note, int velocity) { lock (this) { CheckOpen(); CheckReturnCode(Win32API.midiOutShortMsg(handle, ShortMsg.EncodeNoteOff(channel, note, velocity))); } }
string transpose(string musicKey, string targetKey, int direction, bool flat,out Midi.Pitch outpitch) { //convert the key to a number: //"G8" = 8 * "8" + 7 bool black = musicKey.Contains("Sharp"); musicKey = musicKey.Replace("Sharp", ""); string scale = "CDEFGABC"; int y = int.Parse(""+musicKey[1]); int x = scale.IndexOf(musicKey[0]); if (flat && black) //add1 to x x = (x + 1); if (x == 7) { x %= 7; y++; } int keyID = y * 7 + x; switch(targetKey) { case "G": direction = 3; break; case "A": direction = 2; break; case "B": direction =1; break; } keyID += direction; ; y = keyID / 7; x = keyID % 7; string preout = "" + scale[x] + ((black)?("Sharp"):("")) +y.ToString(); string cnote = "" + preout[0]; // bool sharp = musicKey.Contains("Sharp"); if (black) cnote += "#"; Midi.Note outnote = new Midi.Note(cnote); outpitch = outnote.PitchInOctave(y); return preout; }
/// <summary> /// Returns true if this note name is enharmonic with otherNote. /// </summary> /// <param name="otherNote">Another note.</param> /// <returns>True if the names can refer to the same pitch.</returns> public bool IsEharmonicWith(Note otherNote) { return this.positionInOctave == otherNote.positionInOctave; }
/// <summary> /// Protected constructor. /// </summary> protected NoteMessage(DeviceBase device, Channel channel, Note note, int velocity, float beatTime) : base(device, channel, beatTime) { note.Validate(); if (velocity < 0 || velocity > 127) { throw new ArgumentOutOfRangeException("velocity"); } this.note = note; this.velocity = velocity; }
private void Form1_Load(object sender, EventArgs e) { savedMelodysList = new List<Melody>(); savedMelodysList = Parser.GetAllMelodys(); for (int i = 0; i < savedMelodysList.Count; i++) { savedMelodysComboBox.Items.Add(savedMelodysList[i].Name + "(" + savedMelodysList[i].ScaleName.ToString() + ")"); } if(savedMelodysComboBox.Items.Count != 0) savedMelodysComboBox.SelectedIndex = 0; nameLabel.Text = "Сгенерируйте мелодию!"; notesTextBox.Text = ""; rhythmTextBox.Text = ""; notesCountTextBox.Text = "16"; //Melody.Number = melodyList.Count + 1; generatedMelodysList = new List<Melody>(); gridButtons = new int[6, 16]; /* Гаммы можно менять, но их длина должна оставаться прежней. * В противном случае, нужно произвести изменения в файле MyRandom.cs */ minorScale = new int[7] { 2, 1, 2, 2, 1, 2, 2 }; majorScale = new int[7] { 2, 2, 1, 2, 2, 2, 1 }; flamencoScale = new int[7] { 1, 3, 1, 2, 1, 3, 1 }; bluesScale = new int[] { 3, 2, 1, 1, 3, 2 }; flamenco2Scale = new int[7] { 1, 3, 1, 2, 1, 2, 2 }; int[] scaleIntervals = minorScale; ScaleName scaleName = ScaleName.Minor; selectedScale = new MyScale(scaleName, scaleIntervals); tonica = Note.A3; scaleComboBox.SelectedIndex = 0; buttons = new Button[6, 16]; player = new MediaPlayer(); player.Volume = 0.3; outputDevice = ExampleUtil.ChooseOutputDeviceFromConsole(); outputDevice.Open(); outputDevice.SendProgramChange(Channel.Channel1, Instrument.AcousticGuitarSteel); grifNotes = new Note[6, 16]; //Заполняем 6 струну for (int i = 0; i < grifNotes.GetLength(1); i++) { grifNotes[5, i] = (Note)(40 + i); } //Заполняем 5 струну for (int i = 0; i < grifNotes.GetLength(1); i++) { grifNotes[4, i] = (Note)(45 + i); } //Заполняем 4 струну for (int i = 0; i < grifNotes.GetLength(1); i++) { grifNotes[3, i] = (Note)(50 + i); } //Заполняем 3 струну for (int i = 0; i < grifNotes.GetLength(1); i++) { grifNotes[2, i] = (Note)(55 + i); } //Заполняем 2 струну for (int i = 0; i < grifNotes.GetLength(1); i++) { grifNotes[1, i] = (Note)(59 + i); } //Заполняем 1 струну for (int i = 0; i < grifNotes.GetLength(1); i++) { grifNotes[0, i] = (Note)(64 + i); } int tabindex = 4; for (int i = 0; i < 6; i++) { for (int j = 0; j < 16; j++) { buttons[i, j] = (Button)this.Controls["s" + (i + 1).ToString() + j.ToString()]; buttons[i, j].TabIndex = tabindex; tabindex++; } } //Создание надписей над аппликатурой labels = new Label[6, 16]; this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); for (int i = 0; i < 6; i++) { for (int j = 0; j < 16; j++) { labels[i, j] = new Label(); labels[i, j].AutoSize = true; labels[i, j].Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204))); labels[i, j].ForeColor = System.Drawing.Color.Black; Point p = new Point(); p.X = buttons[i, j].Location.X;// +buttons[i, j].Width / 2; p.Y = buttons[i, j].Location.Y; labels[i, j].Location = p; labels[i, j].Name = "label" + i.ToString() + j.ToString(); labels[i, j].Size = new System.Drawing.Size(15, 13); //labels[i, j].TabIndex = 113; labels[i, j].Text = "T"; labels[i, j].Visible = false; labels[i, j].BackColor = System.Drawing.Color.Transparent; this.Controls.Add(labels[i, j]); labels[i, j].BringToFront(); } } for (int j = 0; j < 6; j++) { for (int k = 0; k < 16; k++) { buttons[j, k].Click += grif_Click; } } }
/// <summary> /// Constructs a Note Off message. /// </summary> /// <param name="device">The device associated with this message.</param> /// <param name="channel">Channel, 0..15, 10 reserved for percussion.</param> /// <param name="note">Note, 0..127, middle C is 60.</param> /// <param name="velocity">Velocity, 0..127.</param> /// <param name="beatTime">Milliseconds since the music started.</param> public NoteOffMessage(DeviceBase device, Channel channel, Note note, int velocity, float beatTime) : base(device, channel, note, velocity, beatTime) { }
/// <summary> /// Returns the note that would name this pitch if it used the given letter. /// </summary> /// <param name="pitch">The pitch being named.</param> /// <param name="letter">The letter to use in the name, in ['A'..'G'].</param> /// <returns>The note for pitch with letter. The result may have a large number of /// accidentals if pitch is not easily named by letter.</returns> /// <exception cref="ArgumentOutOfRangeException">letter is out of range.</exception> public static Note NoteWithLetter(this Pitch pitch, char letter) { if (letter < 'A' || letter > 'G') { throw new ArgumentOutOfRangeException(); } Note pitchNote = pitch.NotePreferringSharps(); Note letterNote = new Note(letter); int upTo = letterNote.SemitonesUpTo(pitchNote); int downTo = letterNote.SemitonesDownTo(pitchNote); if (upTo <= downTo) { return new Note(letter, upTo); } else { return new Note(letter, -downTo); } }
private void btnCreate_Click(object sender, RoutedEventArgs e) { // scale mode? if (!(bool)chkScaleMode.IsChecked) currentScaleNoteIndex = 0; // otherwise, create a cube that matches the specifications we just set Cube cube = new NullCube(Engine.Engine.Origin, 0); // yank values from comboboxes n shit Note note = new Note((string)((ComboBoxItem)cmbNote.SelectedItem).Content); int octave = int.Parse((string)((ComboBoxItem)cmbOctave.SelectedItem).Content); ChordPattern chordPattern = Chord.Major; ScalePattern scalePattern = Scale.Major; switch ((string)((ComboBoxItem)cmbScale.SelectedItem).Content) { case "Major": scalePattern = Scale.Major; break; case "HarmonicMinor": scalePattern = Scale.HarmonicMinor; break; case "MelodicMinorAscending": scalePattern = Scale.MelodicMinorAscending; break; case "MelodicMinorDescending": scalePattern = Scale.MelodicMinorDescending; break; case "NaturalMinor": scalePattern = Scale.NaturalMinor; break; } switch ((string)((ComboBoxItem)cmbChordType.SelectedItem).Content) { case "Major": chordPattern = Chord.Major; break; case "Minor": chordPattern = Chord.Minor; break; case "Seventh": chordPattern = Chord.Seventh; break; case "Augmented": chordPattern = Chord.Augmented; break; case "Diminished": chordPattern = Chord.Diminished; break; } Scale scale = new Scale(note, scalePattern); // scalemode translation note = scale.NoteSequence[currentScaleNoteIndex++ % 7]; Pitch pitch = note.PitchInOctave(octave); int chordInversion = int.Parse((string)((ComboBoxItem)cmbInversion.SelectedItem).Content); Chord chord = new Chord(note, chordPattern, chordInversion); // single note cube if ((bool)Note.IsChecked) { cube = new SingleNoteCube(Engine.Engine.Origin, _Constants.CreateHandDistance / 2.0, pitch, CurrentInstrument, App.OutputDevice, CurrentChannel); } if ((bool)Chord2.IsChecked) { cube = new ChordCube(Engine.Engine.Origin, _Constants.CreateHandDistance / 2.0, chord, octave, CurrentInstrument, App.OutputDevice, CurrentChannel); } // give the cube a random colour Random randomGen = new Random(); KnownColor[] names = (KnownColor[])Enum.GetValues(typeof(KnownColor)); KnownColor randomColorName = names[randomGen.Next(names.Length)]; System.Drawing.Color tempColor = System.Drawing.Color.FromKnownColor(randomColorName); System.Windows.Media.Color randomColor = System.Windows.Media.Color.FromArgb(tempColor.A, tempColor.R, tempColor.G, tempColor.B); cube.SolidColorBrush.Color = randomColor; // now set the engine to create mode, and assign this as the cube to be created App.Engine.SetCreateCube(cube); }
/// <summary> /// Constructs a chord from a string. /// </summary> /// <param name="name">The name to parse. This is the same format as the Name property: /// a letter in ['A'..'G'], an optional series of accidentals (#'s or b's), then an /// optional inversion specified as a '/' followed by another note name. If the /// inversion is present it must be one of the notes in the chord.</param> /// <exception cref="ArgumentNullException">name is null.</exception> /// <exception cref="ArgumentException">cannot parse a chord from name.</exception> public Chord(string name) { if (name == null) { throw new ArgumentNullException("name is null."); } if (name.Length == 0) { throw new ArgumentException("name is empty."); } int pos = 0; this.root = Note.ParseNote(name, ref pos); this.pattern = null; foreach (ChordPattern p in Chord.Patterns) { if (pos + p.Abbreviation.Length > name.Length) { continue; } if (String.Compare(name, pos, p.Abbreviation, 0, p.Abbreviation.Length) != 0) { continue; } if (pos + p.Abbreviation.Length == name.Length || name[pos+p.Abbreviation.Length] == '/') { pos += p.Abbreviation.Length; this.pattern = p; break; } } if (this.pattern == null) { throw new ArgumentException("name does not match a known chord pattern."); } // At this point, we know the note and pattern (but not yet the inversion). Build // the chord prior to inversion. this.positionInOctaveToContains = new bool[12]; Note[] uninvertedSequence = new Note[pattern.Ascent.Length]; Build(root, pattern, this.positionInOctaveToContains, uninvertedSequence); this.noteSequence = new Note[pattern.Ascent.Length]; // Now see if there's an inversion. this.inversion = 0; if (pos < name.Length) { if (name[pos] != '/') { throw new ArgumentException(String.Format("unexpected character '{0}' in name.", name[pos])); } pos++; Note bass = Note.ParseNote(name, ref pos); if (name.Length > pos) { throw new ArgumentException(String.Format("unexpected character '{0}' in name.", name[pos])); } this.inversion = Array.IndexOf(uninvertedSequence, bass); if (inversion == -1) { throw new ArgumentException("invalid bass note for inversion."); } } RotateArrayLeft(uninvertedSequence, this.noteSequence, inversion); }
/// <summary> /// Returns the number of semitones it takes to move down to the next otherNote. /// </summary> /// <param name="otherNote">The other note.</param> /// <returns>The number of semitones.</returns> public int SemitonesDownTo(Note otherNote) { int semitoneDelta = positionInOctave - otherNote.positionInOctave; if (semitoneDelta < 0) { semitoneDelta += 12; } return semitoneDelta; }
/// <summary> /// Constructs a Note On/Off message. /// </summary> /// <param name="device">The device associated with this message.</param> /// <param name="channel">Channel, 0..15, 10 reserved for percussion.</param> /// <param name="note">Note, 0..127, middle C is 60.</param> /// <param name="velocity">Velocity, 0..127.</param> /// <param name="beatTime">Milliseconds since the music started.</param> /// <param name="duration">Milliseconds of duration.</param> public NoteOnOffMessage(DeviceBase device, Channel channel, Note note, int velocity, float beatTime, float duration) : base(device, channel, note, velocity, beatTime) { this.duration = duration; }
/// <summary> /// If the specified key is one of the computer keys used for mock MIDI input, returns true /// and sets note to the value. /// </summary> /// <param name="key">The computer key pressed.</param> /// <param name="note">The note it mocks.</param> /// <returns></returns> public static bool IsMockNote(ConsoleKey key, out Note note) { if (mockKeys.ContainsKey(key)) { note = (Note)mockKeys[key]; return true; } note = 0; return false; }
/// <summary> /// Constructs a scale from its tonic and its pattern. /// </summary> /// <param name="tonic">The tonic note.</param> /// <param name="pattern">The scale pattern.</param> /// <exception cref="ArgumentNullException">tonic or pattern is null.</exception> public Scale(Note tonic, ScalePattern pattern) { if (tonic == null || pattern == null) { throw new ArgumentNullException(); } this.tonic = tonic; this.pattern = pattern; this.positionInOctaveToSequenceIndex = new int[12]; this.noteSequence = new Note[pattern.Ascent.Length]; int numAccidentals; Build(this.tonic, this.pattern, this.positionInOctaveToSequenceIndex, this.noteSequence, out numAccidentals); }
/// <summary> /// Constructs a chord from its root note, pattern, and inversion. /// </summary> /// <param name="root">The root note of the chord.</param> /// <param name="pattern">The chord pattern.</param> /// <param name="inversion">The inversion, in [0..N-1] where N is the number of notes /// in pattern.</param> /// <exception cref="ArgumentNullException">pattern is null.</exception> /// <exception cref="ArgumentOutOfRangeException">inversion is out of range.</exception> public Chord(Note root, ChordPattern pattern, int inversion) { if (pattern == null) { throw new ArgumentNullException(); } if (inversion < 0 || inversion >= pattern.Ascent.Length) { throw new ArgumentOutOfRangeException("inversion out of range."); } this.root = root; this.pattern = pattern; this.inversion = inversion; this.positionInOctaveToContains = new bool[12]; Note[] uninvertedSequence = new Note[pattern.Ascent.Length]; Build(root, pattern, this.positionInOctaveToContains, uninvertedSequence); this.noteSequence = new Note[pattern.Ascent.Length]; RotateArrayLeft(uninvertedSequence, this.noteSequence, inversion); }
/// <summary> /// Builds a scale. /// </summary> /// <param name="tonic">The tonic.</param> /// <param name="pattern">The scale pattern.</param> /// <param name="positionInOctaveToSequenceIndex">Must have 12 elements, and is filled with /// the 0-indexed scale position (or -1) for each position in the octave.</param> /// <param name="noteSequence">Must have pattern.Ascent.Length elements, and is filled with /// the notes for each scale degree.</param> /// <param name="numAccidentals">Filled with the total number of accidentals in the built /// scale.</param> private static void Build(Note tonic, ScalePattern pattern, int[] positionInOctaveToSequenceIndex, Note[] noteSequence, out int numAccidentals) { numAccidentals = 0; for (int i = 0; i < 12; ++i) { positionInOctaveToSequenceIndex[i] = -1; } Pitch tonicPitch = tonic.PitchInOctave(0); for (int i = 0; i < pattern.Ascent.Length; ++i) { Pitch pitch = tonicPitch + pattern.Ascent[i]; Note note; if (pattern.Ascent.Length == 7) { char letter = (char)(i + (int)(tonic.Letter)); if (letter > 'G') { letter = (char)((int)letter - 7); } note = pitch.NoteWithLetter(letter); } else { note = pitch.NotePreferringSharps(); } noteSequence[i] = note; positionInOctaveToSequenceIndex[pitch.PositionInOctave()] = i; } }
private static void Build(Note root, ChordPattern pattern, bool[] positionInOctaveToContains, Note[] noteSequence) { for (int i = 0; i < 12; ++i) { positionInOctaveToContains[i] = false; } Pitch rootPitch = root.PitchInOctave(0); for (int i = 0; i < pattern.Ascent.Length; ++i) { Pitch pitch = rootPitch + pattern.Ascent[i]; char letter = (char)(pattern.LetterOffsets[i] + (int)(root.Letter)); while (letter > 'G') { letter = (char)((int)letter - 7); } noteSequence[i] = pitch.NoteWithLetter(letter); positionInOctaveToContains[pitch.PositionInOctave()] = true; } }
/// <summary> /// Returns the sequence of notes generated by this scale when moving from start to finish. /// </summary> /// <param name="start">The first note in the traversal.</param> /// <param name="finish">The last note in the traversal.</param> /// <returns>The sequence of notes. The result always includes start and finish, and then /// includes whichever intervening notes are implied by scale when moving in that direction. /// </returns> /// <exception cref="ArgumentOutOfRangeException">start or finish is out-of-range. /// </exception> public List<Note> Traverse(Note start, Note finish) { start.Validate(); finish.Validate(); List<Note> result = new List<Note>(); if (finish > start) { for (Note n = start; n <= finish; ++n) { if (n == start || n == finish || ContainsWhenAscending(n)) result.Add(n); } } else if (finish < start) { for (Note n = start; n >= finish; --n) { if (n == start || n == finish || ContainsWhenDescending(n)) result.Add(n); } } else { result.Add(start); } return result; }