Link to home
Start Free TrialLog in
Avatar of so3
so3Flag for Romania

asked on

Convert bytes to flac_int32

I'm trying to compress wave with FLAC codec but i don't know how to convert bytes to flac__int32. Here is the code i'm trying to make it work.

bool static FlacEncode(array<Byte>^ BytesToEncode,int nAudioBytesLeft)
                  {
                        unsigned char *cBuffer;
                        cBuffer =(unsigned char *)malloc(nAudioBytesLeft);
                        
                        for (int i =0; i < nAudioBytesLeft; ++i)
                              cBuffer[i]=BytesToEncode[i];
                  
                        while (nAudioBytesLeft > 0)
                        {
                              int nBytesToAdd = nAudioBytesLeft;

                              /* feed samples to encoder */
                              ok = FLAC__stream_encoder_process_interleaved(encoder, (FLAC__int32*)&cBuffer[0], nBytesToAdd);
                              nAudioBytesLeft -= nBytesToAdd;
                        }
                        return true;
                  }
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

What error do you get?
jkr: The code being called isn't managed C++ Why can't it stay put?
ASKER CERTIFIED SOLUTION
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Have a look in the header file to see what FLAC__int32 actually is.
It will probably be just a synonym for 32bit unsigned integer or something.
>> What does 'array<Byte>^' do in standard C++ other than create an error message? ;o)
I'm just pointing out the code he is trying to interface to isn't managed code so it is as much a non managed code Q and it is a manage Q! You; however, are the administrator so, as you wish!
Avatar of so3

ASKER

thanks evilrix,

I will test it home, so you think that the procedure should be like this.

bool static FlacEncode(array<Byte>^ BytesToEncode,int nAudioBytesLeft)
                  {
                        unsigned char *cBuffer;
                        cBuffer =(unsigned char *)malloc(nAudioBytesLeft);
                       
                        for (int i =0; i < nAudioBytesLeft; ++i)
                              cBuffer[i]=BytesToEncode[i];
                 
                        while (nAudioBytesLeft > 0)
                        {
                              int nBytesToAdd = nAudioBytesLeft;

                              /* feed samples to encoder */
                              ok = FLAC__stream_encoder_process_interleaved(encoder, reinterpret_cast<FLAC__int32*>(cBuffer), nBytesToAdd);
                              nAudioBytesLeft -= nBytesToAdd;
                        }
                        return true;
                  }

In their example is like this(is reading from a wav file)
static FLAC__int32 pcm[READSIZE/*samples*/ * 2/*channels*/];


/* read blocks of samples from WAVE file and feed to encoder */
      if(ok) {
            size_t left = (size_t)total_samples;
            while(ok && left) {
                  size_t need = (left>READSIZE? (size_t)READSIZE : (size_t)left);
                  if(fread(buffer, channels*(bps/8), need, fin) != need) {
                        fprintf(stderr, "ERROR: reading from WAVE file\n");
                        ok = false;
                  }
                  else {
                        /* convert the packed little-endian 16-bit PCM samples from WAVE into an interleaved FLAC__int32 buffer for libFLAC */
                        size_t i;
                        for(i = 0; i < need*channels; i++) {
                              /* inefficient but simple and works on big- or little-endian machines */
                              pcm[i] = (FLAC__int32)(((FLAC__int16)(FLAC__int8)buffer[2*i+1] << 8) | (FLAC__int16)buffer[2*i]);
                        }
                        /* feed samples to encoder */
                        ok = FLAC__stream_encoder_process_interleaved(encoder, pcm, need);
                  }
                  left -= need;
            }
      }
>> so you think that the procedure should be like this
My only assertion is that the mechanism I've suggested for casting should compile -- as to whether the cast is safe or not is another matter. The only guarantee you have when converting from one pointer to another is that you can safely convert back again. Any other usage of that point is undefined -- which doesn't mean it is unsafe, just that the standard doesn't define what behavior you can expect since it largely depends what you've converted from/to and what you plan to do with that converted pointer. Certainly reinterpret_cast is safer than a C style cast as it won't allow you to accidentally cast to a pointer type that is not compatible -- e.g. variable pointer to function pointer; where as a C style cast will.

http://msdn2.microsoft.com/en-us/library/e0w9f63b(VS.80).aspx

"The result of a reinterpret_cast cannot safely be used for anything other than being cast back to its original type. Other uses are, at best, nonportable."

NB. The same is true of C style casts

The example code seems overly complex in the elaborate way the casting is being done; however, I have no knowledge of this code-base so I wouldn't suggest it is wrong. I think, try the reinterpret_cast and if that work then great, if not try to analyze the example code to see why they have such an elaborate multi-casting construct.

Good luck.

-Rx.
Avatar of so3

ASKER

I've tested with your sugestion, i can compile it and id don't receive an error on first time but if i try it again i get error "atempted to read and write protected memory"

Can you please take a look at my code maybe you can give me a sugestion why this isn't working. It's all about the casts i think, but unfortunatly i don't know how to use them in c++. Also if you have time please take a look at the encoder example from FLAC at this link:

http://sourceforge.net/project/showfiles.php?group_id=13478&package_id=12677



My code:

bool static StartEncoder(System::String^ outputfile, int CompressionLevel,int rate, int bits, int channels)
                  {
                        char *  filename=(char*)(void*)Marshal::StringToHGlobalAnsi(outputfile->ToString());
                        
                        sample_rate = rate;
                        channels = channels;
                        bps = bits;
                        //total_samples = (((((((unsigned)buffer[43] << 8) | buffer[42]) << 8) | buffer[41]) << 8) | buffer[40]) / 4;
                        /* allocate the encoder */
                        if((encoder = FLAC__stream_encoder_new()) == NULL) {
                              return false;
                        }
                        ok &= FLAC__stream_encoder_set_verify(encoder, true);
                        ok &= FLAC__stream_encoder_set_compression_level(encoder, CompressionLevel);
                        ok &= FLAC__stream_encoder_set_channels(encoder, channels);
                        ok &= FLAC__stream_encoder_set_bits_per_sample(encoder, bps);
                        ok &= FLAC__stream_encoder_set_sample_rate(encoder, sample_rate);
                        //ok &= FLAC__stream_encoder_set_total_samples_estimate(encoder, total_samples);

                        /* now add some metadata; we'll add some tags and a padding block */
                        if(ok) {
                              if(
                                    (metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) == NULL ||
                                    (metadata[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == NULL ||
                                    /* there are many tag (vorbiscomment) functions but these are convenient for this particular use: */
                                    !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "ARTIST", "Some Artist") ||
                                    !FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, /*copy=*/false) || /* copy=false: let metadata object take control of entry's allocated string */
                                    !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "YEAR", "1984") ||
                                    !FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, /*copy=*/false)
                              ) {
                                    fprintf(stderr, "ERROR: out of memory or tag error\n");
                                    ok = false;
                                    return false;
                              }

                              metadata[1]->length = 1234; /* set the padding length */

                              ok = FLAC__stream_encoder_set_metadata(encoder, metadata, 2);
                        }
                        /* initialize encoder */
                        if(ok) {
                              init_status = FLAC__stream_encoder_init_file(encoder, filename, progress_callback, /*client_data=*/NULL);
                              if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
                                    fprintf(stderr, "ERROR: initializing encoder: %s\n", FLAC__StreamEncoderInitStatusString[init_status]);
                                    ok = false;
                                    return false;
                              }
                        }
                        return true;
            }


            bool static FlacEncode(array<Byte>^ BytesToEncode,int nAudioBytesLeft)
                  {
                        unsigned char *cBuffer;
                        cBuffer =(unsigned char *)malloc(nAudioBytesLeft);
                        
                        for (int i =0; i < nAudioBytesLeft; ++i)
                              cBuffer[i]=BytesToEncode[i];
                  
                        while (nAudioBytesLeft > 0)
                        {
                              int nBytesToAdd = nAudioBytesLeft;

                              /* feed samples to encoder */
                              ok = FLAC__stream_encoder_process_interleaved(encoder, reinterpret_cast<FLAC__int32*>(cBuffer), nBytesToAdd);
                              nAudioBytesLeft -= nBytesToAdd;
                        }
                        return true;
                  }

            bool static CloseEncoder()
            {
                  ok &= FLAC__stream_encoder_finish(encoder);

                  /* now that encoding is finished, the metadata can be freed */
                  FLAC__metadata_object_delete(metadata[0]);
                  FLAC__metadata_object_delete(metadata[1]);

                  FLAC__stream_encoder_delete(encoder);
                  encoder=NULL;
                  return ok;
            }
Avatar of so3

ASKER

Forget about the error on second time(it was from a bool value). Now i don't receive any error but the file is only 1.3k. It seems that only the header is written.
I'm being hassled to go out by my wife so I can't look right now but I can tell you there seems to be a memory leak in FlacEncode -- you malloc cBuffer but never free it.
Avatar of so3

ASKER

Thanks for the tip. you're right i've corrected the code with free(cBuffer).
I think the simplest thing for you to do is use the debugger to step through the code. Put a break point in the part that writes out the bit that seems to be missing and when it's hit step into the code and see what's happening. If your break-point isn't hit this is probably the reason it's not writing :)
Avatar of so3

ASKER

I've tried this too. It steps through the writting code  and i don't receive any error. I'm so confused, i don't receive errors but the output code is only 1.3k.
could be about the casting or the problem is elsewhere?

I've noticed that i repeat the encoding without modifing the code the output size is changing 1.3k, 13k

If you have any ideas, please let me know.
Can you publish the full code here so I can download it and review it?

http://www.ee-stuff.com/

That might make this simpler :)
Avatar of so3

ASKER

Here is the link:
https://filedb.experts-exchange.com/incoming/ee-stuff/5676-Rippers.zip

I'm working with visual studio 2008 so the project is in 2008. the sample contains the project in C# which gets the wav bytes from a CD track and send to it to FlacWriter which is supposed to encode it. You have to attach the project JS.Flac to the main project.

I've played a little with the code and i think that the problem is in casting because i've the part of reading bytes from a file from their example and it works fine.
Avatar of so3

ASKER

static FLAC__byte buffer[READSIZE/*samples*/ * 2/*bytes_per_sample*/ * 2/*channels*/]; /* we read the WAVE data into here */

size_t left = (size_t)total_samples;
while(ok && left) {
size_t need = (left>READSIZE? (size_t)READSIZE : (size_t)left);
 if(fread(buffer, channels*(bps/8), need, fin) != need) {
 fprintf(stderr, "ERROR: reading from WAVE file\n");
 ok = false;
      }

Can  the above code reads from array<Byte>^ BytesToEncode instead of the file?
I think that might be the problem
Objection: I answered the original question!

The question: "I'm trying to compress wave with FLAC codec but i don't know how to convert bytes to flac__int32. Here is the code i'm trying to make it work."

The answer: https://www.experts-exchange.com/questions/22964276/Convert-bytes-to-flac-int32.html?cid=238#20292780

I also pointed out that just because I'd shown him how to perform the cast doesn't mean the cast is safe nor correct!

The OP then introduced a new problem that I was unable to diagnose, which was only identified once I helped him/her get the code to build!
Avatar of so3

ASKER

thanks for your help evilrix
You are very welcome.