public static void Encode(string file) { if (File.Exists(file)) { var encoderLAME = new EncoderLAME(0) { LAME_Bitrate = (int)EncoderLAME.BITRATE.kbps_192, LAME_Mode = EncoderLAME.LAMEMode.Default, LAME_Quality = EncoderLAME.LAMEQuality.Quality }; var resp = BaseEncoder.EncodeFile( inputFile: file, outputFile: file + "_small.mp3", encoder: encoderLAME, proc: null, overwriteOutput: true, deleteInput: false, updateTags: false, fromPos: 5.0f, toPos: 10.0f ); var e = Bass.BASS_ErrorGetCode(); Console.WriteLine(resp); Console.WriteLine(e); } }
private void buttonStartRec_Click(object sender, System.EventArgs e) { this.buttonStartRec.Enabled = false; this.labelRec.Text = "Recording..."; // start recording paused _myRecProc = new RECORDPROC(MyRecoring); _recHandle = Bass.BASS_RecordStart(44100, 2, BASSFlag.BASS_RECORD_PAUSE, _myRecProc, new IntPtr(_encHandle)); // needs 'lame.exe' ! // the recorded data will be written to a file called rectest.mp3 // create the encoder...192kbps, stereo // MP3 encoder setup lame = new EncoderLAME(_recHandle); lame.InputFile = null; //STDIN lame.OutputFile = "rectest.mp3"; lame.LAME_Bitrate = (int)EncoderLAME.BITRATE.kbps_192; lame.LAME_Mode = EncoderLAME.LAMEMode.Default; lame.LAME_TargetSampleRate = (int)EncoderLAME.SAMPLERATE.Hz_44100; lame.LAME_Quality = EncoderLAME.LAMEQuality.Quality; monBuffer.Clear(); checkBoxMonitor.Checked = false; // create a live recording WaveForm WF = new WaveForm(); WF.FrameResolution = 0.01f; // 10ms are nice // start a live recording waveform with 5sec. init size and 2sec. next size WF.RenderStartRecording(_recHandle, 5f, 2f); // really start recording lame.Start(null, IntPtr.Zero, false); Bass.BASS_ChannelPlay(_recHandle, false); }
/// <summary> /// Create a new recording with custom settings /// </summary> /// <param name="strFileName">File Name</param> /// <param name="samplerate">Sample rate</param> /// <param name="channels">Channels</param> /// <param name="bitrate">Bitrate</param> /// <param name="stereomode">Stereo mode</param> public PodcasterRecording(string strFileName, int samplerate, int channels, int bitrate, StereoMode stereomode) { if (!strFileName.ToLower().EndsWith(".mp3")) { // TODO: implement other codecs throw new Exception("Currently, Podcaster only works with MP3 files"); } _myRecProc = new RECORDPROC(RecordAudio); _recHandle = Bass.BASS_RecordStart(samplerate, channels, BASSFlag.BASS_RECORD_PAUSE, _myRecProc, IntPtr.Zero); lame = new EncoderLAME(_recHandle); lame.InputFile = null; lame.OutputFile = strFileName; lame.LAME_Bitrate = bitrate; switch (stereomode) { case StereoMode.JointStereo: lame.LAME_Mode = EncoderLAME.LAMEMode.JointStereo; break; case StereoMode.Mono: lame.LAME_Mode = EncoderLAME.LAMEMode.Mono; break; default: lame.LAME_Mode = EncoderLAME.LAMEMode.Stereo; break; } lame.LAME_TargetSampleRate = samplerate; lame.LAME_Quality = EncoderLAME.LAMEQuality.Quality; }
private void CallLameEncoder(EncoderLAME lameEncoder) { Process pProcess = new System.Diagnostics.Process(); pProcess.StartInfo.CreateNoWindow = true; string lamePath = lameEncoder.EncoderCommandLine.Split(' ')[0]; pProcess.StartInfo.FileName = lamePath; string commandArguments = lameEncoder.EncoderCommandLine.Replace(lamePath, string.Empty); pProcess.StartInfo.Arguments = commandArguments; pProcess.StartInfo.UseShellExecute = false; pProcess.StartInfo.RedirectStandardOutput = true; pProcess.StartInfo.WorkingDirectory = Dukebox.Audio.Properties.Settings.Default.lameEncoderPath; pProcess.Start(); //Get program output string strOutput = pProcess.StandardOutput.ReadToEnd(); logger.Info("Output from lame encoding: " + strOutput); pProcess.WaitForExit(); }
public async void SaveToFile(string file, Action finished) { await Task.Factory.StartNew(() => { //从文件中读取解码流 int strm = Bass.BASS_StreamCreateFile(_file, 0, 0, BASSFlag.BASS_STREAM_DECODE); //从strm解码流中创建FX效果器 strm = BassFx.BASS_FX_TempoCreate(strm, BASSFlag.BASS_STREAM_DECODE); //为效果器设置参数 Pitch&Speed if (_Pitch != -1024) { Bass.BASS_ChannelSetAttribute(strm, BASSAttribute.BASS_ATTRIB_TEMPO_PITCH, _Pitch); } if (_Speed != -1024) { Bass.BASS_ChannelSetAttribute(strm, BASSAttribute.BASS_ATTRIB_TEMPO, _Speed); } //初始化编码器 EncoderLAME l = new EncoderLAME(strm); l.InputFile = null; //STDIN l.OutputFile = file; //输出文件路径 l.LAME_Bitrate = (int)EncoderLAME.BITRATE.kbps_128; //比特率 l.LAME_Mode = EncoderLAME.LAMEMode.Default; //默认模式 l.LAME_Quality = EncoderLAME.LAMEQuality.Quality; //高品质 l.LAME_TargetSampleRate = (int)EncoderLAME.SAMPLERATE.Hz_44100; //44100码率 //解码流开始(并不是播放,也不会有声音输出) Bass.BASS_ChannelPlay(strm, false); //开始编码 l.Start(null, IntPtr.Zero, false); byte[] encBuffer = new byte[65536]; // our dummy encoder buffer while (Bass.BASS_ChannelIsActive(strm) == BASSActive.BASS_ACTIVE_PLAYING) { // getting sample data will automatically feed the encoder int len = Bass.BASS_ChannelGetData(strm, encBuffer, encBuffer.Length); } l.Stop(); // finish Bass.BASS_StreamFree(strm); finished(); }); }
/// <summary> /// Initialize MP3 encoding whith LAME /// </summary> /// <param name="_rechandle"></param> /// <returns></returns> private bool StartLameEncoding(int _rechandle) { /* Voir si en utilisant "lameEncoder.OutputFile = outFile" * on pourrait créer un fichier au lieu d'un buffer * */ _lameMemBuffer.Clear(); _LameEncProc = new ENCODEPROC(LameEncCallback); // Callback function lameEncoder = new EncoderLAME(_rechandle); if (lameEncoder.EncoderExists == false) { Console.Write("Encoder does not exists ?\r"); } lameEncoder.InputFile = null; //STDIN if (bSaveToDisk) { lameEncoder.OutputFile = strSaveFile; } else { lameEncoder.OutputFile = null; //STDOUT - adding file name will prevent the callback from working instead will saving to disk } lameEncoder.LAME_Bitrate = (int)EncoderLAME.BITRATE.kbps_64; lameEncoder.LAME_Mode = EncoderLAME.LAMEMode.Default; lameEncoder.LAME_Quality = EncoderLAME.LAMEQuality.Quality; bool bret = lameEncoder.Start(_LameEncProc, IntPtr.Zero, false); BASSError txt = Bass.BASS_ErrorGetCode(); Msg(txt.ToString()); return(bret); }
/// <summary> /// /// </summary> /// <param name="_fileName"></param> /// <returns></returns> public async Task ConvertCdaFileToMp3(string cdaFileName, string mp3OutFile, BaseEncoder.ENCODEFILEPROC progressCallback, bool overwriteOuputFile) { EncoderLAME lameEncoder = new EncoderLAME(0); lameEncoder.EncoderDirectory = Dukebox.Audio.Properties.Settings.Default.lameEncoderPath; lameEncoder.InputFile = cdaFileName; lameEncoder.OutputFile = Path.GetFullPath(mp3OutFile); await Task.Run(() => { // Extract cda file to wav file on disk. string wavFile = lameEncoder.OutputFile + ".wav"; try { WriteCdaFileToWavFile(lameEncoder.InputFile, wavFile, progressCallback); } catch (Exception ex) { if (lameEncoder.EncoderExists) { logger.ErrorFormat("Encoder result: failed\nLast BASS error: ", Bass.BASS_ErrorGetCode().ToString()); } logger.Error(ex); return; } // Call lame encoder with arguments. lameEncoder.InputFile = wavFile; CallLameEncoder(lameEncoder); // Clean up. File.Delete(wavFile); }); }
/// <summary> /// Start logging /// </summary> public void Start() { EncoderLAME lameEncoder = new EncoderLAME(recordingHandle); string location; // Determine location to save recording to if (WeeklyFolders == true) // If option to save into weekly folders is enabled { CultureInfo cultureInfo = CultureInfo.CurrentCulture; // Get system localisation information DayOfWeek firstDay = cultureInfo.DateTimeFormat.FirstDayOfWeek; // Determine first day of the week DateTime firstDayInWeek = DateTime.Now.Date; // Set to current date // Keep reducing date until the day is the same as the first day of the week while (firstDayInWeek.DayOfWeek != firstDay) { firstDayInWeek = firstDayInWeek.AddDays(-1); } DayOfWeek lastDay = firstDayInWeek.AddDays(-1).DayOfWeek; // Determine last day of the week DateTime lastDayInWeek = DateTime.Now.Date; // Set to current date // Keep reducing date until the day is the same as the first day of the week while (lastDayInWeek.DayOfWeek != lastDay) { lastDayInWeek = lastDayInWeek.AddDays(1); } // Set location location = Folder + "\\" + firstDayInWeek.ToString("dd-MM-yy") + " to " + lastDayInWeek.ToString("dd-MM-yy"); } else // If option to save into weekly folders is disabled { location = Folder; } // Create location if it does not exist if (!Directory.Exists(location)) { Directory.CreateDirectory(location); } // Set encoder settings lameEncoder.InputFile = null; // Set input to Stdout lameEncoder.OutputFile = location + "\\Log " + DateTime.Now.ToString("dd-MM-yy HH.mm") + ".mp3"; // Set output file lameEncoder.LAME_Bitrate = Bitrate; // Set bitrate lameEncoder.LAME_Mode = EncoderLAME.LAMEMode.Default; // Number of channels lameEncoder.LAME_TargetSampleRate = (int)EncoderLAME.SAMPLERATE.Hz_44100; // Sample rate lameEncoder.LAME_Quality = EncoderLAME.LAMEQuality.Quality; // Encoding quality // Set encoder location if (IntPtr.Size == 8) // If running in 64 bit { lameEncoder.EncoderDirectory = "x64"; } else // Else if running in 32 bit { lameEncoder.EncoderDirectory = "x86"; } if (!lameEncoder.EncoderExists) // If encoder has not been found, throw an exception { throw new FileNotFoundException("Unable to find encoder"); } // Start encoder encoder = lameEncoder; encoder.Start(null, IntPtr.Zero, false); CurrentStatus = Status.LOGGING; // Start timer currentHour = DateTime.Now.Hour; hourRecordingStarted = currentHour; timer.Start(); }
private void buttonStart_Click(object sender, System.EventArgs e) { asio = new BassAsioHandler(true, 0, 0, 2, BASSASIOFormat.BASS_ASIO_FORMAT_16BIT, 44100); // set a mirror on output channel 0 (for monitoring) asio.SetMirror(0); this.checkBoxMonitor.Checked = true; // start ASIO (actually starts recording/playing) BASS_ASIO_INFO info = BassAsio.BASS_ASIO_GetInfo(); bool ok = asio.Start(info.bufmax); if (!ok) { MessageBox.Show("Could not start ASIO : " + BassAsio.BASS_ASIO_ErrorGetCode().ToString()); } // now setup the encoder on the provided asio bass channel (which will be created by the above SetFullDuplex call) if (radioButtonLAME.Checked) { lame = new EncoderLAME(asio.InputChannel); lame.InputFile = null; //STDIN lame.OutputFile = "test.mp3"; lame.LAME_Bitrate = (int)EncoderLAME.BITRATE.kbps_128; lame.LAME_Mode = EncoderLAME.LAMEMode.Default; lame.LAME_Quality = EncoderLAME.LAMEQuality.Quality; lame.Start(null, IntPtr.Zero, false); enc = lame; } else if (radioButtonOGG.Checked) { ogg = new EncoderOGG(asio.InputChannel); ogg.InputFile = null; //STDIN ogg.OutputFile = "test.ogg"; ogg.OGG_UseQualityMode = true; ogg.OGG_Quality = 4.0f; ogg.Start(null, IntPtr.Zero, false); enc = ogg; } else if (radioButtonAAC.Checked) { aac = new EncoderNeroAAC(asio.InputChannel); aac.InputFile = null; //STDIN aac.OutputFile = "test.mp4"; aac.NERO_Bitrate = 64; aac.Start(null, IntPtr.Zero, false); enc = aac; } else if (radioButtonWAVE.Checked) { // writing 16-bit wave file here (even if we use a float asio channel) wav = new EncoderWAV(asio.InputChannel); wav.InputFile = null; // STDIN wav.OutputFile = "test.wav"; wav.Start(null, IntPtr.Zero, false); enc = wav; } this.buttonStart.Enabled = false; // display the level plm = new DSP_PeakLevelMeter(asio.InputChannel, 0); plm.UpdateTime = 0.1f; // 100ms plm.Notification += new EventHandler(plm_Notification); }
private void convertWorker_DoWork(object sender, DoWorkEventArgs e) { while (files.Count > 0) { Track t = files.First(); int convertStream = 20; if (!Program.mainWindow.LoadStream(t.filename, out convertStream, BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MUSIC_DECODE)) { continue; } if (Bass.BASS_ErrorGetCode() == 0 && t.length > 0) { EncoderLAME l = new EncoderLAME(convertStream); l.InputFile = null; string tryName = Path.GetFileNameWithoutExtension(t.filename) + ".mp3"; int num = 0; while (File.Exists(Path.Combine(outputPath, tryName))) { tryName = Path.GetFileNameWithoutExtension(t.filename) + "_" + num + ".mp3"; num++; } l.OutputFile = Path.Combine(outputPath, tryName); l.LAME_Bitrate = currentBitrate; l.LAME_Mode = EncoderLAME.LAMEMode.Default; l.LAME_Quality = EncoderLAME.LAMEQuality.Quality; //if(!Un4seen.Bass.AddOn.Tags.BassTags.BASS_TAG_GetFromFile(convertStream, l.TAGs)) Console.WriteLine("no tags"); l.TAGs = Un4seen.Bass.AddOn.Tags.BassTags.BASS_TAG_GetFromFile(t.filename); if (Bass.BASS_ErrorGetCode() != 0) { Console.WriteLine(Bass.BASS_ErrorGetCode()); } l.Start(null, IntPtr.Zero, false); byte[] encBuffer = new byte[65536]; while (Bass.BASS_ChannelIsActive(convertStream) == BASSActive.BASS_ACTIVE_PLAYING) { // getting sample data will automatically feed the encoder int len = Bass.BASS_ChannelGetData(convertStream, encBuffer, encBuffer.Length); convertWorker.ReportProgress((int)((float)Bass.BASS_ChannelGetPosition(convertStream) / (float)Bass.BASS_ChannelGetLength(convertStream) * 100)); if (convertWorker.CancellationPending) { break; } } l.Stop(); // finish Bass.BASS_StreamFree(convertStream); if (convertWorker.CancellationPending) { File.Delete(l.OutputFile); } } else { MessageBox.Show("Error converting: " + Bass.BASS_ErrorGetCode() + Environment.NewLine + t.filename); } if (convertWorker.CancellationPending) { break; } files.RemoveAt(0); convertList.Invoke((MethodInvoker) delegate { convertList.Items.RemoveAt(0); }); convertWorker.ReportProgress(0); } }
private BaseEncoder SetEncoderSettings(int stream) { BaseEncoder encoder = null; switch (_encoder) { case "mp3": EncoderLAME encLame = new EncoderLAME(stream); if (Options.MainSettings.RipLameExpert.Length > 0) { encLame.LAME_CustomOptions = Options.MainSettings.RipLameExpert; encLame.LAME_UseCustomOptionsOnly = true; } else { if (Options.MainSettings.RipLamePreset == (int)Options.LamePreset.ABR) encLame.LAME_PresetName = Options.MainSettings.RipLameABRBitRate.ToString(); else encLame.LAME_PresetName = Enum.GetName(typeof (Options.LamePreset), Options.MainSettings.RipLamePreset).ToLower(); } encoder = encLame; break; case "ogg": EncoderOGG encOgg = new EncoderOGG(stream); if (Options.MainSettings.RipOggExpert.Length > 0) { encOgg.OGG_CustomOptions = Options.MainSettings.RipOggExpert; encOgg.OGG_UseCustomOptionsOnly = true; } else { encOgg.OGG_Quality = Convert.ToInt32(Options.MainSettings.RipOggQuality); } encoder = encOgg; break; case "flac": EncoderFLAC encFlac = new EncoderFLAC(stream); if (Options.MainSettings.RipFlacExpert.Length > 0) { encFlac.FLAC_CustomOptions = Options.MainSettings.RipFlacExpert; encFlac.FLAC_UseCustomOptionsOnly = true; } else { encFlac.FLAC_CompressionLevel = Options.MainSettings.RipFlacQuality; } // put a 1k padding block for Tagging in front encFlac.FLAC_Padding = 1024; encoder = encFlac; break; case "m4a": EncoderFAAC encAAC = new EncoderFAAC(stream); int bitrate = Convert.ToInt32(Options.MainSettings.RipEncoderAACBitRate.Substring(0, Options.MainSettings. RipEncoderAACBitRate.IndexOf(' '))); encAAC.FAAC_Bitrate = bitrate; encAAC.FAAC_Quality = 100; encAAC.FAAC_UseQualityMode = true; encAAC.FAAC_WrapMP4 = true; encoder = encAAC; break; case "wav": EncoderWAV encWav = new EncoderWAV(stream); encoder = encWav; break; case "wma": EncoderWMA encWma = new EncoderWMA(stream); string[] sampleFormat = Options.MainSettings.RipEncoderWMASample.Split(','); string encoderFormat = Options.MainSettings.RipEncoderWMA; if (encoderFormat == "wmapro" || encoderFormat == "wmalossless") encWma.WMA_UsePro = true; else encWma.WMA_ForceStandard = true; if (Options.MainSettings.RipEncoderWMACbrVbr == "Vbr") { encWma.WMA_UseVBR = true; encWma.WMA_VBRQuality = Convert.ToInt32(Options.MainSettings.RipEncoderWMABitRate); } else encWma.WMA_Bitrate = Convert.ToInt32(Options.MainSettings.RipEncoderWMABitRate) / 1000; if (sampleFormat[0] == "24") encWma.WMA_Use24Bit = true; encoder = encWma; break; case "mpc": EncoderMPC encMpc = new EncoderMPC(stream); if (Options.MainSettings.RipEncoderMPCExpert.Length > 0) { encMpc.MPC_CustomOptions = Options.MainSettings.RipEncoderMPCExpert; encMpc.MPC_UseCustomOptionsOnly = true; } else { encMpc.MPC_Preset = (EncoderMPC.MPCPreset)Enum.Parse(typeof (EncoderMPC.MPCPreset), Options.MainSettings.RipEncoderMPCPreset); } encoder = encMpc; break; case "wv": EncoderWavPack encWv = new EncoderWavPack(stream); if (Options.MainSettings.RipEncoderWVExpert.Length > 0) { encWv.WV_CustomOptions = Options.MainSettings.RipEncoderWVExpert; encWv.WV_UseCustomOptionsOnly = true; } else { if (Options.MainSettings.RipEncoderWVPreset == "-f") encWv.WV_FastMode = true; else encWv.WV_HighQuality = true; } encoder = encWv; break; } return encoder; }
internal CUEConverter(EncoderLAME Lame, string FileName, List<TrackDescriptor> Cues, string Outdir, string TempDir) { _Lame = Lame; _Cues = Cues; _TempDir = TempDir; _FileName = new FileChecker(FileName, _TempDir); _FileName.Temporize(); _Output = Outdir; }
internal SimpleConverter(EncoderLAME Lame, string FileName, string Outdir, string TempDir) { _FileName = new FileChecker(FileName, TempDir); _Lame = Lame; _FileName.Temporize(); _Lame.InputFile = _FileName.ToBeConsidered; if (!Directory.Exists(Outdir)) throw new InvalidDataException("Should provide a valid folder."); string FinalName = FileInternalToolBox.CreateNewAvailableName(Outdir, Path.GetFileNameWithoutExtension(_FileName.Desired), FileServices.MP3); _Out = new FileChecker(FinalName, TempDir); _Lame.OutputFile = _Out.ToBeConsidered; }
private EncoderLAME GetLameEndoder(int stream = 0) { EncoderLAME Lame = new EncoderLAME(stream); Lame.LAME_Bitrate = (int)EncoderLAME.BITRATE.kbps_320; Lame.LAME_Mode = EncoderLAME.LAMEMode.Default; Lame.LAME_TargetSampleRate = (int)EncoderLAME.SAMPLERATE.Hz_44100; Lame.LAME_Quality = EncoderLAME.LAMEQuality.Quality; Lame.EncoderDirectory = _DirectoryExe; return Lame; }
// メソッド /// <summary> /// WASAPIの初期化 /// </summary> /// <param name="mode"></param> /// <param name="n希望バッファサイズms">WASAPIのサウンドバッファサイズ</param> /// <param name="n更新間隔ms">サウンドバッファの更新間隔</param> public CSoundDeviceWASAPI(Eデバイスモード mode, long n希望バッファサイズms, long n更新間隔ms, string strRecordFileType, string strEncoderPath) { // 初期化。 Trace.TraceInformation("BASS (WASAPI{0}) の初期化を開始します。", mode.ToString()); this.e出力デバイス = ESoundDeviceType.Unknown; this.n実出力遅延ms = 0; this.n経過時間ms = 0; this.n経過時間を更新したシステム時刻ms = CTimer.nUnused; this.tmシステムタイマ = new CTimer(CTimer.EType.MultiMedia); this.b最初の実出力遅延算出 = true; #region [ BASS registration ] // BASS.NET ユーザ登録(BASSスプラッシュが非表示になる)。 BassNet.Registration("*****@*****.**", "2X9182021152222"); #endregion #region [ BASS Version Check ] // BASS のバージョンチェック。 int nBASSVersion = Utils.HighWord(Bass.BASS_GetVersion()); if (nBASSVersion != Bass.BASSVERSION) { throw new DllNotFoundException(string.Format("bass.dll のバージョンが異なります({0})。このプログラムはバージョン{1}で動作します。", nBASSVersion, Bass.BASSVERSION)); } int nBASSMixVersion = Utils.HighWord(BassMix.BASS_Mixer_GetVersion()); if (nBASSMixVersion != BassMix.BASSMIXVERSION) { throw new DllNotFoundException(string.Format("bassmix.dll のバージョンが異なります({0})。このプログラムはバージョン{1}で動作します。", nBASSMixVersion, BassMix.BASSMIXVERSION)); } int nBASSWASAPIVersion = Utils.HighWord(BassWasapi.BASS_WASAPI_GetVersion()); if (nBASSWASAPIVersion != BassWasapi.BASSWASAPIVERSION) { throw new DllNotFoundException(string.Format("basswasapi.dll のバージョンが異なります({0})。このプログラムはバージョン{1}で動作します。", nBASSWASAPIVersion, BassWasapi.BASSWASAPIVERSION)); } #endregion // BASS の設定。 this.bIsBASSFree = true; Debug.Assert(Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_UPDATEPERIOD, 0), // 0:BASSストリームの自動更新を行わない。(BASSWASAPIから行うため) string.Format("BASS_SetConfig() に失敗しました。[{0}", Bass.BASS_ErrorGetCode())); #region [ デバッグ用: BASSデバイスのenumerateと、ログ出力 ] //Trace.TraceInformation( "BASSデバイス一覧:" ); //int defDevice = -1; //BASS_DEVICEINFO bdi; //for ( int n = 0; ( bdi = Bass.BASS_GetDeviceInfo( n ) ) != null; n++ ) //{ // Trace.TraceInformation( "BASS Device #{0}: {1}: IsDefault={2}, flags={3}, type={4}", // n, // bdi.name, // bdi.IsDefault, bdi.flags.ToString(), bdi.type,ToString() // ); // //if ( bdi.IsDefault ) // //{ // // defDevice = n; // // break; // //} //} #endregion // BASS の初期化。 int n周波数 = 48000; // 仮決め。lデバイス(≠ドライバ)がネイティブに対応している周波数であれば何でもいい?ようだ。BASSWASAPIでデバイスの周波数は変えられる。いずれにしろBASSMXで自動的にリサンプリングされる。 // BASS_Initは、WASAPI初期化の直前に行うよう変更。WASAPIのmix周波数を使って初期化することで、余計なリサンプリング処理を省き高速化するため。 //if( !Bass.BASS_Init( nデバイス, n周波数, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero ) ) // throw new Exception( string.Format( "BASS (WASAPI) の初期化に失敗しました。(BASS_Init)[{0}]", Bass.BASS_ErrorGetCode().ToString() ) ); #region [ デバッグ用: サウンドデバイスのenumerateと、ログ出力 ] //(デバッグ用) Trace.TraceInformation("サウンドデバイス一覧:"); int a; string strDefaultSoundDeviceName = null; BASS_DEVICEINFO[] bassDevInfos = Bass.BASS_GetDeviceInfos(); for (a = 0; a < bassDevInfos.GetLength(0); a++) { { Trace.TraceInformation("Sound Device #{0}: {1}: IsDefault={2}, isEnabled={3}, flags={4}, id={5}", a, bassDevInfos[a].name, bassDevInfos[a].IsDefault, bassDevInfos[a].IsEnabled, bassDevInfos[a].flags, bassDevInfos[a].id ); if (bassDevInfos[a].IsDefault) { // これはOS標準のdefault device。後でWASAPIのdefault deviceと比較する。 strDefaultSoundDeviceName = bassDevInfos[a].name; // 以下はOS標準 default deviceのbus type (PNPIDの頭の文字列)。上位側で使用する。 string[] s = bassDevInfos[a].id.ToString().ToUpper().Split(new char[] { '#' }); if (s != null && s[0] != null) { strDefaultSoundDeviceBusType = s[0]; } } } } #endregion // BASS WASAPI の初期化。 n周波数 = 0; // デフォルトデバイスの周波数 (0="mix format" sample rate) int nチャンネル数 = 0; // デフォルトデバイスのチャンネル数 (0="mix format" channels) this.tWasapiProc = new WASAPIPROC(this.tWASAPI処理); // アンマネージに渡す delegate は、フィールドとして保持しておかないとGCでアドレスが変わってしまう。 // WASAPIの更新間隔(period)は、バッファサイズにも影響を与える。 // 更新間隔を最小にするには、BassWasapi.BASS_WASAPI_GetDeviceInfo( ndevNo ).minperiod の値を使えばよい。 // これをやらないと、更新間隔ms=6ms となり、バッファサイズを 6ms x 4 = 24msより小さくできない。 #region [ 既定の出力デバイスと設定されているWASAPIデバイスを検索し、更新間隔msを設定できる最小値にする ] int nDevNo = -1; BASS_WASAPI_DEVICEINFO deviceInfo; for (int n = 0; (deviceInfo = BassWasapi.BASS_WASAPI_GetDeviceInfo(n)) != null; n++) { // BASS_DEVICEINFOとBASS_WASAPI_DEVICEINFOで、IsDefaultとなっているデバイスが異なる場合がある。 // (WASAPIでIsDefaultとなっているデバイスが正しくない場合がある) // そのため、BASS_DEVICEでIsDefaultとなっているものを探し、それと同じ名前のWASAPIデバイスを使用する。 //if ( deviceInfo.IsDefault ) if (deviceInfo.name == strDefaultSoundDeviceName) { nDevNo = n; #region [ 既定の出力デバイスの情報を表示 ] Trace.TraceInformation("WASAPI Device #{0}: {1}: IsDefault={2}, defPeriod={3}s, minperiod={4}s, mixchans={5}, mixfreq={6}", n, deviceInfo.name, deviceInfo.IsDefault, deviceInfo.defperiod, deviceInfo.minperiod, deviceInfo.mixchans, deviceInfo.mixfreq); #endregion break; } } if (nDevNo != -1) { Trace.TraceInformation("Start Bass_Init(device=0(fixed value: no sound), deviceInfo.mixfreq=" + deviceInfo.mixfreq + ", BASS_DEVICE_DEFAULT, Zero)"); if (!Bass.BASS_Init(0, deviceInfo.mixfreq, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero)) // device = 0:"no device": BASS からはデバイスへアクセスさせない。アクセスは BASSWASAPI アドオンから行う。 { throw new Exception(string.Format("BASS (WASAPI{0}) の初期化に失敗しました。(BASS_Init)[{1}]", mode.ToString(), Bass.BASS_ErrorGetCode().ToString())); } // Trace.TraceInformation( "Selected Default WASAPI Device: {0}", deviceInfo.name ); // Trace.TraceInformation( "MinPeriod={0}, DefaultPeriod={1}", deviceInfo.minperiod, deviceInfo.defperiod ); // n更新間隔ms = ( mode == Eデバイスモード.排他 )? Convert.ToInt64(Math.Ceiling(deviceInfo.minperiod * 1000.0f)) : Convert.ToInt64(Math.Ceiling(deviceInfo.defperiod * 1000.0f)); // 更新間隔として、WASAPI排他時はminperiodより大きい最小のms値を、WASAPI共有時はdefperiodより大きい最小のms値を用いる // Win10では、更新間隔がminperiod以下だと、確実にBASS_ERROR_UNKNOWNとなる。 //if ( n希望バッファサイズms <= 0 || n希望バッファサイズms < n更新間隔ms + 1 ) //{ // n希望バッファサイズms = n更新間隔ms + 1; // 2013.4.25 #31237 yyagi; バッファサイズ設定の完全自動化。更新間隔=バッファサイズにするとBASS_ERROR_UNKNOWNになるので+1する。 //} } else { Trace.TraceError("Error: Default WASAPI Device is not found."); } #endregion #region [ デバッグ用: WASAPIデバイスのenumerateと、ログ出力 ] //(デバッグ用) Trace.TraceInformation("WASAPIデバイス一覧:"); //int a, count = 0; BASS_WASAPI_DEVICEINFO wasapiDevInfo; for (a = 0; (wasapiDevInfo = BassWasapi.BASS_WASAPI_GetDeviceInfo(a)) != null; a++) { if ((wasapiDevInfo.flags & BASSWASAPIDeviceInfo.BASS_DEVICE_INPUT) == 0 && // device is an output device (not input) (wasapiDevInfo.flags & BASSWASAPIDeviceInfo.BASS_DEVICE_ENABLED) != 0) // and it is enabled { Trace.TraceInformation("WASAPI Device #{0}: {1}: IsDefault={2}, defPeriod={3}s, minperiod={4}s, mixchans={5}, mixfreq={6}", a, wasapiDevInfo.name, wasapiDevInfo.IsDefault, wasapiDevInfo.defperiod, wasapiDevInfo.minperiod, wasapiDevInfo.mixchans, wasapiDevInfo.mixfreq); } } #endregion var flags = (mode == Eデバイスモード.排他) ? BASSWASAPIInit.BASS_WASAPI_AUTOFORMAT | BASSWASAPIInit.BASS_WASAPI_EXCLUSIVE : BASSWASAPIInit.BASS_WASAPI_AUTOFORMAT | BASSWASAPIInit.BASS_WASAPI_SHARED; // 注: BASS_WASAPI_SHARED==0 なので、SHAREDの指定は意味なし if (COS.bIsWin7OrLater() && CSoundManager.bSoundUpdateByEventWASAPI) { flags |= BASSWASAPIInit.BASS_WASAPI_EVENT; // Win7以降の場合は、WASAPIをevent drivenで動作させてCPU負荷減、レイテインシ改善 } n周波数 = deviceInfo.mixfreq; nチャンネル数 = deviceInfo.mixchans; // 更新間隔として、WASAPI排他時はminperiodより大きい最小のms値を、WASAPI共有時はdefperiodより大きい最小のms値を用いる // (Win10のlow latency modeではない前提でまずは設定値を決める) float fPeriod = (mode == Eデバイスモード.排他) ? deviceInfo.minperiod : deviceInfo.defperiod; Trace.TraceInformation("arg: n希望バッファサイズms=" + n希望バッファサイズms); Trace.TraceInformation("arg: n更新間隔ms=" + n更新間隔ms); Trace.TraceInformation("fPeriod = " + fPeriod + " (排他時: minperiod, 共有時: defperiod。Win10 low latency audio考慮前)"); float f更新間隔sec = (n更新間隔ms > 0) ? (n更新間隔ms / 1000.0f) : fPeriod; if (f更新間隔sec < fPeriod) { f更新間隔sec = fPeriod; // Win10では、更新間隔がminperiod以下だと、確実にBASS_ERROR_UNKNOWNとなる。 } Trace.TraceInformation("f更新間隔sec=" + f更新間隔sec); // バッファサイズは、更新間隔より大きくする必要あり。(イコールだと、WASAPI排他での初期化時にBASS_ERROR_UNKNOWNとなる) // そのため、最低でも、更新間隔より1ms大きく設定する。 float f希望バッファサイズsec = (n希望バッファサイズms > 0) ? (n希望バッファサイズms / 1000.0f) : fPeriod + 0.001f; if (f希望バッファサイズsec < fPeriod) { f希望バッファサイズsec = fPeriod + 0.001f; } // WASAPI排他時は、バッファサイズは更新間隔の4倍必要(event driven時は2倍) if (mode == Eデバイスモード.排他) { if ((flags & BASSWASAPIInit.BASS_WASAPI_EVENT) != BASSWASAPIInit.BASS_WASAPI_EVENT && f希望バッファサイズsec < f更新間隔sec * 4) { f希望バッファサイズsec = f更新間隔sec * 4; } else if ((flags & BASSWASAPIInit.BASS_WASAPI_EVENT) == BASSWASAPIInit.BASS_WASAPI_EVENT && f希望バッファサイズsec < f更新間隔sec * 2) { f希望バッファサイズsec = f更新間隔sec * 2; } } //else //if (COS.bIsWin10OrLater() && (mode == Eデバイスモード.共有)) // Win10 low latency shared mode support //{ // // バッファ自動設定をユーザーが望む場合は、periodを最小値にする。さもなくば、バッファサイズとしてユーザーが指定した値を、periodとして用いる。 // if (n希望バッファサイズms == 0) // { // f更新間隔sec = deviceInfo.minperiod; // } // else // { // f更新間隔sec = n希望バッファサイズms / 1000.0f; // if (f更新間隔sec < deviceInfo.minperiod) // { // f更新間隔sec = deviceInfo.minperiod; // } // } // f希望バッファサイズsec = 0.0f; //} Trace.TraceInformation("f希望バッファサイズsec=" + f希望バッファサイズsec + ", f更新間隔sec=" + f更新間隔sec + ": Win10 low latency audio 考慮後"); Trace.TraceInformation("Start Bass_Wasapi_Init(device=" + nDevNo + ", freq=" + n周波数 + ", nchans=" + nチャンネル数 + ", flags=" + flags + "," + " buffer=" + f希望バッファサイズsec + ", period=" + f更新間隔sec + ")"); if (BassWasapi.BASS_WASAPI_Init(nDevNo, n周波数, nチャンネル数, flags, f希望バッファサイズsec, f更新間隔sec, this.tWasapiProc, IntPtr.Zero)) { if (mode == Eデバイスモード.排他) { #region [ 排他モードで作成成功。] //----------------- this.e出力デバイス = ESoundDeviceType.ExclusiveWASAPI; nDevNo = BassWasapi.BASS_WASAPI_GetDevice(); deviceInfo = BassWasapi.BASS_WASAPI_GetDeviceInfo(nDevNo); var wasapiInfo = BassWasapi.BASS_WASAPI_GetInfo(); int n1サンプルのバイト数 = 2 * wasapiInfo.chans; // default; switch (wasapiInfo.format) // BASS WASAPI で扱うサンプルはすべて 32bit float で固定されているが、デバイスはそうとは限らない。 { case BASSWASAPIFormat.BASS_WASAPI_FORMAT_8BIT: n1サンプルのバイト数 = 1 * wasapiInfo.chans; break; case BASSWASAPIFormat.BASS_WASAPI_FORMAT_16BIT: n1サンプルのバイト数 = 2 * wasapiInfo.chans; break; case BASSWASAPIFormat.BASS_WASAPI_FORMAT_24BIT: n1サンプルのバイト数 = 3 * wasapiInfo.chans; break; case BASSWASAPIFormat.BASS_WASAPI_FORMAT_32BIT: n1サンプルのバイト数 = 4 * wasapiInfo.chans; break; case BASSWASAPIFormat.BASS_WASAPI_FORMAT_FLOAT: n1サンプルのバイト数 = 4 * wasapiInfo.chans; break; } int n1秒のバイト数 = n1サンプルのバイト数 * wasapiInfo.freq; this.n実バッファサイズms = (long)(wasapiInfo.buflen * 1000.0f / n1秒のバイト数); this.n実出力遅延ms = 0; // 初期値はゼロ Trace.TraceInformation("使用デバイス: #" + nDevNo + " : " + deviceInfo.name + ", flags=" + deviceInfo.flags); Trace.TraceInformation("BASS を初期化しました。(WASAPI排他モード, {0}Hz, {1}ch, フォーマット:{2}, バッファ{3}bytes [{4}ms(希望{5}ms)], 更新間隔{6}ms)", wasapiInfo.freq, wasapiInfo.chans, wasapiInfo.format.ToString(), wasapiInfo.buflen, n実バッファサイズms.ToString(), (f希望バッファサイズsec * 1000).ToString(), //n希望バッファサイズms.ToString(), (f更新間隔sec * 1000).ToString() //n更新間隔ms.ToString() ); Trace.TraceInformation("デバイスの最小更新時間={0}ms, 既定の更新時間={1}ms", deviceInfo.minperiod * 1000, deviceInfo.defperiod * 1000); this.bIsBASSFree = false; //----------------- #endregion } else { #region [ 共有モードで作成成功。] //----------------- this.e出力デバイス = ESoundDeviceType.SharedWASAPI; var wasapiInfo = BassWasapi.BASS_WASAPI_GetInfo(); int n1サンプルのバイト数 = 2 * wasapiInfo.chans; // default; int n1秒のバイト数 = n1サンプルのバイト数 * wasapiInfo.freq; this.n実バッファサイズms = (long)(wasapiInfo.buflen * 1000.0f / n1秒のバイト数); this.n実出力遅延ms = 0; // 初期値はゼロ var devInfo = BassWasapi.BASS_WASAPI_GetDeviceInfo(BassWasapi.BASS_WASAPI_GetDevice()); // 共有モードの場合、更新間隔はデバイスのデフォルト値に固定される。 //Trace.TraceInformation( "BASS を初期化しました。(WASAPI共有モード, 希望バッファサイズ={0}ms, 更新間隔{1}ms)", n希望バッファサイズms, devInfo.defperiod * 1000.0f ); Trace.TraceInformation("使用デバイス: #" + nDevNo + " : " + deviceInfo.name + ", flags=" + deviceInfo.flags); Trace.TraceInformation("BASS を初期化しました。(WASAPI共有モード, {0}Hz, {1}ch, フォーマット:{2}, バッファ{3}bytes [{4}ms(希望{5}ms)], 更新間隔{6}ms)", wasapiInfo.freq, wasapiInfo.chans, wasapiInfo.format.ToString(), wasapiInfo.buflen, n実バッファサイズms.ToString(), (f希望バッファサイズsec * 1000).ToString(), //n希望バッファサイズms.ToString(), (f更新間隔sec * 1000).ToString() //n更新間隔ms.ToString() ); Trace.TraceInformation("デバイスの最小更新時間={0}ms, 既定の更新時間={1}ms", deviceInfo.minperiod * 1000, deviceInfo.defperiod * 1000); this.bIsBASSFree = false; //----------------- #endregion } } #region [ #31737 WASAPI排他モードのみ利用可能とし、WASAPI共有モードは使用できないようにするために、WASAPI共有モードでの初期化フローを削除する。 ] else if (mode == Eデバイスモード.排他) { BASSError errcode = Bass.BASS_ErrorGetCode(); Trace.TraceInformation("Failed to initialize setting BASS_WASAPI_Init (WASAPI{0}): [{1}]", mode.ToString(), errcode); #region [ 排他モードに失敗したのなら共有モードでリトライ。] //----------------- // mode = Eデバイスモード.共有; // goto Retry; //----------------- Bass.BASS_Free(); this.bIsBASSFree = true; throw new Exception(string.Format("BASS (WASAPI{0}) の初期化に失敗しました。(BASS_WASAPI_Init)[{1}]", mode.ToString(), errcode)); #endregion } #endregion else { #region [ それでも失敗したら例外発生。] //----------------- BASSError errcode = Bass.BASS_ErrorGetCode(); Bass.BASS_Free(); this.bIsBASSFree = true; throw new Exception(string.Format("BASS (WASAPI{0}) の初期化に失敗しました。(BASS_WASAPI_Init)[{1}]", mode.ToString(), errcode)); //----------------- #endregion } #if TEST_MultiThreadedMixer //LoadLibraryに失敗する・・・ //BASSThreadedMixerLibraryWrapper.InitBASSThreadedMixerLibrary(); #endif // WASAPI出力と同じフォーマットを持つ BASS ミキサーを作成。 // 1つのまとめとなるmixer (hMixer) と、そこにつなぐ複数の楽器別mixer (hMixer _forChips)を作成。 //Debug.Assert( Bass.BASS_SetConfig( BASSConfig.BASS_CONFIG_MIXER_BUFFER, 5 ), // バッファ量を最大量の5にする // string.Format( "BASS_SetConfig(CONFIG_MIXER_BUFFER) に失敗しました。[{0}", Bass.BASS_ErrorGetCode() ) ); var info = BassWasapi.BASS_WASAPI_GetInfo(); #if TEST_MultiThreadedMixer this.hMixer = BASSThreadedMixerLibraryWrapper.BASS_ThreadedMixer_Create( info.freq, info.chans, (int)(BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_POSEX), out hMixerThreaded ); #else this.hMixer = BassMix.BASS_Mixer_StreamCreate( info.freq, info.chans, BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_POSEX); // デコードのみ=発声しない。WASAPIに出力されるだけ。 #endif if (this.hMixer == 0) { BASSError errcode = Bass.BASS_ErrorGetCode(); BassWasapi.BASS_WASAPI_Free(); Bass.BASS_Free(); this.bIsBASSFree = true; throw new Exception(string.Format("BASSミキサ(mixing)の作成に失敗しました。[{0}]", errcode)); } for (int i = 0; i <= (int)CSound.EInstType.Unknown; i++) { #if TEST_MultiThreadedMixer this.hMixer_Chips[i] = BASSThreadedMixerLibraryWrapper.BASS_ThreadedMixer_Create( info.freq, info.chans, (int)(BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_POSEX), out this.hMixerThreaded_Chips[i] ); // デコードのみ=発声しない。WASAPIに出力されるだけ。 #else this.hMixer_Chips[i] = BassMix.BASS_Mixer_StreamCreate( info.freq, info.chans, BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_POSEX); // デコードのみ=発声しない。WASAPIに出力されるだけ。 #endif if (this.hMixer_Chips[i] == 0) { BASSError errcode = Bass.BASS_ErrorGetCode(); BassWasapi.BASS_WASAPI_Free(); Bass.BASS_Free(); this.bIsBASSFree = true; throw new Exception(string.Format("BASSミキサ(楽器[{1}]ごとのmixing)の作成に失敗しました。[{0}]", errcode, i)); } // Mixerのボリューム設定 Bass.BASS_ChannelSetAttribute(this.hMixer_Chips[i], BASSAttribute.BASS_ATTRIB_VOL, CSoundManager.nMixerVolume[i] / 100.0f); //Trace.TraceInformation("Vol{0}: {1}", i, CSound管理.nMixerVolume[i]); #if TEST_MultiThreadedMixer bool b1 = BASSThreadedMixerLibraryWrapper.BASS_ThreadedMixer_AddSource(this.hMixerThreaded, this.hMixer_Chips[i], IntPtr.Zero); #else bool b1 = BassMix.BASS_Mixer_StreamAddChannel(this.hMixer, this.hMixer_Chips[i], BASSFlag.BASS_DEFAULT); #endif if (!b1) { BASSError errcode = Bass.BASS_ErrorGetCode(); BassWasapi.BASS_WASAPI_Free(); Bass.BASS_Free(); this.bIsBASSFree = true; throw new Exception(string.Format("個別BASSミキサ({1}}から(mixing)への接続に失敗しました。[{0}]", errcode, i)); } ; } // BASS ミキサーの1秒あたりのバイト数を算出。 var mixerInfo = Bass.BASS_ChannelGetInfo(this.hMixer); long nミキサーの1サンプルあたりのバイト数 = mixerInfo.chans * 4; // 4 = sizeof(FLOAT) this.nミキサーの1秒あたりのバイト数 = nミキサーの1サンプルあたりのバイト数 * mixerInfo.freq; // 単純に、hMixerの音量をMasterVolumeとして制御しても、 // ChannelGetData()の内容には反映されない。 // そのため、もう一段mixerを噛ませて、一段先のmixerからChannelGetData()することで、 // hMixerの音量制御を反映させる。 this.hMixer_DeviceOut = BassMix.BASS_Mixer_StreamCreate( info.freq, info.chans, BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_MIXER_POSEX); // デコードのみ=発声しない。WASAPIに出力されるだけ。 if (this.hMixer_DeviceOut == 0) { BASSError errcode = Bass.BASS_ErrorGetCode(); BassWasapi.BASS_WASAPI_Free(); Bass.BASS_Free(); this.bIsBASSFree = true; throw new Exception(string.Format("BASSミキサ(最終段)の作成に失敗しました。[{0}]", errcode)); } { bool b1 = BassMix.BASS_Mixer_StreamAddChannel(this.hMixer_DeviceOut, this.hMixer, BASSFlag.BASS_DEFAULT); if (!b1) { BASSError errcode = Bass.BASS_ErrorGetCode(); BassWasapi.BASS_WASAPI_Free(); Bass.BASS_Free(); this.bIsBASSFree = true; throw new Exception(string.Format("BASSミキサ(最終段とmixing)の接続に失敗しました。[{0}]", errcode)); } ; } // 録音設定(DTX2WAV) if (!string.IsNullOrEmpty(strRecordFileType)) { switch (strRecordFileType.ToUpper()) { case "WAV": { var e = new EncoderWAV(this.hMixer_DeviceOut); //e.WAV_EncoderType = BASSChannelType.BASS_CTYPE_STREAM_WAV_PCM; encoder = e; } break; case "OGG": { var e = new EncoderOGG(this.hMixer_DeviceOut); e.EncoderDirectory = strEncoderPath; e.OGG_UseQualityMode = true; e.OGG_Quality = (float)CSoundManager.nBitrate; //e.OGG_Bitrate = 128; //e.OGG_MinBitrate = 0; //e.OGG_MaxBitrate = 0; encoder = e; } break; case "MP3": { var e = new EncoderLAME(this.hMixer_DeviceOut); e.EncoderDirectory = strEncoderPath; e.LAME_UseVBR = false; e.LAME_Bitrate = CSoundManager.nBitrate; encoder = e; } break; default: encoder = new EncoderWAV(this.hMixer_DeviceOut); break; } encoder.InputFile = null; //STDIN encoder.OutputFile = CSoundManager.strRecordOutFilename; encoder.UseAsyncQueue = true; encoder.Start(null, IntPtr.Zero, true); // PAUSE状態で録音開始 } //Bass.BASS_ChannelSetAttribute(this.hMixer_DeviceOut, BASSAttribute.BASS_ATTRIB_VOL, 0.10f); //Bass.BASS_SetConfig(BASSConfig.BASS_CONFIG_GVOL_SAMPLE, 1000); //Bass.BASS_SetVolume(0.1f); // 出力を開始。 BassWasapi.BASS_WASAPI_Start(); }
private BaseEncoder SetEncoderSettings(int stream) { BaseEncoder encoder = null; switch (_encoder) { case "mp3": EncoderLAME encLame = new EncoderLAME(stream); if (Options.MainSettings.RipLameExpert.Length > 0) { encLame.LAME_CustomOptions = Options.MainSettings.RipLameExpert; encLame.LAME_UseCustomOptionsOnly = true; } else { if (Options.MainSettings.RipLamePreset == (int)Options.LamePreset.ABR) { encLame.LAME_PresetName = Options.MainSettings.RipLameABRBitRate.ToString(); } else { encLame.LAME_PresetName = Enum.GetName(typeof(Options.LamePreset), Options.MainSettings.RipLamePreset).ToLower(); } } encoder = encLame; break; case "ogg": EncoderOGG encOgg = new EncoderOGG(stream); if (Options.MainSettings.RipOggExpert.Length > 0) { encOgg.OGG_CustomOptions = Options.MainSettings.RipOggExpert; encOgg.OGG_UseCustomOptionsOnly = true; } else { encOgg.OGG_Quality = Convert.ToInt32(Options.MainSettings.RipOggQuality); } encoder = encOgg; break; case "flac": EncoderFLAC encFlac = new EncoderFLAC(stream); if (Options.MainSettings.RipFlacExpert.Length > 0) { encFlac.FLAC_CustomOptions = Options.MainSettings.RipFlacExpert; encFlac.FLAC_UseCustomOptionsOnly = true; } else { encFlac.FLAC_CompressionLevel = Options.MainSettings.RipFlacQuality; } // put a 1k padding block for Tagging in front encFlac.FLAC_Padding = 1024; encoder = encFlac; break; case "m4a": EncoderFAAC encAAC = new EncoderFAAC(stream); int bitrate = Convert.ToInt32(Options.MainSettings.RipEncoderAACBitRate.Substring(0, Options.MainSettings. RipEncoderAACBitRate.IndexOf(' '))); encAAC.FAAC_Bitrate = bitrate; encAAC.FAAC_Quality = 100; encAAC.FAAC_UseQualityMode = true; encAAC.FAAC_WrapMP4 = true; encoder = encAAC; break; case "wav": EncoderWAV encWav = new EncoderWAV(stream); encoder = encWav; break; case "wma": EncoderWMA encWma = new EncoderWMA(stream); string[] sampleFormat = Options.MainSettings.RipEncoderWMASample.Split(','); string encoderFormat = Options.MainSettings.RipEncoderWMA; if (encoderFormat == "wmapro" || encoderFormat == "wmalossless") { encWma.WMA_UsePro = true; } else { encWma.WMA_ForceStandard = true; } if (Options.MainSettings.RipEncoderWMACbrVbr == "Vbr") { encWma.WMA_UseVBR = true; encWma.WMA_VBRQuality = Convert.ToInt32(Options.MainSettings.RipEncoderWMABitRate); } else { encWma.WMA_Bitrate = Convert.ToInt32(Options.MainSettings.RipEncoderWMABitRate) / 1000; } if (sampleFormat[0] == "24") { encWma.WMA_Use24Bit = true; } encoder = encWma; break; case "mpc": EncoderMPC encMpc = new EncoderMPC(stream); if (Options.MainSettings.RipEncoderMPCExpert.Length > 0) { encMpc.MPC_CustomOptions = Options.MainSettings.RipEncoderMPCExpert; encMpc.MPC_UseCustomOptionsOnly = true; } else { encMpc.MPC_Preset = (EncoderMPC.MPCPreset)Enum.Parse(typeof(EncoderMPC.MPCPreset), Options.MainSettings.RipEncoderMPCPreset); } encoder = encMpc; break; case "wv": EncoderWavPack encWv = new EncoderWavPack(stream); if (Options.MainSettings.RipEncoderWVExpert.Length > 0) { encWv.WV_CustomOptions = Options.MainSettings.RipEncoderWVExpert; encWv.WV_UseCustomOptionsOnly = true; } else { if (Options.MainSettings.RipEncoderWVPreset == "-f") { encWv.WV_FastMode = true; } else { encWv.WV_HighQuality = true; } } encoder = encWv; break; } return(encoder); }