/// <summary> /// 이 클래스가 작동하기 위해서는 /// Initialize()가 호출된 후에 반드시 호출되어야 합니다. /// </summary> public static void Start() { if (IsReady && !HasStart) { timerNumber = 0; timer = new Timer(1, TickTimer); Accompaniment.Start(); HasStart = true; ThemeChanged(); new Test.SFXTest(); // Run some tests. } }
/// <summary> /// 자동 반주의 상태를 초기화합니다. /// 이것을 호출하는 함수는 반드시 이 함수 호출을 "play"라는 lockName의 Util.TaskQueue 함수 안에서 수행해야 합니다. /// </summary> private static void ResetAccompaniment() { if (SFXTheme.IsReady) { for (int staff = 7; staff <= 8; staff++) { if (SFXTheme.CurrentSFXTheme.Instruments.ContainsKey(staff)) { Accompaniment.SetNewCurrentPattern(staff); accompanimentPlayNumber[staff] = 0; accompanimentTickNumber[staff] = 0; } } } }
/// <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); }
/// <summary> /// 음악 출력 장치와 타이머를 초기화하고, 현재 음악 테마를 SFXThemeName으로 설정합니다. /// </summary> /// <param name="SFXThemeName">설정할 음악 테마 이름</param> /// <param name="noteResolution">단위 리듬</param> /// <param name="timerTickDelegates">타이머의 틱마다 추가로 실행할 메서드의 대리자 목록</param> public static void Initialize(string SFXThemeName, int noteResolution, Timer.TickDelegate[] timerTickDelegates = null) { IsReady = false; HasStart = false; //outDevice = new OutputDevice(0); settings = new Settings(); settings[ConfigurationKeys.SynthAudioChannels].IntValue = 2; syn = new Synth(settings); try { syn.LoadSoundFont("FluidR3_GM.sf2", true); } catch (FileNotFoundException e) { Console.WriteLine(e.StackTrace); return; } for (int i = 0; i < 16; i++) { syn.SoundFontSelect(i, 0); } adriver = new AudioDriver(syn.Settings, syn); /* * WaveInEvent recorder = new WaveInEvent * { * WaveFormat = new WaveFormat(44100, 2) * }; * BufferedWaveProvider sound = new BufferedWaveProvider(recorder.WaveFormat); * recorder.DataAvailable += (object sender, WaveInEventArgs e) => * { * sound.AddSamples(e.Buffer, 0, e.BytesRecorded); * }; * recorder.StartRecording(); * //sound.Read(); */ //playback = new WaveOutEvent(); //playback.Init(sound); //playback.Play(); /* * sound = new BufferedWaveProvider(new WaveFormat(44100, 2)); * buffer = new byte[44100 * 4]; * stream = new MemoryStream(); * Task.Run(() => { * soundStream = new RawSourceWaveStream(stream, new WaveFormat(44100, 2)); * reverb = new DmoEffectWaveProvider<DmoWavesReverb, DmoWavesReverb.Params>(soundStream); * outputDevice = new WasapiOut(); * * outputDevice.Init(reverb); * outputDevice.Play(); * }); */ SFXTheme.CurrentSFXTheme = SFXTheme.FindSFXTheme(SFXThemeName); //Console.WriteLine(SFXThemeName + " " + SFXTheme.CurrentSFXTheme.Name); NoteResolution = noteResolution; Accompaniment.Initialize(); tickDelegate += Tick; if (timerTickDelegates != null) { foreach (Timer.TickDelegate t in timerTickDelegates) { tickDelegate += t; } } mgmt = new PowerManagement(); mgmt.InitPowerEvents(); mgmt.OnPowerSuspend += Suspend; mgmt.OnPowerResume += Resume; syncPlayBuffer = new List <Note>(); syncTransitionBuffer = false; playPitchEventBuffer = new List <int>(); accompanimentTickNumber = new Dictionary <int, int>(); accompanimentPlayNumber = new Dictionary <int, int>(); accompanimentTickNumber.Add(7, 0); accompanimentTickNumber.Add(8, 0); accompanimentPlayNumber.Add(7, 0); accompanimentPlayNumber.Add(8, 0); IsReady = true; /* * Task.Run(() => * { * var capture = new WasapiLoopbackCapture(); * var effectProvider = new DmoEffectWaveProvider<DmoWavesReverb, DmoWavesReverb.Params>(new WaveInProvider(capture)); * * PlayEffectorSound(capture, effectProvider); * using (var outputDevice = new WasapiOut()) * { * outputDevice.Init(effectProvider); * capture.StartRecording(); * outputDevice.Play(); * while (capture.CaptureState != NAudio.CoreAudioApi.CaptureState.Stopped) * { * Thread.Sleep(500); * if (!IsReady) capture.StopRecording(); * } * Console.WriteLine("Effector stopped"); * } * * }); */ }