Guest User

Untitled

a guest
Dec 6th, 2019
209
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.84 KB | None | 0 0
  1. from argparse import ArgumentParser
  2. from subprocess import Popen, PIPE
  3. import matplotlib.pyplot as plt
  4. import traceback
  5. import pickle
  6. import sys
  7. import os
  8.  
  9.  
  10. parser = ArgumentParser()
  11. parser.add_argument('--mode', required=True,
  12. choices=['before', 'after', 'plot'],
  13. help="Use 'before 'to analyze keys the first time, use 'after' to " \
  14. "analyze the keys again after using Mixed in Key and compare the " \
  15. "results to the 'before' run, use 'plot' to visualize results")
  16. parser.add_argument('--path',
  17. help='base path to directory for song key analysis')
  18. parser.add_argument('--exclude', default=[], nargs='+',
  19. help='list of genres to exclude from plot')
  20. args = parser.parse_args()
  21.  
  22.  
  23. def plot(old_keys, diff_keys):
  24.  
  25. def bar_text(bars, values):
  26. print(len(bars), len(values))
  27. for b, bar_type in enumerate(bars):
  28. print(f"bar type {b} is {bar_type}")
  29. for idx,rect in enumerate(bar_type):
  30. print(f"\trect {idx} value: {values[b][idx]}")
  31. height = rect.get_height() / 2
  32. height += sum([x[idx].get_height() for x in bars[:b]])
  33. ax.text(rect.get_x() + rect.get_width()/2, height,
  34. values[b][idx],
  35. ha='center', va='bottom', rotation=0)
  36.  
  37. fig, ax = plt.subplots()
  38.  
  39. # ensure keys are in sorted order
  40. key_order = sorted(old_keys.keys())
  41. temp1, temp2 = {}, {}
  42. for k in key_order:
  43. if k.lower() not in [x.lower() for x in args.exclude]:
  44. temp1[k] = old_keys[k]
  45. temp2[k] = diff_keys[k]
  46. old_keys = temp1
  47. diff_keys = temp2
  48.  
  49. ############################################################################
  50. #### Percentage stacked bar chart -- key changes overall #################
  51. ############################################################################
  52.  
  53. # get numbers for overall key analysis
  54. total_songs = sum([len(v) for v in old_keys.values()])
  55. changed_songs = sum([len(v) for v in diff_keys.values()])
  56. same_songs = total_songs - changed_songs
  57.  
  58. # get numbers for per genre key analysis
  59. data = {'Changed': [len(v) for v in diff_keys.values()],
  60. 'Same': [len(old_keys[k]) - len(v) for k,v in diff_keys.items()]}
  61.  
  62. # from count values to percentages
  63. totals = [len(v) for v in old_keys.values()]
  64. changed_bars = [changed_songs / total_songs * 100] + [i / j * 100 for i,j in zip(data['Changed'], totals)]
  65. same_bars = [same_songs / total_songs * 100] + [i / j * 100 for i,j in zip(data['Same'], totals)]
  66. bar_data = [changed_bars, same_bars]
  67.  
  68. # plot
  69. barWidth = 0.85
  70. names = ['Overall'] + list(old_keys.keys())
  71. r = list(range(len(names)))
  72. bars = []
  73.  
  74. bars.append(plt.bar(r, changed_bars, color='#f9bc86', edgecolor='white',
  75. width=barWidth, label="Changed"))
  76. bars.append(plt.bar(r, same_bars, bottom=changed_bars, color='#b5ffb9',
  77. edgecolor='white', width=barWidth, label="Same"))
  78. bar_text(bars, [[changed_songs] + data['Changed'], [same_songs] + data['Same']])
  79.  
  80. plt.xticks(r, names, rotation=90)
  81. plt.xlabel("Genre")
  82. plt.ylabel("Number of songs")
  83. plt.legend(loc='upper right', bbox_to_anchor=(1.1,1.1), ncol=1)
  84. #plt.tight_layout(pad=2)
  85. plt.yticks([])
  86. plt.title('Changed/same keys')
  87. plt.show()
  88.  
  89. ############################################################################
  90. #### Bar chart -- type of key change #####################################
  91. ############################################################################
  92.  
  93. fig, ax = plt.subplots()
  94.  
  95. # get numbers for per genre key analysis
  96. data = {}
  97. key_change_types = {
  98. 'Major/minor': 0,
  99. 'Minor/major': 0,
  100. 'Root': 0,
  101. 'Major/minor and root': 0,
  102. 'Minor/major and root': 0}
  103. for k,v in diff_keys.items():
  104. data[k] = key_change_types.copy()
  105. for song, keys in v.items():
  106. before,after = keys
  107.  
  108. if not before or not after:
  109. continue
  110.  
  111. if before[-1] == 'A' and after[-1] == 'B' \
  112. and before[:-1] != after[:-1]:
  113. data[k]['Major/minor and root'] += 1
  114. elif before[-1] == 'B' and after[-1] == 'A' \
  115. and before[:-1] != after[:-1]:
  116. data[k]['Minor/major and root'] += 1
  117. elif before[-1] == 'A' and after[-1] == 'B':
  118. data[k]['Major/minor'] += 1
  119. elif before[-1] == 'B' and after[-1] == 'A':
  120. data[k]['Minor/major'] += 1
  121. else:
  122. data[k]['Root'] += 1
  123.  
  124. # from count values to percentages
  125. totals = [sum(v.values()) for v in data.values()]
  126. all_totals = sum(totals)
  127. counts = [[data[k][k_type] for k,total in zip(data.keys(), totals)]
  128. for k_type in key_change_types.keys()]
  129. counts_all = [sum(x) for x in counts]
  130. bars = [[data[k][k_type] / total * 100 for k,total in zip(data.keys(), totals)]
  131. for k_type in key_change_types.keys()]
  132. bars_all = [sum([data[k][k_type] for k in data.keys()]) / all_totals * 100
  133. for k_type in key_change_types.keys()]
  134. for i,each in enumerate(bars):
  135. each.insert(0, bars_all[i])
  136. for i,each in enumerate(counts):
  137. each.insert(0, counts_all[i])
  138.  
  139. # plot
  140. barWidth = 0.85
  141. names = ['Overall'] + list(data.keys())
  142. r = list(range(len(names)))
  143.  
  144. colors = ['#e7fb78',
  145. '#fcc400',
  146. '#fe7f08',
  147. '#1b79c7',
  148. '#001fc0']
  149.  
  150. _bars = []
  151. bottoms = [0 for _ in r]
  152. for b,bar in enumerate(bars):
  153. if b == 0:
  154. _bars.append(plt.bar(r, bar, color=colors[b], edgecolor='white',
  155. width=barWidth, label=list(key_change_types.keys())[b]))
  156. else:
  157. _bars.append(plt.bar(r, bar, color=colors[b], edgecolor='white',
  158. width=barWidth, label=list(key_change_types.keys())[b],
  159. bottom=bottoms))
  160. for x,y in enumerate(bar):
  161. bottoms[x] += y
  162. bar_text(_bars, counts)
  163.  
  164. plt.xticks(r, names, rotation=90)
  165. plt.xlabel("Genre")
  166. plt.ylabel("Number of songs")
  167. plt.legend(loc='upper right', bbox_to_anchor=(1.1,1.2), ncol=1)
  168. plt.yticks([])
  169. plt.title('Type of key change')
  170. plt.show()
  171.  
  172.  
  173. if args.mode in ['before', 'after']:
  174. if not args.path:
  175. sys.exit(f"'path' is a required argument in '{args.mode}' mode")
  176.  
  177. if args.mode == 'after':
  178. try:
  179. old_keys = pickle.load(open('keys.pkl', 'rb'))
  180. except FileNotFoundError:
  181. sys.exit('No existing keys.pkl file -- run in before mode first to get initial song keys')
  182.  
  183. diff_keys = {}
  184. removed_songs = []
  185. same = different = 0
  186.  
  187. base = args.path
  188. keys = {}
  189. cmd1 = ['ffprobe', '']
  190. cmd2 = ['grep', 'TKEY']
  191. for d in os.listdir(base):
  192. print(f"Getting {d} keys")
  193. path = base + d + '/'
  194. keys[d] = {}
  195.  
  196. if args.mode == 'after':
  197. diff_keys[d] = {}
  198.  
  199. songs = os.listdir(path)
  200. for s, song in enumerate(songs, start=1):
  201. if s % 50 == 0:
  202. print(f"\tsong {s} of {len(songs)}")
  203. cmd1[1] = path + song
  204. proc1 = Popen(cmd1, stderr=PIPE)
  205. proc2 = Popen(cmd2, stdin=proc1.stderr, stdout=PIPE)
  206. proc1.stderr.close()
  207. out = proc2.communicate()
  208.  
  209. try:
  210. key = out[0].decode('utf-8').split(':')[-1].strip()
  211. keys[d][song] = key
  212. if args.mode == 'after':
  213. if old_keys[d][song] != key:
  214. diff_keys[d][song] = (old_keys[d][song], key)
  215. different += 1
  216. else:
  217. same += 1
  218. except KeyError:
  219. if song.startswith('._'):
  220. removed_songs.append(song)
  221. os.remove(path + song)
  222.  
  223. if args.mode == 'after':
  224. print('Removed songs:')
  225. for s in removed_songs:
  226. print('\t',s)
  227.  
  228. print(f"same: {same}\ndifferent: {different}")
  229. pickle.dump(diff_keys, open('diff_keys.pkl', 'wb'))
  230. plot(old_keys, diff_keys)
  231. else:
  232. pickle.dump(keys, open('keys.pkl', 'wb'))
  233. else:
  234. try:
  235. old_keys = pickle.load(open('keys.pkl', 'rb'))
  236. except FileNotFoundError:
  237. sys.exit("No existing keys.pkl file -- run in 'before' mode first to get initial song keys")
  238.  
  239. try:
  240. diff_keys = pickle.load(open('diff_keys.pkl', 'rb'))
  241. except FileNotFoundError:
  242. sys.exit("No existing diff_keys.pkl file -- run in 'after' mode first to get adjustedsong keys")
  243.  
  244. plot(old_keys, diff_keys)
Advertisement
Add Comment
Please, Sign In to add comment