PageRenderTime 105ms CodeModel.GetById 40ms app.highlight 20ms RepoModel.GetById 42ms app.codeStats 0ms

/thirdparty/liblastfm2/src/fingerprint/contrib/VorbisSource.cpp

http://github.com/tomahawk-player/tomahawk
C++ | 204 lines | 137 code | 32 blank | 35 comment | 26 complexity | 51c0f8ca1470a6d15108837cf0ce758d MD5 | raw file
  1/*
  2   Copyright 2009 Last.fm Ltd. 
  3   Copyright 2009 John Stamp <jstamp@users.sourceforge.net>
  4
  5   This file is part of liblastfm.
  6
  7   liblastfm is free software: you can redistribute it and/or modify
  8   it under the terms of the GNU General Public License as published by
  9   the Free Software Foundation, either version 3 of the License, or
 10   (at your option) any later version.
 11
 12   liblastfm is distributed in the hope that it will be useful,
 13   but WITHOUT ANY WARRANTY; without even the implied warranty of
 14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15   GNU General Public License for more details.
 16
 17   You should have received a copy of the GNU General Public License
 18   along with liblastfm.  If not, see <http://www.gnu.org/licenses/>.
 19*/
 20#include "VorbisSource.h"
 21#include <QFile>
 22#include <cassert>
 23#include <cstdlib>
 24#include <iostream>
 25#include <limits>
 26#include <stdexcept>
 27#include <errno.h>
 28
 29// These specify the output format
 30static const int wordSize = 2; // 16 bit output
 31static const int isSigned = 1;
 32#if __BIG_ENDIAN__
 33static const int isBigEndian = 1;
 34#else
 35static const int isBigEndian = 0;
 36#endif
 37
 38
 39VorbisSource::VorbisSource()
 40    : m_channels( 0 )
 41    , m_samplerate( 0 )
 42    , m_eof( false )
 43{
 44    memset( &m_vf, 0, sizeof(m_vf) );
 45}
 46
 47// ---------------------------------------------------------------------
 48
 49VorbisSource::~VorbisSource()
 50{
 51    // ov_clear() also closes the file
 52    ov_clear( &m_vf );
 53}
 54
 55// ---------------------------------------------------------------------
 56
 57void VorbisSource::init(const QString& fileName)
 58{
 59    m_fileName = fileName;
 60    
 61    if ( m_vf.datasource )
 62    {
 63        std::cerr << "Warning: file already appears to be open";
 64        return;
 65    }
 66
 67    FILE *fp = fopen(QFile::encodeName(m_fileName), "rb" );
 68    if( !fp )
 69        throw std::runtime_error( "ERROR: Cannot open ogg file!" );
 70
 71    // See the warning about calling ov_open on Windows
 72    if ( ov_test_callbacks( fp, &m_vf, NULL, 0, OV_CALLBACKS_DEFAULT ) < 0 )
 73    {
 74        fclose( fp );
 75        throw std::runtime_error( "ERROR: This is not an ogg vorbis file!" );
 76    }
 77
 78    ov_test_open( &m_vf );
 79
 80    // Don't fingerprint files with more than one logical bitstream
 81    // They most likely contain more than one track
 82    if ( ov_streams( &m_vf ) != 1 )
 83        throw std::runtime_error( "ERROR: ogg file contains multiple bitstreams" );
 84
 85    m_channels = ov_info( &m_vf, 0 )->channels;
 86    m_samplerate = static_cast<int>(ov_info( &m_vf, 0 )->rate);
 87    m_eof = false;
 88}
 89
 90void VorbisSource::getInfo( int& lengthSecs, int& samplerate, int& bitrate, int& nchannels)
 91{
 92    // stream info
 93    nchannels = ov_info( &m_vf, -1 )->channels;
 94    samplerate = static_cast<int>(ov_info( &m_vf, -1 )->rate);
 95    lengthSecs = static_cast<int>(ov_time_total( &m_vf, -1 ) + 0.5);
 96    bitrate = static_cast<int>(ov_bitrate( &m_vf, -1 ));
 97}
 98
 99// ---------------------------------------------------------------------
100
101void VorbisSource::skip( const int mSecs )
102{
103    if ( mSecs < 0 )
104        return;
105
106    double ts = mSecs / 1000.0 + ov_time_tell( &m_vf );
107    ov_time_seek( &m_vf, ts );
108}
109
110// ---------------------------------------------------------------------
111
112void VorbisSource::skipSilence(double silenceThreshold /* = 0.0001 */)
113{
114    silenceThreshold *= static_cast<double>( std::numeric_limits<short>::max() );
115
116    char sampleBuffer[4096];
117    int bs = 0;
118    for (;;)
119    {
120        long charReadBytes = ov_read( &m_vf, sampleBuffer, 4096, isBigEndian, wordSize, isSigned, &bs );
121
122        // eof
123        if ( !charReadBytes )
124        {
125            m_eof = true;
126            break;
127        }
128        if ( charReadBytes < 0 )
129        {
130            // a bad bit of data: OV_HOLE || OV_EBADLINK
131            continue;
132        }
133        else if ( charReadBytes > 0 )
134        {
135            double sum = 0;
136            int16_t *buf = reinterpret_cast<int16_t*>(sampleBuffer);
137            switch ( m_channels )
138            {
139                case 1:
140                    for (long j = 0; j < charReadBytes/wordSize; j++)
141                        sum += abs( buf[j] );
142                    break;
143                case 2:
144                    for (long j = 0; j < charReadBytes/wordSize; j+=2)
145                        sum += abs( (buf[j] >> 1) + (buf[j+1] >> 1) );
146                    break;
147            }
148            if ( sum >= silenceThreshold * static_cast<double>(charReadBytes/wordSize/m_channels) )
149                break;
150        }
151    }
152}
153
154// ---------------------------------------------------------------------
155
156int VorbisSource::updateBuffer( signed short *pBuffer, size_t bufferSize )
157{
158    char buf[ bufferSize * wordSize ];
159    int bs = 0;
160    size_t charwrit = 0; //number of samples written to the output buffer
161
162    for (;;)
163    {
164        long charReadBytes = ov_read( &m_vf, buf, static_cast<int>(bufferSize * wordSize - charwrit),
165                                      isBigEndian, wordSize, isSigned, &bs );
166        if ( !charReadBytes )
167        {
168            m_eof = true;
169            break; // nothing else to read
170        }
171
172        // Don't really need this though since we're excluding files that have
173        // more than one logical bitstream
174        if ( bs != 0 )
175        {
176            vorbis_info *vi = ov_info( &m_vf, -1 );
177            if ( m_channels != vi->channels || m_samplerate != vi->rate )
178            {
179                std::cerr << "Files that change channel parameters or samplerate are currently not supported" << std::endl;
180                return 0;
181            }
182        }
183
184        if( charReadBytes < 0 )
185        {
186            std::cerr << "Warning: corrupt section of data, attempting to continue..." << std::endl;
187            continue;
188        }
189
190        char* pBufferIt = reinterpret_cast<char*>(pBuffer) + charwrit;
191        charwrit += charReadBytes;
192
193        assert( charwrit <= bufferSize * wordSize );
194        memcpy( pBufferIt, buf, charReadBytes );
195
196      if (charwrit == bufferSize * wordSize)
197         return static_cast<int>(charwrit/wordSize);
198   }
199
200   return static_cast<int>(charwrit/wordSize);
201}
202
203// -----------------------------------------------------------------------------
204