libmpcdec: src/sample.cpp Source File

Main Page | Class List | Directories | File List | Class Members | File Members | Related Pages

# sample.cpp

    00001 /*
    00002   Copyright (c) 2005, The Musepack Development Team
    00003   All rights reserved.
    00004
    00005   Redistribution and use in source and binary forms, with or without
    00006   modification, are permitted provided that the following conditions are
    00007   met:
    00008
    00009   * Redistributions of source code must retain the above copyright
    00010   notice, this list of conditions and the following disclaimer.
    00011
    00012   * Redistributions in binary form must reproduce the above
    00013   copyright notice, this list of conditions and the following
    00014   disclaimer in the documentation and/or other materials provided
    00015   with the distribution.
    00016
    00017   * Neither the name of the The Musepack Development Team nor the
    00018   names of its contributors may be used to endorse or promote
    00019   products derived from this software without specific prior
    00020   written permission.
    00021
    00022   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    00023   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    00024   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    00025   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    00026   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    00027   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    00028   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    00029   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    00030   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    00031   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    00032   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    00033 */
    00034
    00035 #include <stdio.h>
    00036 #include <assert.h>
    00037 #include <time.h>
    00038
    00039 #include <mpcdec/mpcdec.h>
    00040
    00041 /*
    00042   The data bundle we pass around with our reader to store file
    00043   position and size etc.
    00044 */
    00045 typedef struct reader_data_t {
    00046     FILE *file;
    00047     long size;
    00048     mpc_bool_t seekable;
    00049 } reader_data;
    00050
    00051 /*
    00052   Our implementations of the mpc_reader callback functions.
    00053 */
    00054 mpc_int32_t
    00055 read_impl(void *data, void *ptr, mpc_int32_t size)
    00056 {
    00057     reader_data *d = (reader_data *) data;
    00058     return fread(ptr, 1, size, d->file);
    00059 }
    00060
    00061 mpc_bool_t
    00062 seek_impl(void *data, mpc_int32_t offset)
    00063 {
    00064     reader_data *d = (reader_data *) data;
    00065     return d->seekable ? !fseek(d->file, offset, SEEK_SET) : false;
    00066 }
    00067
    00068 mpc_int32_t
    00069 tell_impl(void *data)
    00070 {
    00071     reader_data *d = (reader_data *) data;
    00072     return ftell(d->file);
    00073 }
    00074
    00075 mpc_int32_t
    00076 get_size_impl(void *data)
    00077 {
    00078     reader_data *d = (reader_data *) data;
    00079     return d->size;
    00080 }
    00081
    00082 mpc_bool_t
    00083 canseek_impl(void *data)
    00084 {
    00085     reader_data *d = (reader_data *) data;
    00086     return d->seekable;
    00087 }
    00088
    00089 #define WFX_SIZE (2+2+4+4+2+2)
    00090
    00091 #ifdef MPC_FIXED_POINT
    00092 static int
    00093 shift_signed(MPC_SAMPLE_FORMAT val, int shift)
    00094 {
    00095     if (shift > 0)
    00096         val <<= shift;
    00097     else if (shift < 0)
    00098         val >>= -shift;
    00099     return (int)val;
    00100 }
    00101 #endif
    00102
    00103 class WavWriter {
    00104   public:
    00105     WavWriter(FILE * p_output, unsigned p_nch, unsigned p_bps,
    00106               unsigned p_srate)
    00107     : m_file(p_output), m_nch(p_nch), m_bps(p_bps), m_srate(p_srate) {
    00108         assert(m_bps == 16 || m_bps == 24);
    00109
    00110         WriteRaw("RIFF", 4);
    00111         WriteDword(0);          //fix this in destructor
    00112
    00113         WriteRaw("WAVE", 4);
    00114         WriteRaw("fmt ", 4);
    00115         WriteDword(WFX_SIZE);
    00116
    00117         WriteWord(1);           //WAVE_FORMAT_PCM
    00118         WriteWord(m_nch);
    00119         WriteDword(m_srate);
    00120         WriteDword(m_srate * m_nch * (m_bps >> 3));
    00121         WriteWord(m_nch * (m_bps >> 3));
    00122         WriteWord(m_bps);
    00123         /*
    00124            WORD  wFormatTag;
    00125            WORD  nChannels;
    00126            DWORD nSamplesPerSec;
    00127            DWORD nAvgBytesPerSec;
    00128            WORD  nBlockAlign;
    00129            WORD  wBitsPerSample;
    00130          */
    00131         WriteRaw("data", 4);
    00132         WriteDword(0);          //fix this in destructor
    00133
    00134         m_data_bytes_written = 0;
    00135     } mpc_bool_t WriteSamples(const MPC_SAMPLE_FORMAT * p_buffer, unsigned p_size) {
    00136         unsigned n;
    00137         int clip_min = -1 << (m_bps - 1),
    00138             clip_max = (1 << (m_bps - 1)) - 1, float_scale = 1 << (m_bps - 1);
    00139         for (n = 0; n < p_size; n++) {
    00140             int val;
    00141 #ifdef MPC_FIXED_POINT
    00142             val =
    00143                 shift_signed(p_buffer[n],
    00144                              m_bps - MPC_FIXED_POINT_SCALE_SHIFT);
    00145 #else
    00146             val = (int)(p_buffer[n] * float_scale);
    00147 #endif
    00148             if (val < clip_min)
    00149                 val = clip_min;
    00150             else if (val > clip_max)
    00151                 val = clip_max;
    00152             if (!WriteInt(val, m_bps))
    00153                 return false;
    00154         }
    00155         m_data_bytes_written += p_size * (m_bps >> 3);
    00156         return true;
    00157     }
    00158
    00159     ~WavWriter() {
    00160         if (m_data_bytes_written & 1) {
    00161             char blah = 0;
    00162             WriteRaw(&blah, 1);
    00163             m_data_bytes_written++;
    00164         }
    00165         Seek(4);
    00166         WriteDword((unsigned long)(m_data_bytes_written + 4 + 8 + WFX_SIZE +
    00167                                    8));
    00168         Seek(8 + 4 + 8 + WFX_SIZE + 4);
    00169         WriteDword(m_data_bytes_written);
    00170     }
    00171
    00172   private:
    00173
    00174     mpc_bool_t Seek(unsigned p_offset) {
    00175         return !fseek(m_file, p_offset, SEEK_SET);
    00176     }
    00177
    00178     mpc_bool_t WriteRaw(const void *p_buffer, unsigned p_bytes) {
    00179         return fwrite(p_buffer, 1, p_bytes, m_file) == p_bytes;
    00180     }
    00181
    00182     mpc_bool_t WriteDword(unsigned long p_val) {
    00183         return WriteInt(p_val, 32);
    00184     }
    00185     mpc_bool_t WriteWord(unsigned short p_val) {
    00186         return WriteInt(p_val, 16);
    00187     }
    00188
    00189     // write a little-endian number properly
    00190     mpc_bool_t WriteInt(unsigned int p_val, unsigned p_width_bits) {
    00191         unsigned char temp;
    00192         unsigned shift = 0;
    00193         assert((p_width_bits % 8) == 0);
    00194         do {
    00195             temp = (unsigned char)((p_val >> shift) & 0xFF);
    00196             if (!WriteRaw(&temp, 1))
    00197                 return false;
    00198             shift += 8;
    00199         } while (shift < p_width_bits);
    00200         return true;
    00201     }
    00202
    00203     unsigned m_nch, m_bps, m_srate;
    00204     FILE *m_file;
    00205     unsigned m_data_bytes_written;
    00206 };
    00207
    00208
    00209 static void
    00210 usage(const char *exename)
    00211 {
    00212     printf
    00213         ("Usage: %s <infile.mpc> [<outfile.wav>]\nIf <outfile.wav> is not specified, decoder will run in benchmark mode.\n",
    00214          exename);
    00215 }
    00216
    00217 int
    00218 main(int argc, char **argv)
    00219 {
    00220     if (argc != 2 && argc != 3) {
    00221         if (argc > 0)
    00222             usage(argv[0]);
    00223         return 0;
    00224     }
    00225
    00226     FILE *input = fopen(argv[1], "rb");
    00227     FILE *output = 0;
    00228     if (input == 0) {
    00229         usage(argv[0]);
    00230         printf("Error opening input file: \"%s\"\n", argv[1]);
    00231         return 1;
    00232     }
    00233
    00234     if (argc == 3) {
    00235         output = fopen(argv[2], "wb");
    00236         if (output == 0) {
    00237             fclose(input);
    00238             usage(argv[0]);
    00239             printf("Error opening output file: \"%s\"\n", argv[2]);
    00240             return 1;
    00241         }
    00242     }
    00243
    00244     /* initialize our reader_data tag the reader will carry around with it */
    00245     reader_data data;
    00246     data.file = input;
    00247     data.seekable = true;
    00248     fseek(data.file, 0, SEEK_END);
    00249     data.size = ftell(data.file);
    00250     fseek(data.file, 0, SEEK_SET);
    00251
    00252     /* set up an mpc_reader linked to our function implementations */
    00253     mpc_decoder decoder;
    00254     mpc_reader reader;
    00255     reader.read = read_impl;
    00256     reader.seek = seek_impl;
    00257     reader.tell = tell_impl;
    00258     reader.get_size = get_size_impl;
    00259     reader.canseek = canseek_impl;
    00260     reader.data = &data;
    00261
    00262     /* read file's streaminfo data */
    00263     mpc_streaminfo info;
    00264     mpc_streaminfo_init(&info);
    00265     if (mpc_streaminfo_read(&info, &reader) != ERROR_CODE_OK) {
    00266         printf("Not a valid musepack file: \"%s\"\n", argv[1]);
    00267         return 1;
    00268     }
    00269
    00270     /* instantiate a decoder with our file reader */
    00271     mpc_decoder_setup(&decoder, &reader);
    00272     if (!mpc_decoder_initialize(&decoder, &info)) {
    00273         printf("Error initializing decoder.\n", argv[1]);
    00274         return 1;
    00275     }
    00276
    00277     /* decode the file */
    00278     printf("Decoding from:\n%s\nTo:\n%s\n", argv[1],
    00279            output ? argv[2] : "N/A");
    00280     WavWriter *wavwriter =
    00281         output ? new WavWriter(output, 2, 16, info.sample_freq) : 0;
    00282     MPC_SAMPLE_FORMAT sample_buffer[MPC_DECODER_BUFFER_LENGTH];
    00283     clock_t begin, end;
    00284     begin = clock();
    00285     unsigned total_samples = 0;
    00286     mpc_bool_t successful = FALSE;
    00287     for (;;) {
    00288         unsigned status = mpc_decoder_decode(&decoder, sample_buffer, 0, 0);
    00289         if (status == (unsigned)(-1)) {
    00290             //decode error
    00291             printf("Error decoding file.\n");
    00292             break;
    00293         }
    00294         else if (status == 0)   //EOF
    00295         {
    00296             successful = true;
    00297             break;
    00298         }
    00299         else                    //status>0
    00300         {
    00301             total_samples += status;
    00302             if (wavwriter) {
    00303                 if (!wavwriter->
    00304                     WriteSamples(sample_buffer, status * /* stereo */ 2)) {
    00305                     printf("Write error.\n");
    00306                     break;
    00307                 }
    00308             }
    00309         }
    00310     }
    00311
    00312     end = clock();
    00313
    00314     if (wavwriter) {
    00315         delete wavwriter;
    00316     }
    00317
    00318     if (successful) {
    00319         printf("\nFinished.\nTotal samples decoded: %u.\n", total_samples);
    00320         unsigned ms = (end - begin) * 1000 / CLOCKS_PER_SEC;
    00321         unsigned ratio =
    00322             (unsigned)((double)total_samples / (double)info.sample_freq /
    00323                        ((double)ms / 1000.0) * 100.0);
    00324         printf("Time: %u ms (%u.%02ux).\n", ms, ratio / 100, ratio % 100);
    00325     }
    00326
    00327     return 0;
    00328 }