Author Topic: Recording and ecnoding to mp3  (Read 1027 times)

smakarov3

  • Guest
Recording and ecnoding to mp3
« on: 4 Oct '18 - 12:56 »
Hi! I am trying record from mic, but current code saves it only on wav. Ho i can encode it on the fly and save to mp3?
Current solution
Code: [Select]
private void WriteWavHeader()
    {
        _fileName = UnityEngine.Random.Range(0, Int32.MaxValue).ToString() + ".wav";
        using (Stream fileStream = new FileStream(CommonSettings.Instance.GetAndroidFriendlyFilesPath() + "/" + _fileName, FileMode.Create, FileAccess.Write, FileShare.None))
        {
            int channelCount = 2;
            int sampleRate = 44100;
            int bitDepth = 16;
            fileStream.Position = 0;
            fileStream.Write(Encoding.ASCII.GetBytes("RIFF"), 0, 4);
            fileStream.Write(BitConverter.GetBytes(36), 0, 4);
            fileStream.Write(Encoding.ASCII.GetBytes("WAVE"), 0, 4);
            fileStream.Write(Encoding.ASCII.GetBytes("fmt "), 0, 4);
            fileStream.Write(BitConverter.GetBytes(16), 0, 4);
            fileStream.Write(BitConverter.GetBytes((ushort) 1), 0, 2);
            fileStream.Write(BitConverter.GetBytes(channelCount), 0, 2);
            fileStream.Write(BitConverter.GetBytes(sampleRate), 0, 4);
            fileStream.Write(BitConverter.GetBytes(sampleRate * channelCount * (bitDepth / 8)), 0, 4);
            fileStream.Write(BitConverter.GetBytes((ushort) channelCount * (bitDepth / 8)), 0, 2);
            fileStream.Write(BitConverter.GetBytes(bitDepth), 0, 2);
            fileStream.Write(Encoding.ASCII.GetBytes("data"), 0, 4);
            fileStream.Write(BitConverter.GetBytes(0), 0, 4);
        }
    }

    private bool MyRecording(int handle, IntPtr buffer, int length, IntPtr user)
    {
        byte[] buf = new byte[length];
        Marshal.Copy(buffer, buf, 0, length);
        _fileStream.Write(buf, 0, buf.Length);
        return true;
    }
public void StartRecord()
    {
        Bass.BASS_RecordInit(-1);
        _myRecProc = new RECORDPROC(MyRecording);
        _recHandle = Bass.BASS_RecordStart(44100, 2, BASSFlag.BASS_RECORD_PAUSE, _myRecProc, IntPtr.Zero);
        WriteWavHeader();

        _fileStream = new FileStream(CommonSettings.Instance.GetAndroidFriendlyFilesPath() + "/" + _fileName, FileMode.Open, FileAccess.Write, FileShare.None);
        _fileStream.Position = 44;

        Debug.Log(CommonSettings.Instance.GetAndroidFriendlyFilesPath() + "/" + _fileName);
        BassEnc.BASS_Encode_Start(_recHandle, "lame --alt-preset standard - 666666.mp3", 0, null, IntPtr.Zero);
       
        Bass.BASS_ChannelPlay(_recHandle, false);
    }

    public void StopRecord()
    {
        if (BassEnc.BASS_Encode_Stop(_recHandle))
        {
            Debug.Log("ok");
        }
        else
        {
            Debug.Log(Bass.BASS_ErrorGetCode());
        }
             
        Bass.BASS_ChannelStop(_recHandle);

        _fileStream.Position = 40;
        _fileStream.Write(BitConverter.GetBytes(_fileStream.Length - 44), 0, 4);
        _fileStream.Close();

        Bass.BASS_RecordFree();
    }
Now i got BASS_ERROR_HANDLE on BASS_Encode_Stop

Luiz

  • Posts: 12
Re: Recording and ecnoding to mp3
« Reply #1 on: 4 Oct '18 - 15:42 »
Hi, in delphi I used  the addon dll bassenc_mp3     
  BASS_Encode_MP3_StartFile(handle, 0, BASS_ENCODE_FP_AUTO or BASS_UNICODE, PChar(OutputFileName));

Ian @ un4seen

  • Administrator
  • Posts: 21372
Re: Recording and ecnoding to mp3
« Reply #2 on: 4 Oct '18 - 16:46 »
Yep, the easiest way to do it is to use the BASSenc_MP3 add-on. For example, you could replace this line:

Code: [Select]
        BassEnc.BASS_Encode_Start(_recHandle, "lame --alt-preset standard - 666666.mp3", 0, null, IntPtr.Zero);

With this:

Code: [Select]
        int result = BassEnc_MP3.BASS_Encode_MP3_StartFile(_recHandle, "--alt-preset standard", 0, "666666.mp3");

Note that call will probably fail with a BASS_ERROR_CREATE error, in which case you should provide a full pathname (somewhere writeable) for the output file. You also don't need to do anything in the MyRecording function (just "return true") when using an encoder.

teq

  • Posts: 26
Re: Recording and ecnoding to mp3
« Reply #3 on: 5 Oct '18 - 10:24 »
Yep, the easiest way to do it is to use the BASSenc_MP3 add-on. For example, you could replace this line:

Code: [Select]
        BassEnc.BASS_Encode_Start(_recHandle, "lame --alt-preset standard - 666666.mp3", 0, null, IntPtr.Zero);

With this:

Code: [Select]
        int result = BassEnc_MP3.BASS_Encode_MP3_StartFile(_recHandle, "--alt-preset standard", 0, "666666.mp3");

Note that call will probably fail with a BASS_ERROR_CREATE error, in which case you should provide a full pathname (somewhere writeable) for the output file. You also don't need to do anything in the MyRecording function (just "return true") when using an encoder.

I use Bass.Net and have installed bassenc_mp3, but i have only BassEnc_Flac, BassEnc_Ogg, BassEnc_Opus. May be BassEnc_MP3 is not supported in Bass.Net ?
And is it possible to pause recording and encoding and then continue ?
« Last Edit: 5 Oct '18 - 11:39 by teq »

Ian @ un4seen

  • Administrator
  • Posts: 21372
Re: Recording and ecnoding to mp3
« Reply #4 on: 5 Oct '18 - 13:55 »
I use Bass.Net and have installed bassenc_mp3, but i have only BassEnc_Flac, BassEnc_Ogg, BassEnc_Opus. May be BassEnc_MP3 is not supported in Bass.Net ?

Yes, BASS.Net unfortunately doesn't currently include support for the BASSenc_MP3 add-on. An update including support should be available soon.

And is it possible to pause recording and encoding and then continue ?

You can pause a recording (and encoder on it) using BASS_ChannelPause, and resume it using BASS_ChannelPlay.

Bello

  • Posts: 40
Re: Recording and ecnoding to mp3
« Reply #5 on: 6 Oct '18 - 21:03 »
When using Bass.Net, you could use the EncoderMP3 class, in combination with lame.exe.

Ian @ un4seen

  • Administrator
  • Posts: 21372
Re: Recording and ecnoding to mp3
« Reply #6 on: 8 Oct '18 - 14:34 »
The original poster appears to be using Android. Unfortunately, command-line encoders like LAME.EXE aren't available there, so the only way to use LAME is to build it into the app. There are some posts about doing that on this forum (from before BASSenc_MP3 was available) but it's much simpler to use the BASSenc_MP3 add-on.

If you can't wait, I think it is possible to import the BASSenc_MP3 functions directly (without going through BASS.Net) by using "DllImport", perhaps something like this:

Code: [Select]
[DllImport("libbassenc_mp3.so")]
public static extern int BASS_Encode_MP3_StartFile(int handle, string options, int flags, string filename);

radio42

  • Posts: 4637
Re: Recording and ecnoding to mp3
« Reply #7 on: 9 Oct '18 - 08:56 »
I hope to ship a new Bass.Net version later this week!

teq

  • Posts: 26
Re: Recording and ecnoding to mp3
« Reply #8 on: 13 Oct '18 - 10:50 »
By the way does it possible to check freq in current recorded stream to make some kind of guitar tuner?
And another one) Can i use fx compressor while recording (i need some noise remove) and then save eventually processed stream?
« Last Edit: 13 Oct '18 - 11:01 by teq »

Ian @ un4seen

  • Administrator
  • Posts: 21372
Re: Recording and ecnoding to mp3
« Reply #9 on: 15 Oct '18 - 13:04 »
By the way does it possible to check freq in current recorded stream to make some kind of guitar tuner?

Yes, that is possible. Here's a previous thread on the subject:

   www.un4seen.com/forum/?topic=13623

And another one) Can i use fx compressor while recording (i need some noise remove) and then save eventually processed stream?

Yes, if you set a compressor effect on the recording channel handle (from BASS_RecordStart), it will be present in the recorded/encoded file. You could use the BASS_FX add-on's BASS_FX_BFX_COMPRESSOR2 effect (via BASS_ChannelSetFX) for that.

teq

  • Posts: 26
Re: Recording and ecnoding to mp3
« Reply #10 on: 20 Oct '18 - 14:02 »
Yep, the easiest way to do it is to use the BASSenc_MP3 add-on. For example, you could replace this line:

Code: [Select]
        BassEnc.BASS_Encode_Start(_recHandle, "lame --alt-preset standard - 666666.mp3", 0, null, IntPtr.Zero);

With this:

Code: [Select]
        int result = BassEnc_MP3.BASS_Encode_MP3_StartFile(_recHandle, "--alt-preset standard", 0, "666666.mp3");

Note that call will probably fail with a BASS_ERROR_CREATE error, in which case you should provide a full pathname (somewhere writeable) for the output file. You also don't need to do anything in the MyRecording function (just "return true") when using an encoder.
Hi! And thanks a lot for answers! In my case user can listen a song and then he can record some parallel line, but if he change current track position i need to record stream also change in this position. Can i achive this somehow?
So, in my opinion it can't be achives with BASS_Encode_MP3_StartFile, only with
Yep, the easiest way to do it is to use the BASSenc_MP3 add-on. For example, you could replace this line:

Code: [Select]
        BassEnc.BASS_Encode_Start(_recHandle, "lame --alt-preset standard - 666666.mp3", 0, null, IntPtr.Zero);

With this:

Code: [Select]
        int result = BassEnc_MP3.BASS_Encode_MP3_StartFile(_recHandle, "--alt-preset standard", 0, "666666.mp3");

Note that call will probably fail with a BASS_ERROR_CREATE error, in which case you should provide a full pathname (somewhere writeable) for the output file. You also don't need to do anything in the MyRecording function (just "return true") when using an encoder.
Hi! And thanks a lot for answers! In my case user can listen a song and then he can record some parallel line, but if he change current track position i need to record stream also change in this position. Can i achive this somehow?
<Start>--<OldPos>------------<NewPos>------<End>
So, in my opinion it can't be achived with BASS_Encode_MP3_StartFile, and have to use BASS_Encode_Start but fill empty space from OldPos to NewPos with zeroes, and continue writing record stream from NewPos. Am i right?

And one moment about volume detection. Is method is right solution?
Code: [Select]
int level = Bass.BASS_ChannelGetLevel(_recHandle);
level  = Utils.LevelToDB(level, 32768);
« Last Edit: 22 Oct '18 - 14:31 by teq »

Ian @ un4seen

  • Administrator
  • Posts: 21372
Re: Recording and ecnoding to mp3
« Reply #11 on: 22 Oct '18 - 15:46 »
Hi! And thanks a lot for answers! In my case user can listen a song and then he can record some parallel line, but if he change current track position i need to record stream also change in this position. Can i achive this somehow?
<Start>--<OldPos>------------<NewPos>------<End>
So, in my opinion it can't be achived with BASS_Encode_MP3_StartFile, and have to use BASS_Encode_Start but fill empty space from OldPos to NewPos with zeroes, and continue writing record stream from NewPos. Am i right?

Do you mean you are encoding the file while it's playing, and when playback jumps from OldPos to NewPos, you want the encoded file to do the same? If so, that will happen automatically because the encoder receives the sample data as it is decoded/played, ie. if playback changes position then so will the encoding.

And one moment about volume detection. Is method is right solution?
Code: [Select]
int level = Bass.BASS_ChannelGetLevel(_recHandle);
level  = Utils.LevelToDB(level, 32768);

BASS_ChannelGetLevel returns the left level in the low 16 bits and the right level in the high 16 bits, so you will need to extract each from the return value before converting to dB, like this:

Code: [Select]
int level = Bass.BASS_ChannelGetLevel(_recHandle);
double leftlevel  = Utils.LevelToDB(Utils.LowWord32(level), 32768);
double rightlevel  = Utils.LevelToDB(Utils.HighWord32(level), 32768);