Main Page | Class List | Directories | File List | 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 "musepack/musepack.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     BOOL 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 BOOL
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 BOOL
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     } BOOL 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     BOOL Seek(unsigned p_offset) {
00175         return !fseek(m_file, p_offset, SEEK_SET);
00176     }
00177 
00178     BOOL WriteRaw(const void *p_buffer, unsigned p_bytes) {
00179         return fwrite(p_buffer, 1, p_bytes, m_file) == p_bytes;
00180     }
00181 
00182     BOOL WriteDword(unsigned long p_val) {
00183         return WriteInt(p_val, 32);
00184     }
00185     BOOL WriteWord(unsigned short p_val) {
00186         return WriteInt(p_val, 16);
00187     }
00188 
00189     // write a little-endian number properly
00190     BOOL 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     BOOL 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 }

Generated on Sat Jan 22 09:34:07 2005 for libmusepack by  doxygen 1.4.1