/// <summary>Create MP3FileWriter to write to supplied stream</summary>
        /// <param name="outStream">Stream to write encoded data to</param>
        /// <param name="format">Input Genode.Audio.WavFormat</param>
        /// <param name="bitRate">Output bit rate in kbps</param>
        /// <param name="id3">Optional ID3 data block</param>
        public LameMP3FileWriter(Stream outStream, Cgen.Audio.WavFormat format, int bitRate, int channels = 2, int sampleRate = 44100, ID3TagData id3 = null)
            : base()
        {
            // sanity check
            if (outStream == null)
            {
                throw new ArgumentNullException("outStream");
            }

            // select encoder function that matches data format
            if (format == Cgen.Audio.WavFormat.PCM)
            {
                if (channels == 1)
                {
                    _encode = encode_pcm_16_mono;
                }
                else
                {
                    _encode = encode_pcm_16_stereo;
                }
            }
            else
            {
                if (channels == 1)
                {
                    _encode = encode_float_mono;
                }
                else
                {
                    _encode = encode_float_stereo;
                }
            }

            // Set base properties
            this.inputFormat   = format;
            this.outStream     = outStream;
            this.disposeOutput = false;

            // Allocate buffers based on sample rate
            this.channels  = channels;
            this.inBuffer  = new ArrayUnion(sampleRate * channels * 2);
            this.outBuffer = new byte[sampleRate * 5 / 4 + 7200];

            // Initialize lame library
            this._lame = new Lame.Wrapper.LibMp3Lame();

            this._lame.InputSampleRate = sampleRate;
            this._lame.NumChannels     = channels;

            this._lame.BitRate = bitRate;

            if (id3 != null)
            {
                ApplyID3Tag(id3);
            }

            this._lame.InitParams();
        }
        /// <summary>Setup ID3 tag with supplied information</summary>
        /// <param name="tag">ID3 data</param>
        private void ApplyID3Tag(ID3TagData tag)
        {
            if (tag == null)
            {
                return;
            }

            // Apply standard ID3 fields
            if (!string.IsNullOrEmpty(tag.Title))
            {
                _lame.ID3SetTitle(tag.Title);
            }
            if (!string.IsNullOrEmpty(tag.Artist))
            {
                _lame.ID3SetArtist(tag.Artist);
            }
            if (!string.IsNullOrEmpty(tag.Album))
            {
                _lame.ID3SetAlbum(tag.Album);
            }
            if (!string.IsNullOrEmpty(tag.Year))
            {
                _lame.ID3SetYear(tag.Year);
            }
            if (!string.IsNullOrEmpty(tag.Comment))
            {
                _lame.ID3SetComment(tag.Comment);
            }
            if (!string.IsNullOrEmpty(tag.Genre))
            {
                _lame.ID3SetGenre(tag.Genre);
            }
            if (!string.IsNullOrEmpty(tag.Track))
            {
                _lame.ID3SetTrack(tag.Track);
            }

            // Apply standard ID3 fields that are not directly supported by LAME
            if (!string.IsNullOrEmpty(tag.Subtitle))
            {
                _lame.ID3SetFieldValue(string.Format("TIT3={0}", tag.Subtitle));
            }
            if (!string.IsNullOrEmpty(tag.AlbumArtist))
            {
                _lame.ID3SetFieldValue(string.Format("TPE2={0}", tag.AlbumArtist));
            }

            // Add user-defined tags if present
            // NB: LAME handles the replacement of duplicates.
            if (tag.UserDefinedTags?.Length > 0)
            {
                foreach (var userDefinedTag in tag.UserDefinedTags)
                {
                    _lame.ID3SetFieldValue(string.Format("TXXX={0}", userDefinedTag));
                }
            }

            // Set the album art if supplied and within size limits
            if (tag.AlbumArt?.Length > 0 && tag.AlbumArt.Length < 131072)
            {
                _lame.ID3SetAlbumArt(tag.AlbumArt);
            }
        }
 /// <summary>Create MP3FileWriter to write to a file on disk</summary>
 /// <param name="outFileName">Name of file to create</param>
 /// <param name="format">Input Genode.Audio.WavFormat</param>
 /// <param name="bitRate">Output bit rate in kbps</param>
 /// <param name="id3">Optional ID3 data block</param>
 public LameMP3FileWriter(string outFileName, Cgen.Audio.WavFormat format, int bitRate, int channels = 2, int sampleRate = 44100, ID3TagData id3 = null)
     : this(File.Create(outFileName), format, bitRate, channels, sampleRate, id3)
 {
     this.disposeOutput = true;
 }