Author Topic: [C#] Re-encoding audio without attaching an encoder to a decoding stream  (Read 132 times)

std66

  • Posts: 22
Dear members,

As far as I know, if I want to decode a HSTREAM into PCM wave data and pass it to an encoder (like LAME), I need to do something like this:
Code: [Select]
async Task EncodeAsMp3ToStreamAsync(Stream TargetStream) {
   //This copies the encoded data received from the encoder to the given Stream.
   ENCODEPROC proc = new ENCODEPROC(
      (handle, channel, buffer, length, user) => {
         byte[] ManagedBuffer = new byte[length];
         Marshal.Copy(buffer, ManagedBuffer, 0, length);

         TargetStream.Write(ManagedBuffer, 0, length);
      }
   );

   //This is the channel I want to decode and re-encode.
   int DecodingChannel = Bass.BASS_StreamCreateFile(this.Filename, 0, 0, BASSFlag.BASS_STREAM_DECODE);
   long DecodingChannelLength = Bass.BASS_ChannelGetLength(DecodingChannel);

   //Here I attach an encoder to the decoding stream...
   int Handle = BassEnc.BASS_Encode_Start(
      DecodingChannel,
      (new Lame()).GetCommandLine(),
      BASSEncode.BASS_ENCODE_AUTOFREE,
      proc,
      IntPtr.Zero
   );

   await Task.Run(() => {
      int BufferLength = 10240;
      byte[] Buffer = new byte[BufferLength];
     
      while (Bass.BASS_ChannelGetPosition(DecodingChannel) < DecodingChannelLength) {
        //... so the only thing I need to do is to read data from the decoding stream.
        Bass.BASS_ChannelGetData(DecodingChannel, Buffer, BufferLength);
      }

      BassEnc.BASS_Encode_Stop(Handle);
   });
}

I have several issues with this method, but the most important things are:
- This is not unit testable.
- It has a hardcoded dependency on BASS and the LAME encoder.
- Also violates the most of the SOLID principles.

So, I'd like to create two interfaces:
Code: [Select]
interface IDecoder {
   long Length { get; }
   long Position { get; }
   IEnumerable<byte> ReadPcmWaveData(int MaxBufferLength);
}

interface IEncoder {
   void WritePcmWaveData(IEnumerable<byte> PcmWaveData);
}

//This way I could create a method something like this:
async Task EncodeAsync(IDecoder Decoder, IEncoder Encoder) {
   await Task.Run(() => {
      while (Decoder.Position < Decoder.Length) {
         Encoder.WritePcmWaveData(
            Decoder.ReadPcmWaveData(10240);
         );
      }
   });
}

My question is that how should I use BASS and BASSEnc so that I could encode like this?
« Last Edit: 20 Sep '17 - 09:19 by std66 »