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