@@ -16,161 +16,6 @@ var _createCounterBuffer = function (buffer) {
16
16
return audioBuf ;
17
17
} ;
18
18
19
- // process peaks
20
- class Peak {
21
- constructor ( amp , i ) {
22
- this . sampleIndex = i ;
23
- this . amplitude = amp ;
24
- this . tempos = [ ] ;
25
- this . intervals = [ ] ;
26
- }
27
- }
28
-
29
- // 1. for processPeaks() Function to identify peaks above a threshold
30
- // returns an array of peak indexes as frames (samples) of the original soundfile
31
- function getPeaksAtThreshold ( data , threshold ) {
32
- var peaksObj = { } ;
33
- var length = data . length ;
34
-
35
- for ( var i = 0 ; i < length ; i ++ ) {
36
- if ( data [ i ] > threshold ) {
37
- var amp = data [ i ] ;
38
- var peak = new Peak ( amp , i ) ;
39
- peaksObj [ i ] = peak ;
40
- // Skip forward ~ 1/8s to get past this peak.
41
- i += 6000 ;
42
- }
43
- i ++ ;
44
- }
45
- return peaksObj ;
46
- }
47
-
48
- // 2. for processPeaks()
49
- function countIntervalsBetweenNearbyPeaks ( peaksObj ) {
50
- var intervalCounts = [ ] ;
51
- var peaksArray = Object . keys ( peaksObj ) . sort ( ) ;
52
-
53
- for ( var index = 0 ; index < peaksArray . length ; index ++ ) {
54
- // find intervals in comparison to nearby peaks
55
- for ( var i = 0 ; i < 10 ; i ++ ) {
56
- var startPeak = peaksObj [ peaksArray [ index ] ] ;
57
- var endPeak = peaksObj [ peaksArray [ index + i ] ] ;
58
-
59
- if ( startPeak && endPeak ) {
60
- var startPos = startPeak . sampleIndex ;
61
- var endPos = endPeak . sampleIndex ;
62
- var interval = endPos - startPos ;
63
-
64
- // add a sample interval to the startPeak in the allPeaks array
65
- if ( interval > 0 ) {
66
- startPeak . intervals . push ( interval ) ;
67
- }
68
-
69
- // tally the intervals and return interval counts
70
- var foundInterval = intervalCounts . some ( function ( intervalCount ) {
71
- if ( intervalCount . interval === interval ) {
72
- intervalCount . count ++ ;
73
- return intervalCount ;
74
- }
75
- } ) ;
76
-
77
- // store with JSON like formatting
78
- if ( ! foundInterval ) {
79
- intervalCounts . push ( {
80
- interval : interval ,
81
- count : 1 ,
82
- } ) ;
83
- }
84
- }
85
- }
86
- }
87
-
88
- return intervalCounts ;
89
- }
90
-
91
- // 3. for processPeaks --> find tempo
92
- function groupNeighborsByTempo ( intervalCounts , sampleRate ) {
93
- var tempoCounts = [ ] ;
94
-
95
- intervalCounts . forEach ( function ( intervalCount ) {
96
- try {
97
- // Convert an interval to tempo
98
- var theoreticalTempo = Math . abs (
99
- 60 / ( intervalCount . interval / sampleRate )
100
- ) ;
101
-
102
- theoreticalTempo = mapTempo ( theoreticalTempo ) ;
103
-
104
- var foundTempo = tempoCounts . some ( function ( tempoCount ) {
105
- if ( tempoCount . tempo === theoreticalTempo )
106
- return ( tempoCount . count += intervalCount . count ) ;
107
- } ) ;
108
- if ( ! foundTempo ) {
109
- if ( isNaN ( theoreticalTempo ) ) {
110
- return ;
111
- }
112
- tempoCounts . push ( {
113
- tempo : Math . round ( theoreticalTempo ) ,
114
- count : intervalCount . count ,
115
- } ) ;
116
- }
117
- } catch ( e ) {
118
- throw e ;
119
- }
120
- } ) ;
121
-
122
- return tempoCounts ;
123
- }
124
-
125
- // 4. for processPeaks - get peaks at top tempo
126
- function getPeaksAtTopTempo ( peaksObj , tempo , sampleRate , bpmVariance ) {
127
- var peaksAtTopTempo = [ ] ;
128
- var peaksArray = Object . keys ( peaksObj ) . sort ( ) ;
129
-
130
- // TO DO: filter out peaks that have the tempo and return
131
- for ( var i = 0 ; i < peaksArray . length ; i ++ ) {
132
- var key = peaksArray [ i ] ;
133
- var peak = peaksObj [ key ] ;
134
-
135
- for ( var j = 0 ; j < peak . intervals . length ; j ++ ) {
136
- var intervalBPM = Math . round (
137
- Math . abs ( 60 / ( peak . intervals [ j ] / sampleRate ) )
138
- ) ;
139
-
140
- intervalBPM = mapTempo ( intervalBPM ) ;
141
-
142
- if ( Math . abs ( intervalBPM - tempo ) < bpmVariance ) {
143
- // convert sampleIndex to seconds
144
- peaksAtTopTempo . push ( peak . sampleIndex / sampleRate ) ;
145
- }
146
- }
147
- }
148
-
149
- // filter out peaks that are very close to each other
150
- peaksAtTopTempo = peaksAtTopTempo . filter ( function ( peakTime , index , arr ) {
151
- var dif = arr [ index + 1 ] - peakTime ;
152
- if ( dif > 0.01 ) {
153
- return true ;
154
- }
155
- } ) ;
156
-
157
- return peaksAtTopTempo ;
158
- }
159
-
160
- // helper function for processPeaks
161
- function mapTempo ( theoreticalTempo ) {
162
- // these scenarios create infinite while loop
163
- if ( ! isFinite ( theoreticalTempo ) || theoreticalTempo === 0 ) {
164
- return ;
165
- }
166
-
167
- // Adjust the tempo to fit within the 90-180 BPM range
168
- while ( theoreticalTempo < 90 ) theoreticalTempo *= 2 ;
169
- while ( theoreticalTempo > 180 && theoreticalTempo > 90 ) theoreticalTempo /= 2 ;
170
-
171
- return theoreticalTempo ;
172
- }
173
-
174
19
/*** SCHEDULE EVENTS ***/
175
20
176
21
// Cue inspired by JavaScript setTimeout, and the
@@ -1487,101 +1332,8 @@ class SoundFile {
1487
1332
return bufferSourceNode ;
1488
1333
}
1489
1334
1490
- /**
1491
- * processPeaks returns an array of timestamps where it thinks there is a beat.
1492
- *
1493
- * This is an asynchronous function that processes the soundfile in an offline audio context,
1494
- * and sends the results to your callback function.
1495
- *
1496
- * The process involves running the soundfile through a lowpass filter, and finding all of the
1497
- * peaks above the initial threshold. If the total number of peaks are below the minimum number of peaks,
1498
- * it decreases the threshold and re-runs the analysis until either minPeaks or minThreshold are reached.
1499
- *
1500
- * @method processPeaks
1501
- * @for p5.SoundFile
1502
- * @param {Function } callback a function to call once this data is returned
1503
- * @param {Number } [initThreshold] initial threshold defaults to 0.9
1504
- * @param {Number } [minThreshold] minimum threshold defaults to 0.22
1505
- * @param {Number } [minPeaks] minimum number of peaks defaults to 200
1506
- * @return {Array } Array of timestamped peaks
1507
- */
1508
1335
processPeaks ( callback , _initThreshold , _minThreshold , _minPeaks ) {
1509
- var self = this ;
1510
- var bufLen = this . buffer . length ;
1511
- var sampleRate = this . buffer . sampleRate ;
1512
- var buffer = this . buffer ;
1513
- var allPeaks = [ ] ;
1514
-
1515
- var initialThreshold = _initThreshold || 0.9 ,
1516
- threshold = initialThreshold ,
1517
- minThreshold = _minThreshold || 0.22 ,
1518
- minPeaks = _minPeaks || 200 ;
1519
-
1520
- // Create offline context
1521
- var offlineContext = new window . OfflineAudioContext ( 1 , bufLen , sampleRate ) ;
1522
-
1523
- // create buffer source
1524
- var source = offlineContext . createBufferSource ( ) ;
1525
- source . buffer = buffer ;
1526
-
1527
- // Create filter. TO DO: allow custom setting of filter
1528
- var filter = offlineContext . createBiquadFilter ( ) ;
1529
- filter . type = 'lowpass' ;
1530
- source . connect ( filter ) ;
1531
- filter . connect ( offlineContext . destination ) ;
1532
-
1533
- // start playing at time:0
1534
- source . start ( 0 ) ;
1535
- offlineContext . startRendering ( ) ; // Render the song
1536
-
1537
- // act on the result
1538
- offlineContext . oncomplete = function ( e ) {
1539
- if ( ! self . panner ) return ;
1540
- var filteredBuffer = e . renderedBuffer ;
1541
- var bufferData = filteredBuffer . getChannelData ( 0 ) ;
1542
-
1543
- // step 1:
1544
- // create Peak instances, add them to array, with strength and sampleIndex
1545
- do {
1546
- allPeaks = getPeaksAtThreshold ( bufferData , threshold ) ;
1547
- threshold -= 0.005 ;
1548
- } while (
1549
- Object . keys ( allPeaks ) . length < minPeaks &&
1550
- threshold >= minThreshold
1551
- ) ;
1552
-
1553
- // step 2:
1554
- // find intervals for each peak in the sampleIndex, add tempos array
1555
- var intervalCounts = countIntervalsBetweenNearbyPeaks ( allPeaks ) ;
1556
-
1557
- // step 3: find top tempos
1558
- var groups = groupNeighborsByTempo (
1559
- intervalCounts ,
1560
- filteredBuffer . sampleRate
1561
- ) ;
1562
-
1563
- // sort top intervals
1564
- var topTempos = groups
1565
- . sort ( function ( intA , intB ) {
1566
- return intB . count - intA . count ;
1567
- } )
1568
- . splice ( 0 , 5 ) ;
1569
-
1570
- // set this SoundFile's tempo to the top tempo ??
1571
- this . tempo = topTempos [ 0 ] . tempo ;
1572
-
1573
- // step 4:
1574
- // new array of peaks at top tempo within a bpmVariance
1575
- var bpmVariance = 5 ;
1576
- var tempoPeaks = getPeaksAtTopTempo (
1577
- allPeaks ,
1578
- topTempos [ 0 ] . tempo ,
1579
- filteredBuffer . sampleRate ,
1580
- bpmVariance
1581
- ) ;
1582
-
1583
- callback ( tempoPeaks ) ;
1584
- } ;
1336
+ console . warn ( 'processPeaks is deprecated' ) ;
1585
1337
}
1586
1338
1587
1339
/**
0 commit comments