|
@@ -1,6 +1,6 @@
|
1
|
1
|
##| Copyright: (C) 2019-2020 Kevin Larke <contact AT larke DOT org>
|
2
|
2
|
##| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
|
3
|
|
-import os, sys,json
|
|
3
|
+import os, sys,json,math
|
4
|
4
|
import matplotlib.pyplot as plt
|
5
|
5
|
import numpy as np
|
6
|
6
|
from common import parse_yaml_cfg
|
|
@@ -458,17 +458,43 @@ def _plot_us_db_takes( inDir, cfg, pitchL, takeIdL, printDir="", printFn="" ):
|
458
|
458
|
|
459
|
459
|
usL, dbL, durMsL, _, holdDutyPctL = get_merged_pulse_db_measurements( inDir, midi_pitch, analysisArgsD['rmsAnalysisArgs'], takeId=takeId )
|
460
|
460
|
|
|
461
|
+
|
461
|
462
|
ax.plot(usL,dbL, marker='.',label="%i:%i %s %s" % (midi_pitch,takeId,keyMapD[midi_pitch]['class'],keyMapD[midi_pitch]['type']))
|
462
|
463
|
|
463
|
|
- # for i,(x,y) in enumerate(zip(usL,dbL)):
|
464
|
|
- # ax.text(x,y,str(i))
|
|
464
|
+ for i,(x,y) in enumerate(zip(usL,dbL)):
|
|
465
|
+ ax.text(x,y,str(i))
|
465
|
466
|
|
|
467
|
+ f_usL,f_dbL = filter_us_db(usL,dbL)
|
|
468
|
+
|
|
469
|
+ ax.plot(f_usL,f_dbL, marker='.')
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+ elbow_us,elbow_db = elbow.find_elbow(usL,dbL)
|
|
473
|
+ ax.plot([elbow_us],[elbow_db],marker='*',markersize=12,color='red',linestyle='None')
|
|
474
|
+
|
|
475
|
+ elb_idx = nearest_sample_point( dbL, usL, elbow_db, elbow_us )
|
466
|
476
|
|
467
|
477
|
if printDir:
|
468
|
478
|
plt.savefig(os.path.join(printDir,printFn),format="png")
|
469
|
479
|
|
470
|
480
|
plt.legend()
|
471
|
481
|
plt.show()
|
|
482
|
+
|
|
483
|
+def get_pitches_and_takes( inDir ):
|
|
484
|
+
|
|
485
|
+ pitchD = {}
|
|
486
|
+ inDirL = os.listdir( inDir )
|
|
487
|
+
|
|
488
|
+ for pitch in inDirL:
|
|
489
|
+ path = os.path.join( inDir, pitch )
|
|
490
|
+ takeIdL = os.listdir( path )
|
|
491
|
+
|
|
492
|
+ takeIdL = sorted([ int(takeId) for takeId in takeIdL ])
|
|
493
|
+ takeIdL = [ str(x) for x in takeIdL ]
|
|
494
|
+ pitchD[int(pitch)] = takeIdL
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+ return pitchD
|
472
|
498
|
|
473
|
499
|
def plot_us_db_takes( inDir, cfg, pitchL, printDir=""):
|
474
|
500
|
|
|
@@ -480,14 +506,11 @@ def plot_us_db_takes( inDir, cfg, pitchL, printDir=""):
|
480
|
506
|
|
481
|
507
|
def plot_us_db_takes_last( inDir, cfg, pitchL, printDir ):
|
482
|
508
|
|
|
509
|
+ pitchD = get_pitches_and_takes(inDir)
|
|
510
|
+
|
483
|
511
|
takeIdL = []
|
484
|
512
|
for pitch in pitchL:
|
485
|
|
-
|
486
|
|
- inDirL = os.listdir( os.path.join(inDir,str(pitch)))
|
487
|
|
-
|
488
|
|
- inDirL = sorted(inDirL)
|
489
|
|
-
|
490
|
|
- takeIdL.append( int(inDirL[-1]) )
|
|
513
|
+ takeIdL.append( int(pitchD[pitch][-1]) )
|
491
|
514
|
|
492
|
515
|
return _plot_us_db_takes( inDir, cfg, pitchL, takeIdL, printDir, "us_db_takes_last.png")
|
493
|
516
|
|
|
@@ -535,17 +558,21 @@ def plot_all_noise_curves( inDir, cfg, pitchL=None ):
|
535
|
558
|
plt.legend()
|
536
|
559
|
plt.show()
|
537
|
560
|
|
538
|
|
-def plot_min_max_2_db( inDir, cfg, pitchL=None, takeId=2, printDir=None ):
|
|
561
|
+def nearest_sample_point( dbL, usL, db0, us0 ):
|
|
562
|
+ xL = np.array([ abs(us-us0) for db,us in zip(dbL,usL) ])
|
539
|
563
|
|
540
|
|
- pitchFolderL = os.listdir(inDir)
|
|
564
|
+ return np.argmin(xL)
|
541
|
565
|
|
542
|
|
- print(pitchL)
|
|
566
|
+
|
|
567
|
+def plot_min_max_2_db( inDir, cfg, pitchL=None, takeId=2, printDir=None ):
|
543
|
568
|
|
|
569
|
+ takeIdArg = takeId
|
|
570
|
+ pitchTakeD = get_pitches_and_takes(inDir)
|
|
571
|
+
|
|
572
|
+ pitchFolderL = os.listdir(inDir)
|
544
|
573
|
if pitchL is None:
|
545
|
574
|
pitchL = [ int( int(pitchFolder) ) for pitchFolder in pitchFolderL ]
|
546
|
575
|
|
547
|
|
- print(pitchL)
|
548
|
|
-
|
549
|
576
|
okL = []
|
550
|
577
|
outPitchL = []
|
551
|
578
|
minDbL = []
|
|
@@ -553,9 +580,11 @@ def plot_min_max_2_db( inDir, cfg, pitchL=None, takeId=2, printDir=None ):
|
553
|
580
|
|
554
|
581
|
for midi_pitch in pitchL:
|
555
|
582
|
|
556
|
|
- print(midi_pitch)
|
|
583
|
+ takeId = None
|
|
584
|
+ if takeIdArg == -1:
|
|
585
|
+ takeId = pitchTakeD[midi_pitch][-1]
|
557
|
586
|
|
558
|
|
- usL, dbL, durMsL, takeIdL, holdDutyPctL = get_merged_pulse_db_measurements( inDir, midi_pitch, cfg.analysisArgs['rmsAnalysisArgs'] )
|
|
587
|
+ usL, dbL, durMsL, takeIdL, holdDutyPctL = get_merged_pulse_db_measurements( inDir, midi_pitch, cfg.analysisArgs['rmsAnalysisArgs'], takeId )
|
559
|
588
|
|
560
|
589
|
okL.append(False)
|
561
|
590
|
|
|
@@ -571,6 +600,9 @@ def plot_min_max_2_db( inDir, cfg, pitchL=None, takeId=2, printDir=None ):
|
571
|
600
|
minDbL.append(elbow_db)
|
572
|
601
|
outPitchL.append(midi_pitch)
|
573
|
602
|
|
|
603
|
+ smp_idx = nearest_sample_point( dbL, usL, elbow_db, elbow_us )
|
|
604
|
+
|
|
605
|
+ print(" %i:[-1,%i], " % (midi_pitch,smp_idx))
|
574
|
606
|
|
575
|
607
|
|
576
|
608
|
p_dL = sorted( zip(outPitchL,minDbL,maxDbL,okL), key=lambda x: x[0] )
|
|
@@ -593,7 +625,9 @@ def plot_min_max_2_db( inDir, cfg, pitchL=None, takeId=2, printDir=None ):
|
593
|
625
|
|
594
|
626
|
plt.show()
|
595
|
627
|
|
596
|
|
-def plot_min_db_manual( inDir, cfg, printDir=None ):
|
|
628
|
+def plot_min_db_manual( inDir, cfg, printDir=None, absMaxDb=27, absMinDb=3 ):
|
|
629
|
+
|
|
630
|
+ pitchTakeD = get_pitches_and_takes(inDir)
|
597
|
631
|
|
598
|
632
|
pitchL = list(cfg.manualMinD.keys())
|
599
|
633
|
|
|
@@ -606,30 +640,40 @@ def plot_min_db_manual( inDir, cfg, printDir=None ):
|
606
|
640
|
|
607
|
641
|
for midi_pitch in pitchL:
|
608
|
642
|
|
609
|
|
- manual_take_id = cfg.manualMinD[midi_pitch][0]
|
|
643
|
+ if cfg.manualLastFl:
|
|
644
|
+ manual_take_id = pitchTakeD[midi_pitch][-1]
|
|
645
|
+ takeId = manual_take_id
|
|
646
|
+ else:
|
|
647
|
+ manual_take_id = cfg.manualMinD[midi_pitch][0]
|
|
648
|
+ takeId = None
|
|
649
|
+
|
610
|
650
|
manual_sample_idx = cfg.manualMinD[midi_pitch][1]
|
611
|
651
|
|
612
|
|
- usL, dbL, durMsL, takeIdL, holdDutyPctL = get_merged_pulse_db_measurements( inDir, midi_pitch, cfg.analysisArgs['rmsAnalysisArgs'] )
|
|
652
|
+ usL, dbL, durMsL, takeIdL, holdDutyPctL = get_merged_pulse_db_measurements( inDir, midi_pitch, cfg.analysisArgs['rmsAnalysisArgs'], takeId )
|
613
|
653
|
|
614
|
654
|
okL.append(False)
|
615
|
655
|
|
616
|
|
- takeId = len(set(takeIdL))-1
|
|
656
|
+ if takeId is None:
|
|
657
|
+ takeId = len(set(takeIdL))-1
|
617
|
658
|
|
|
659
|
+ # most pitches have 3 sample takes that do not
|
|
660
|
+ if len(set(takeIdL)) == 3 and manual_take_id == takeId:
|
|
661
|
+ okL[-1] = True
|
|
662
|
+ else:
|
|
663
|
+ okL[-1] = True
|
|
664
|
+
|
618
|
665
|
# maxDb is computed on all takes (not just the specified take)
|
619
|
666
|
db_maxL = sorted(dbL)
|
620
|
|
- max_db = np.mean(db_maxL[-4:])
|
|
667
|
+ max_db = min(absMaxDb,np.mean(db_maxL[-4:]))
|
621
|
668
|
maxDbL.append( max_db )
|
622
|
669
|
|
623
|
670
|
# get the us,db values for the specified take
|
624
|
671
|
usL,dbL = zip(*[(usL[i],dbL[i]) for i in range(len(usL)) if takeIdL[i]==manual_take_id ])
|
625
|
672
|
|
626
|
|
- # most pitches have 3 sample takes that do not
|
627
|
|
- if len(set(takeIdL)) == 3 and manual_take_id == takeId:
|
628
|
|
- okL[-1] = True
|
629
|
673
|
|
630
|
674
|
# min db from the sample index manually specified in cfg
|
631
|
|
- manualMinDb = dbL[ manual_sample_idx ]
|
632
|
|
-
|
|
675
|
+ manualMinDb = max(absMinDb,dbL[ manual_sample_idx ])
|
|
676
|
+
|
633
|
677
|
minDbL.append( manualMinDb )
|
634
|
678
|
outPitchL.append(midi_pitch)
|
635
|
679
|
|
|
@@ -642,8 +686,6 @@ def plot_min_db_manual( inDir, cfg, printDir=None ):
|
642
|
686
|
|
643
|
687
|
|
644
|
688
|
|
645
|
|
-
|
646
|
|
-
|
647
|
689
|
# Form the complete set of min/max db levels for each pitch by interpolating the
|
648
|
690
|
# db values between the manually selected anchor points.
|
649
|
691
|
interpMinDbL = np.interp( pitchL, cfg.manualAnchorPitchMinDbL, anchorMinDbL )
|
|
@@ -861,27 +903,67 @@ def report_take_ids( inDir ):
|
861
|
903
|
if len(takeDirL) == 0:
|
862
|
904
|
print(pitch," directory empty")
|
863
|
905
|
else:
|
864
|
|
- with open( os.path.join(pitchDir,'0','seq.json'), "rb") as f:
|
865
|
|
- r = json.load(f)
|
|
906
|
+
|
|
907
|
+ fn = os.path.join(pitchDir,'0','seq.json')
|
|
908
|
+
|
|
909
|
+ if not os.path.isfile(fn):
|
|
910
|
+ print("Missing sequence file:",fn)
|
|
911
|
+ else:
|
|
912
|
+ with open( fn, "rb") as f:
|
|
913
|
+ r = json.load(f)
|
866
|
914
|
|
867
|
|
- if len(r['eventTimeL']) != 81:
|
868
|
|
- print(pitch," ",len(r['eventTimeL']))
|
|
915
|
+
|
|
916
|
+ if len(r['eventTimeL']) != 81:
|
|
917
|
+ print(pitch," ",len(r['eventTimeL']))
|
|
918
|
+
|
|
919
|
+ if len(takeDirL) != 3:
|
|
920
|
+ print("***",pitch,len(takeDirL))
|
|
921
|
+
|
|
922
|
+def filter_us_db( us0L, db0L ):
|
|
923
|
+
|
|
924
|
+ us1L = [us0L[-1]]
|
|
925
|
+ db1L = [db0L[-1]]
|
|
926
|
+ dDb = 0
|
|
927
|
+ lastIdx = 0
|
|
928
|
+ for i,(us,db) in enumerate(zip( us0L[::-1],db0L[::-1])):
|
|
929
|
+ db1 = db1L[-1]
|
|
930
|
+ if db < db1 and db1-db >= dDb/2:
|
|
931
|
+ dDb = db1 - db
|
|
932
|
+ us1L.append(us)
|
|
933
|
+ db1L.append(db)
|
|
934
|
+ lastIdx = i
|
869
|
935
|
|
870
|
|
- if len(takeDirL) != 3:
|
871
|
|
- print("***",pitch,len(takeDirL))
|
872
|
936
|
|
|
937
|
+ lastIdx = len(us0L) - lastIdx - 1
|
|
938
|
+
|
|
939
|
+
|
|
940
|
+ usL = [ us0L[lastIdx] ]
|
|
941
|
+ dbL = [ db0L[lastIdx] ]
|
|
942
|
+ dDb = 0
|
|
943
|
+ for us,db in zip(us0L[lastIdx::],db0L[lastIdx::]):
|
|
944
|
+ db1 = dbL[-1]
|
|
945
|
+ if db > db1:
|
|
946
|
+ dDb = db-db1
|
|
947
|
+ usL.append(us)
|
|
948
|
+ dbL.append(db)
|
|
949
|
+
|
|
950
|
+ return usL,dbL
|
|
951
|
+
|
873
|
952
|
def cache_us_db( inDir, cfg, outFn ):
|
874
|
953
|
|
|
954
|
+ pitchTakeD = get_pitches_and_takes(inDir)
|
|
955
|
+
|
875
|
956
|
pitch_usDbD = {}
|
876
|
957
|
pitchDirL = os.listdir(inDir)
|
877
|
958
|
|
878
|
|
- for pitch in pitchDirL:
|
|
959
|
+ for pitch,takeIdL in pitchTakeD.items():
|
879
|
960
|
|
880
|
961
|
pitch = int(pitch)
|
|
962
|
+ takeId = takeIdL[-1]
|
881
|
963
|
|
882
|
964
|
print(pitch)
|
883
|
965
|
|
884
|
|
- usL, dbL, durMsL, takeIdL, holdDutyPctL = get_merged_pulse_db_measurements( inDir, pitch, cfg.analysisArgs['rmsAnalysisArgs'] )
|
|
966
|
+ usL, dbL, durMsL, takeIdL, holdDutyPctL = get_merged_pulse_db_measurements( inDir, pitch, cfg.analysisArgs['rmsAnalysisArgs'], takeId )
|
885
|
967
|
|
886
|
968
|
pitch_usDbD[pitch] = { 'usL':usL, 'dbL':dbL, 'durMsL':durMsL, 'takeIdL':takeIdL, 'holdDutyPctL': holdDutyPctL }
|
887
|
969
|
|
|
@@ -889,7 +971,7 @@ def cache_us_db( inDir, cfg, outFn ):
|
889
|
971
|
with open(outFn,"w") as f:
|
890
|
972
|
json.dump(pitch_usDbD,f)
|
891
|
973
|
|
892
|
|
-
|
|
974
|
+
|
893
|
975
|
|
894
|
976
|
def gen_vel_map( inDir, cfg, minMaxDbFn, dynLevelN, cacheFn ):
|
895
|
977
|
|
|
@@ -897,28 +979,44 @@ def gen_vel_map( inDir, cfg, minMaxDbFn, dynLevelN, cacheFn ):
|
897
|
979
|
|
898
|
980
|
pitchDirL = os.listdir(inDir)
|
899
|
981
|
|
|
982
|
+ # pitchUsDbD = { pitch:
|
900
|
983
|
with open(cacheFn,"r") as f:
|
901
|
984
|
pitchUsDbD = json.load(f)
|
902
|
985
|
|
903
|
986
|
|
|
987
|
+ # form minMaxDb = { pitch:(minDb,maxDb) }
|
904
|
988
|
with open("minInterpDb.json","r") as f:
|
905
|
989
|
r = json.load(f)
|
906
|
990
|
minMaxDbD = { pitch:(minDb,maxDb) for pitch,minDb,maxDb in zip(r['pitchL'],r['minDbL'],r['maxDbL']) }
|
907
|
|
-
|
908
|
991
|
|
|
992
|
+
|
909
|
993
|
pitchL = sorted( [ int(pitch) for pitch in pitchUsDbD.keys()] )
|
910
|
|
-
|
|
994
|
+
|
|
995
|
+ # for each pitch
|
911
|
996
|
for pitch in pitchL:
|
|
997
|
+
|
|
998
|
+ # get the us/db map for this
|
912
|
999
|
d = pitchUsDbD[str(pitch)]
|
|
1000
|
+
|
|
1001
|
+
|
|
1002
|
+ usL, dbL = filter_us_db( d['usL'], d['dbL'] )
|
|
1003
|
+ #usL = d['usL']
|
|
1004
|
+ #dbL = np.array(d['dbL'])
|
|
1005
|
+ dbL = np.array(dbL)
|
913
|
1006
|
|
914
|
|
- usL = d['usL']
|
915
|
|
- dbL = np.array(d['dbL'])
|
916
|
1007
|
|
917
|
1008
|
velMapD[pitch] = []
|
918
|
|
-
|
919
|
|
- for i in range(dynLevelN+1):
|
920
|
1009
|
|
921
|
|
- db = minMaxDbD[pitch][0] + (i * (minMaxDbD[pitch][1] - minMaxDbD[pitch][0])/ dynLevelN)
|
|
1010
|
+ maxDb = minMaxDbD[pitch][1]
|
|
1011
|
+ minDb = minMaxDbD[pitch][0]
|
|
1012
|
+
|
|
1013
|
+ dynLevelN = len(cfg.velTableDbL)
|
|
1014
|
+
|
|
1015
|
+ # for each dynamic level
|
|
1016
|
+ for i in range(dynLevelN):
|
|
1017
|
+
|
|
1018
|
+ #db = minDb + (i * (maxDb - minDb)/ dynLevelN)
|
|
1019
|
+ db = cfg.velTableDbL[i]
|
922
|
1020
|
|
923
|
1021
|
usIdx = np.argmin( np.abs(dbL - db) )
|
924
|
1022
|
|
|
@@ -946,7 +1044,7 @@ def gen_vel_map( inDir, cfg, minMaxDbFn, dynLevelN, cacheFn ):
|
946
|
1044
|
|
947
|
1045
|
if __name__ == "__main__":
|
948
|
1046
|
|
949
|
|
- printDir = None #os.path.expanduser( "~/src/picadae_ac_3/doc")
|
|
1047
|
+ printDir = os.path.expanduser("~/temp") # os.path.expanduser( "~/src/picadae_ac_3/doc")
|
950
|
1048
|
cfgFn = sys.argv[1]
|
951
|
1049
|
inDir = sys.argv[2]
|
952
|
1050
|
mode = sys.argv[3]
|
|
@@ -981,7 +1079,7 @@ if __name__ == "__main__":
|
981
|
1079
|
elif mode == 'manual_db':
|
982
|
1080
|
plot_min_db_manual( inDir, cfg, printDir=printDir )
|
983
|
1081
|
elif mode == 'gen_vel_map':
|
984
|
|
- gen_vel_map( inDir, cfg, "minInterpDb.json", 9, "cache_us_db.json" )
|
|
1082
|
+ gen_vel_map( inDir, cfg, "minInterpDb.json", 12, "cache_us_db.json" )
|
985
|
1083
|
elif mode == 'cache_us_db':
|
986
|
1084
|
cache_us_db( inDir, cfg, "cache_us_db.json")
|
987
|
1085
|
else:
|