/// <summary> /// 화음 전이를 일으키면서 새 화음의 음들을 재생합니다. /// 확률적으로 연주 속도가 변할 수 있습니다. /// </summary> /// <returns></returns> private static void PlayChordTransition() { // ChordingCoding에서 공백 문자를 입력할 때 호출됨 if (!HasStart) { return; } int pitch; StopPlaying(0); chord = new Chord(SFXTheme.CurrentSFXTheme.ChordTransition, chord); pitch = chord.NextNote(); syncPlayBuffer = new List <Note>(); Random r = new Random(); if (r.Next(0, 27) > 0) { // TPS 29 기준으로 한 마디에 한 번씩 시도할 때 1분에 한 번 꼴로 발생하는 확률로 채널(staff) 0의 악기를 재생하지 않음 SFXTheme.InstrumentInfo ii = SFXTheme.CurrentSFXTheme.Instruments[0]; foreach (int p in chord.NotesInChord()) { if (p != pitch) { PlayANoteSync(ii.whitespacePitchModulator(p), ii.whitespaceVolume, ii.whitespaceRhythm, 0); } } } foreach (KeyValuePair <int, SFXTheme.InstrumentInfo> pair in SFXTheme.CurrentSFXTheme.Instruments) { if (pair.Value.whitespaceVolume > 0 && pair.Key > 1) { PlayANoteSync(pair.Value.whitespacePitchModulator(pitch), pair.Value.whitespaceVolume, pair.Value.whitespaceRhythm, pair.Key); } } // 빠르기 변경 SetTickPerSecond((int)TICK_PER_SECOND + (int)(1f * Math.Round(Util.GaussianRandom(r), MidpointRounding.AwayFromZero))); OnChordTransition?.Invoke(pitch); }
/// <summary> /// 리듬에 맞게 음표를 재생합니다. /// tickDelegate에 의해 1초에 32번씩 자동으로 호출됩니다. /// </summary> private static void Tick() { if (!HasStart) { return; } //Score.NoteOff(outDevice); Score.NoteOff(syn); void TickPlay(object[] args) { // 지속 효과음이 멈추는 것을 대비하여 if (SFXTheme.CurrentSFXTheme.Instruments.ContainsKey(5) && SFXTheme.CurrentSFXTheme.Instruments.ContainsKey(6)) { if (tickNumber % ((int)TICK_PER_SECOND * 10) == 0) { StopPlaying(5); SFXTheme.InstrumentInfo inst = SFXTheme.CurrentSFXTheme.Instruments[5]; Note note = new Note(inst.sfxPitchModulator(45), inst.sfxVolume, inst.sfxRhythm * 64 * 60, Measure, Position, 5); // 음표를 3840배 길게 늘여서 재생 //Score.PlayANoteForever(outDevice, note, (int)Math.Round(inst.sfxVolume * (SFXTheme.CurrentSFXTheme.Volume / 100D))); // 기본 빗소리 (사라지지 않아야 함) Score.PlayANote(syn, note, SFXTheme.CurrentSFXTheme.Volume / 100f); } if (tickNumber % ((int)TICK_PER_SECOND * 10) == (int)TICK_PER_SECOND * 5) { StopPlaying(6); SFXTheme.InstrumentInfo inst = SFXTheme.CurrentSFXTheme.Instruments[6]; Note note = new Note(inst.sfxPitchModulator(45), inst.sfxVolume, inst.sfxRhythm * 64 * 60, Measure, Position, 6); // 음표를 3840배 길게 늘여서 재생 //Score.PlayANoteForever(outDevice, note, (int)Math.Round(inst.sfxVolume * (SFXTheme.CurrentSFXTheme.Volume / 100D))); // 기본 빗소리 (사라지지 않아야 함) Score.PlayANote(syn, note, SFXTheme.CurrentSFXTheme.Volume / 100f); } } for (int staff = 7; staff <= 8; staff++) { if (SFXTheme.CurrentSFXTheme.Instruments.ContainsKey(staff)) { if (accompanimentTickNumber[staff] >= Accompaniment.currentPatterns[staff].length) { accompanimentPlayNumber[staff]++; if (accompanimentPlayNumber[staff] >= Accompaniment.currentPatterns[staff].iteration) { Accompaniment.SetNewCurrentPattern(staff); accompanimentPlayNumber[staff] = 0; } else { Score.Play(Accompaniment.currentPatterns[staff].score, "Accompaniment", SFXTheme.CurrentSFXTheme.Instruments[staff].accompanimentVolume / 127f); } accompanimentTickNumber[staff] = 0; } Score accompaniment = Accompaniment.currentPatterns[staff].score; /* * // 64분음표 단위로 음을 하나씩 재생 * long measure = accompanimentTickNumber[staff] / 64; * int position = accompanimentTickNumber[staff] % 64; * if (SFXTheme.CurrentSFXTheme.Instruments.ContainsKey(staff)) * { * accompaniment.PlayEnumerable(syn, measure, position, staff, * (int)Math.Round(SFXTheme.CurrentSFXTheme.Instruments[staff].accompanimentVolume * (SFXTheme.CurrentSFXTheme.Volume / 100D))); * * } */ accompanimentTickNumber[staff]++; } else { accompanimentTickNumber[staff] = 0; } } // 자동 반주 악보에 대해서만, 자동 반주가 꺼지면 음량이 0이 되도록 float volumeChanger(string scoreClassName) { switch (scoreClassName) { case "Accompaniment": float accompVolume = 1f; if (!SFXTheme.CurrentSFXTheme.hasAccompanied) { accompVolume = 0f; } return(SFXTheme.CurrentSFXTheme.Volume / 100f * accompVolume); default: return(SFXTheme.CurrentSFXTheme.Volume / 100f); } } // Play()로 재생 목록에 넣은 악보들을 재생 Score.PlayPerTick(syn, volumeChanger); } Util.TaskQueue.Add("play", TickPlay); if (tickNumber % 64 == 0 && (SFXTheme.CurrentSFXTheme.Instruments.ContainsKey(7) || SFXTheme.CurrentSFXTheme.Instruments.ContainsKey(8)) && SFXTheme.CurrentSFXTheme.hasAccompanied) { syncTransitionBuffer = false; PlayChordTransition(); } else if (syncTransitionBuffer && tickNumber % 32 == 0) { syncTransitionBuffer = false; PlayChordTransition(); } // 동기화된 박자(최소 리듬 단위)에 맞춰 버퍼에 저장되어 있던 음표 재생 if (NoteResolution > 0 && tickNumber % NoteResolution == 0 && syncPlayBuffer.Count > 0) { FlushSyncPlayBuffer(); } //SoundPipeline(buffer); void IncreaseTick(object[] args) { tickNumber++; } Util.TaskQueue.Add("play", IncreaseTick); }