19 Jun '13 - 21:39 *
Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
 
   Home   Help Search Login Register  
Pages: [1]
  Reply  |  Print  
Author Topic: Read and Encode CD Track into memory  (Read 543 times)
DutchJohn
Posts: 8


« on: 22 Jun '12 - 16:29 »
Reply with quoteQuote

Hi All,

since my first post as a very green newbee on Bass, I have come some way. I managed to play files from disk, files from an SQL database (mp3 as blobs) and CD tracks, and I thought to be ready for the next step, just combining my current 'victories'.

What I want now is get a CD track, read it and encode it using Lame into a byte array or memorystream to be played (much) later. Without any file creation.

so I get myself a stream:
_stream = BassCd.BASS_CD_StreamCreate(ct.driveNo, ct.trackNr - 1, BASSFlag.BASS_DEFAULT);

stick this into an encoder:
BassEnc.BASS_Encode_Start(_stream, "lame", BASSEncode.BASS_ENCODE_AUTOFREE, null, IntPtr.Zero)

and now all one needs to do is create the bytes:
MemoryStream m = new MemoryStream();
while (BassEnc.BASS_Encode_IsActive(_stream) != BASSActive.BASS_ACTIVE_STOPPED)
    byte[] buf = new byte[20000];                        // processing buffer
    BassEnc.BASS_Encode_Write(_stream, buf, buf.Length); // send the buffered data to the encoder
    m.Write(buf, 0, buf.Length);                         // append the stream
}
BassEnc.BASS_Encode_Stop(_stream); // close the encoder
and lo: I have a memorystream for later consumption.

I am afraid this was too easy, since the the loop to fill my memorystream never is entered.
Now I suspect it is 'just' setting the right switches, but for the life of me I cannot figure out which to use.

Does anyone have suggestion?

John
« Last Edit: 22 Jun '12 - 17:44 by DutchJohn » Logged
Ian @ un4seen
Administrator
Posts: 15366


« Reply #1 on: 22 Jun '12 - 17:56 »
Reply with quoteQuote

You will need to implement an ENCODEPROC function to receive the data from the encoder, and provide that in the BASS_Encode_Start call. You should also use BASS_ChannelGetData rather than BASS_Encode_Write, as you don't yet have any data to send the encoder, eg. there is nothing in the "buf" array in the code above.

The example I posted in your previous thread might be modified to use an ENCODEPROC like this...

void CALLBACK EncodeProc(HENCODE handle, DWORD channel, void *buffer, DWORD length, void *user)
{
// do something with the "length" bytes of data in "buffer"
}

...

HSTREAM decoder=BASS_CD_StreamCreate(drive, track, BASS_STREAM_DECODE); // create a "decoding channel" from a CD track
BASS_Encode_Start(decoder, "lame -", BASS_ENCODE_AUTOFREE, EncodeProc, NULL); // set an MP3 encoder (LAME) on it, and receive the encoded data via a callback
while (BASS_ChannelIsActive(decoder) && BASS_Encode_IsActive(decoder)) { // the decoder and encoder are still going
char buf [20000]; // processing buffer
BASS_ChannelGetData(decoder, buf, sizeof(buf)); // process some data
}
BASS_StreamFree(decoder); // free the decoder (and encoder due to AUTOFREE)
Logged
DutchJohn
Posts: 8


« Reply #2 on: 22 Jun '12 - 22:02 »
Reply with quoteQuote

Hi Ian,

quick reply!

I now changed my code to:
private ENCODEPROC _myEndoderProc;
 private void MyEncodingWriter(int handle, int channel, IntPtr buffer, int length, IntPtr user)
 {
  // copy from managed to unmanaged memory
  Marshal.Copy(buffer, _encbuffer, 0, length);
  // process the data in _encbuffer, e.g. write to disk or whatever
  m.Write(_encbuffer, 0, _encbuffer.Length);
  Console.WriteLine("callback with " + length);
 }

...and

 int _decoder = BassCd.BASS_CD_StreamCreate(ct.driveNo, ct.trackNr - 1, BASSFlag.BASS_STREAM_DECODE);
 _myEndoderProc = new ENCODEPROC(MyEncodingWriter);

 BassEnc.BASS_Encode_Start(_decoder, "lame -", BASSEncode.BASS_ENCODE_AUTOFREE, _myEndoderProc, IntPtr.Zero);
 m = new MemoryStream();
 while ((Bass.BASS_ChannelIsActive(_decoder) == BASSActive.BASS_ACTIVE_PLAYING)
     && (BassEnc.BASS_Encode_IsActive(_decoder) == BASSActive.BASS_ACTIVE_PLAYING))
 { // stream and encoder still running
   byte[] _encbuffer = new byte[20000]; // processing buffer
   Bass.BASS_ChannelGetData(_stream, _encbuffer, _encbuffer.Length); // send the buffered data to the encoder
 }
 Bass.BASS_StreamFree(_decoder); // free the decoder stream


(I changed the returntype of MyEncodingWriter to void because the compiler kept complaining)

But... the effect is still the same: jump straight over the while loop and do nothing.When I check the switches the Channel is active, but the Encoder is on stopped before the loop is entered.

Can it be an encoder problem? I downloaded the latest Lame (3.99.5) and put the lame_enc.dll in the directory, and used the PluginLoad directly after the init...

John


Logged
DutchJohn
Posts: 8


« Reply #3 on: 23 Jun '12 - 17:51 »
Reply with quoteQuote

I now moved the lame.exe into the library which resulted in the Encoder starting! (Stupid me: I assumed the lame dll was enough Embarrassed).
Still, there was only one pass through the while loop, where BASS-ChannelGetData returns -1, untill I noticed I had been tinkering with the lame command as well.
Reset that to "lame.exe -" and off it went: looping like mad! Great.
Increased the buffer from 20k to 1Mb and it still went looping like mad.
A bit too much: I interrupted the loop after some 25000(!) passes and no callback yet! And 25000 Mb is a bit more than would fit on that cd...
(ok, now for some food and football).

Later..
« Last Edit: 23 Jun '12 - 18:18 by DutchJohn » Logged
DutchJohn
Posts: 8


« Reply #4 on: 23 Jun '12 - 22:09 »
Reply with quoteQuote

I think I have to stop this post. Cry
My original plan was to read a cd track, encode in into memory and save it there for a while, and do the playback later on from memory as if it was a normal mp3 file. Basicaly feed the momory 'file' into the branches I already have that play mp3's. This would mean fast reading of the cd, take it out and still being able to play it.
After some more reading and searching it turns out that a 'normal' mp3 file has header information at the front of the file which is written by the encode at the last moment. Impossible to do while the encoded information in the meantime is led away to some place in memory. So what I would have in memory is a lot of encoded bytes that I would not be able to head or front from.
So I might as well give up before I waste any more of your time.
Ian, I apologise.

John
Logged
gnag
Posts: 160


« Reply #5 on: 24 Jun '12 - 17:31 »
Reply with quoteQuote

It would be an very interesting Player which is "sucking" the CDs right after you insert them, so you could insert it and listen to it and in the Background it automatically gets cached in the memory.

I could imagine for example if you close the Player or remove the CD / insert next one it could dump the CD Audio to the Disc, so in the end it grabs CDs automatically when you insert them once so you dont have to reinsert it again, if there are still people who preferer buying and storing Discs if they can buy MP3 instead ..
Logged
Ian @ un4seen
Administrator
Posts: 15366


« Reply #6 on: 25 Jun '12 - 16:38 »
Reply with quoteQuote

I now moved the lame.exe into the library which resulted in the Encoder starting! (Stupid me: I assumed the lame dll was enough Embarrassed).

Yep, it is the LAME.EXE file that is needed rather than the DLL.

After some more reading and searching it turns out that a 'normal' mp3 file has header information at the front of the file which is written by the encode at the last moment. Impossible to do while the encoded information in the meantime is led away to some place in memory. So what I would have in memory is a lot of encoded bytes that I would not be able to head or front from.

Although LAME will write a header, it isn't actually needed for the file to be playable (it just provides some additional info). So, for example, you should still be able to play the MP3 data by passing the memory block to BASS_StreamCreateFile.

If you are still having trouble with the encoding, please post your latest code to have a look at.
Logged
Pages: [1]
  Reply  |  Print  
 
Jump to:  

Powered by SMF 1.1.18 | SMF © 2013, Simple Machines