| | 1 | | using System; |
| | 2 | | using System.Collections.Generic; |
| | 3 | |
|
| | 4 | | namespace MusicTheory.Theory.Pitch |
| | 5 | | { |
| | 6 | |
|
| | 7 | | // 変換ユーティリティ(綴り→pc、Pitch↔MIDI) |
| | 8 | | public static class PitchUtils |
| | 9 | | { |
| | 10 | | // C=0, D=2, E=4, F=5, G=7, A=9, B=11 を基準に綴り→pc |
| 118 | 11 | | public static int LetterBasePc(Letter l) => l switch { Letter.C => 0, Letter.D => 2, Letter.E => 4, Letter.F => |
| 27 | 12 | | public static PitchClass ToPc(SpelledPitch s) => new(LetterBasePc(s.Letter) + s.Acc.AccidentalValue); |
| 23 | 13 | | public static PitchClass ToPc(Pitch p) => ToPc(p.Spelling); |
| | 14 | |
|
| | 15 | | // MIDI は C-1=0 とし、綴りのオクターブ系を MIDI に投影 |
| | 16 | | public static int ToMidi(Pitch p) |
| | 17 | | { |
| | 18 | | // 例: C4=60(慣習) |
| 16 | 19 | | int octaveOffset = (p.Octave + 1) * 12; |
| 16 | 20 | | return octaveOffset + ToPc(p).Pc; |
| | 21 | | } |
| | 22 | | public static Pitch FromMidi(int midi, SpelledPitch prefer = default, int? preferOctave = null) |
| | 23 | | { |
| | 24 | | // 初期版: 等音→簡易綴り(黒鍵は♯寄り)で復元 |
| 5 | 25 | | int pc = ((midi % 12) + 12) % 12; |
| 5 | 26 | | var (letter, acc) = pc switch |
| 5 | 27 | | { |
| 1 | 28 | | 0 => (Letter.C, 0), |
| 2 | 29 | | 1 => (Letter.C, 1), |
| 0 | 30 | | 2 => (Letter.D, 0), |
| 1 | 31 | | 3 => (Letter.D, 1), |
| 0 | 32 | | 4 => (Letter.E, 0), |
| 1 | 33 | | 5 => (Letter.F, 0), |
| 0 | 34 | | 6 => (Letter.F, 1), |
| 0 | 35 | | 7 => (Letter.G, 0), |
| 0 | 36 | | 8 => (Letter.G, 1), |
| 0 | 37 | | 9 => (Letter.A, 0), |
| 0 | 38 | | 10 => (Letter.A, 1), |
| 0 | 39 | | 11 => (Letter.B, 0), |
| 0 | 40 | | _ => (Letter.C, 0) |
| 5 | 41 | | }; |
| 5 | 42 | | int oct = (midi / 12) - 1; |
| 5 | 43 | | return new Pitch(new SpelledPitch(letter, new Accidental(acc)), preferOctave ?? oct); |
| | 44 | | } |
| | 45 | |
|
| | 46 | |
|
| | 47 | | //複音程 |
| | 48 | |
|
| | 49 | | public static Pitch Transpose(Pitch p, MusicTheory.Theory.Interval.SemitoneInterval ivl) |
| 2 | 50 | | => FromMidi(ToMidi(p) + ivl.Semitones); |
| | 51 | | public static PitchClass Transpose(PitchClass pc, MusicTheory.Theory.Interval.SemitoneInterval ivl) |
| 1 | 52 | | => new PitchClass(pc.Pc + ivl.Semitones); |
| | 53 | |
|
| | 54 | |
|
| | 55 | | //異名同音の表記 |
| | 56 | | public static IEnumerable<SpelledPitch> GetEnharmonicSpellings(PitchClass pc) |
| | 57 | | { |
| 61 | 58 | | foreach (Letter l in Enum.GetValues(typeof(Letter))) |
| | 59 | | { |
| 25 | 60 | | int basePc = LetterBasePc(l); |
| 25 | 61 | | int acc = pc.Pc - basePc; |
| 25 | 62 | | if (acc >= -3 && acc <= 3) |
| 12 | 63 | | yield return new SpelledPitch(l, new Accidental(acc)); |
| | 64 | | } |
| 0 | 65 | | } |
| | 66 | | } |
| | 67 | |
|
| | 68 | | } |