decoder.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. from __future__ import absolute_import
  2. import os
  3. import sys
  4. import fnmatch
  5. import numpy as np
  6. from pydub import AudioSegment
  7. from pydub.utils import audioop
  8. from dejavu import wavio
  9. from hashlib import sha1
  10. DEFAULT_FS = int(44100 / 2)
  11. if sys.version_info >= (3, 0):
  12. xrange = range
  13. def unique_hash(filepath, blocksize=2**20):
  14. """ Small function to generate a hash to uniquely generate
  15. a file. Inspired by MD5 version here:
  16. http://stackoverflow.com/a/1131255/712997
  17. Works with large files.
  18. """
  19. s = sha1()
  20. with open(filepath , "rb") as f:
  21. while True:
  22. buf = f.read(blocksize)
  23. if not buf:
  24. break
  25. s.update(buf)
  26. return s.hexdigest().upper()
  27. def find_files(path, extensions):
  28. # Allow both with ".mp3" and without "mp3" to be used for extensions
  29. extensions = [e.replace(".", "") for e in extensions]
  30. for dirpath, dirnames, files in os.walk(path):
  31. for extension in extensions:
  32. for f in fnmatch.filter(files, "*.%s" % extension):
  33. p = os.path.join(dirpath, f)
  34. yield (p, extension)
  35. def read_chunks(filename, chunk_size = 1, start = 0, fmt = None):
  36. start = start * 1000
  37. chunk_size = chunk_size * 1000
  38. filename_hash = unique_hash(filename)
  39. try:
  40. audiofile = AudioSegment.from_file(filename,fmt)
  41. if audiofile.frame_rate != DEFAULT_FS:
  42. audiofile = audiofile.set_frame_rate(DEFAULT_FS)
  43. while True:
  44. end = start + chunk_size
  45. audio_chunk = audiofile[start:end]
  46. if len(audio_chunk) == 0:
  47. return;
  48. data = np.fromstring(audio_chunk._data, np.int16)
  49. channels = []
  50. for chn in xrange(audio_chunk.channels):
  51. channels.append(data[chn::audio_chunk.channels])
  52. yield channels, audio_chunk.frame_rate,filename_hash, len(audio_chunk)
  53. start = end
  54. except audioop.error:
  55. fs, _, audiofile = wavio.readwav(filename)
  56. if audiofile.frame_rate != DEFAULT_FS:
  57. audiofile = audiofile.set_frame_rate(DEFAULT_FS)
  58. while True:
  59. end = start + chunk_size
  60. audio_chunk = audiofile[start:end]
  61. if len(audio_chunk) == 0:
  62. return;
  63. audio_chunk = audio_chunk.T
  64. audio_chunk = audio_chunk.astype(np.int16)
  65. channels = []
  66. for chn in audio_chunk:
  67. channels.append(chn)
  68. yield channels, audio_chunk.frame_rate, filename_hash, len(audio_chunk)
  69. start = end
  70. def read(filename, limit=None, fmt = None, offset = 0):
  71. """
  72. Reads any file supported by pydub (ffmpeg) and returns the data contained
  73. within. If file reading fails due to input being a 24-bit wav file,
  74. wavio is used as a backup.
  75. Can be optionally limited to a certain amount of seconds from the start
  76. of the file by specifying the `limit` parameter. This is the amount of
  77. seconds from the start of the file.
  78. returns: (channels, samplerate)
  79. """
  80. if limit:
  81. offset = offset * 1000
  82. limit = offset + limit * 1000
  83. # pydub does not support 24-bit wav files, use wavio when this occurs
  84. try:
  85. audiofile = AudioSegment.from_file(filename,fmt)
  86. if audiofile.frame_rate != DEFAULT_FS:
  87. audiofile = audiofile.set_frame_rate(DEFAULT_FS)
  88. if limit:
  89. audiofile = audiofile[offset:limit]
  90. data = np.fromstring(audiofile._data, np.int16)
  91. channels = []
  92. for chn in xrange(audiofile.channels):
  93. channels.append(data[chn::audiofile.channels])
  94. fs = audiofile.frame_rate
  95. except audioop.error:
  96. fs, _, audiofile = wavio.readwav(filename)
  97. if audiofile.frame_rate != DEFAULT_FS:
  98. audiofile = audiofile.set_frame_rate(DEFAULT_FS)
  99. if limit:
  100. audiofile = audiofile[offset:limit]
  101. audiofile = audiofile.T
  102. audiofile = audiofile.astype(np.int16)
  103. channels = []
  104. for chn in audiofile:
  105. channels.append(chn)
  106. return channels, audiofile.frame_rate, unique_hash(filename), len(audiofile)
  107. def path_to_songname(path):
  108. """
  109. Extracts song name from a filepath. Used to identify which songs
  110. have already been fingerprinted on disk.
  111. """
  112. return os.path.splitext(os.path.basename(path))[0]