Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

199
LINES

< > BotCompany Repo | #1032970 // PianoSampler [dev.]

JavaX fragment (include) [tags: use-pretranspiled]

Libraryless. Compilation Failed (11097L/66K).

1  
sclass PianoSampler {
2  
  macro dprint { if (debug) printVars } bool debug;
3  
    
4  
  int channels = 1;
5  
  double sampleRate = 48000;
6  
  double currentSample;
7  
  IQuerySound sound;
8  
  IAudioSample audio;
9  
  SlidingWindow window;
10  
  
11  
  long haarFeaturesChecked;
12  
13  
  persistable class Oscillator extends HasKey<Frequency> {
14  
    double currentPeriodStart;
15  
    // all recorded intensities
16  
    new TreeMap<DoubleRange, Channels<Complex>> intensities;
17  
    double interval; // in samples
18  
    
19  
    *(Frequency f) {
20  
      super(f);
21  
      interval = frequency().interval()*sampleRate;
22  
    }
23  
    
24  
    Frequency frequency() { ret key(); }
25  
    double interval() { ret interval; }
26  
    
27  
    void record_impl(DoubleRange r, Channels<Complex> c) {
28  
      intensities.put(r, c);
29  
    }
30  
    
31  
    void advancePeriodToRange(DoubleRange timeRange) {
32  
      double end = currentPeriodStart + interval;
33  
      int phaseShifts = ifloor((timeRange.start-end)/interval);
34  
      if (phaseShifts = 0) ret;
35  
      setStart(currentPeriodStart + phaseShifts*interval);
36  
    }
37  
    
38  
    // we span a total range of interval*1.25 because of the sin/cos thing
39  
    void measure(DoubleRange timeRange) {
40  
      DoubleRange p1 = doubleRangeWithLength(phaseMinus90(), interval);
41  
      p1 = intersectDoubleRanges(p1, timeRange);
42  
      double re = 0;
43  
      if (!isEmpty(p1)) {
44  
        AudioHaarFeature haar = new(audio, p1);
45  
        re = haar!;
46  
      }
47  
      
48  
      DoubleRange p2 = doubleRangeWithLength(currentPeriodStart, interval);
49  
      p2 = intersectDoubleRanges(p2, timeRange);
50  
      double im = 0;
51  
      if (!isEmpty(p2)) {
52  
        AudioHaarFeature haar = new(audio, p2);
53  
        im = haar!;
54  
      }
55  
      
56  
      record(this, p1 /*TODO*/, complexChannels(re, im));
57  
      haarFeaturesChecked += 2;
58  
    }
59  
    
60  
    void dropMeasurementsLeftOf(double t) {
61  
      while ping (true) {
62  
        var r = firstKey(intensities);
63  
        if (r != null && r.end() <= t)
64  
          popFirst(intensities);
65  
        else
66  
          break;
67  
      }
68  
    }
69  
    
70  
    void initial(double currentSample) {
71  
      setStart(currentSample + startPhase());
72  
    }
73  
    
74  
    void moveTo(double time) {
75  
      currentPeriodStart = time;
76  
      double next = phase360();
77  
      dprint("moveTo", +this, +next);
78  
      completionsForSample.put(next, this);
79  
    }
80  
    
81  
    double startPhase() { ret phase90(); }
82  
    
83  
    double quarterPhase() { ret interval()*.25; }
84  
    
85  
    double phaseMinus90() { ret currentPeriodStart - interval()*.25; }
86  
    double phase0() { ret currentPeriodStart; }
87  
    double phase90() { ret currentPeriodStart + interval()*.25; }
88  
    double phase180() { ret currentPeriodStart + interval()*.5; }
89  
    double phase270() { ret currentPeriodStart + interval()*.75; }
90  
    double phase360() { ret currentPeriodStart + interval(); }
91  
    double phase450() { ret currentPeriodStart + interval()*1.25; }
92  
  } // end of Oscillator
93  
  
94  
  TreeHasKeyMap<Frequency, Oscillator> oscillators = new TreeHasKeyMap<Frequency, Oscillator>(map(f -> new Oscillator(f), pianoFrequencies88()));
95  
  new TreeMultiMap<Double, Oscillator> completionsForSample;
96  
  
97  
  *() {}
98  
  *(IAudioSample audio, double *currentSample) { setAudio(audio); }
99  
  *(IAudioSample audio) { setAudio(audio); } // start at time 0
100  
  
101  
  void setAudio(IAudioSample audio) {
102  
    this.audio = audio;
103  
    window = optCast SlidingWindow(audio);
104  
  }
105  
  
106  
  void verboseOnRecordAdded() {
107  
    onRecordAdded(lambda1 print);
108  
  }
109  
  
110  
  int nFrequencies() {
111  
    ret oscillators.size();
112  
  }
113  
  
114  
  void startOscillators {
115  
    for (o : oscillators)
116  
      o.initial(currentSample);
117  
  }
118  
  
119  
  void stepTo(DoubleRange timeRange) {
120  
    while ping (true) {
121  
      Double t = firstKey(completionsForSample);
122  
      if (t != null && t <= timeRange.start) {
123  
        var list = completionsForSample.getAndClear(t);
124  
        dprint(+t, +list);
125  
        for (Oscillator o : list) {
126  
          o.measure(timeRange);
127  
          o.relocate(t);
128  
        }
129  
      } else
130  
        break;
131  
    }
132  
  }
133  
  
134  
  void record(Oscillator o, DoubleRange r, Channels<Complex> c) {
135  
    if (o == null) ret;
136  
    o.record_impl(r, c);
137  
    onRecordAdded(new RecordAdded(o, r, c));
138  
  }
139  
  
140  
  record RecordAdded(Oscillator oscillator, DoubleRange period, Channels<Complex> intensity) {}
141  
  
142  
  transient event interface OnRecordAdded as onRecordAdded shipping RecordAdded;
143  
  
144  
  Frequency lowestFrequency() { ret oscillators.firstKey(); }
145  
  Frequency highestFrequency() { ret oscillators.lastKey(); }
146  
  
147  
  int minWindowSize() {
148  
    ret iceil(sampleRate*lowestFrequency().interval());
149  
  }
150  
  
151  
  void makeSmallestWindow(IQuerySound sound) {
152  
    this.sound = sound;
153  
    setAudio(new SlidingWindow(channels, sampleRate, sound, 0, minWindowSize());
154  
  }
155  
  
156  
  double windowSize() {
157  
    ret window.length();
158  
  }
159  
  
160  
  S stats() { ret renderVars(+audio, +haarFeaturesChecked); }
161  
  
162  
  IIntegralImage imageColumn(DoubleRange timeRange) {
163  
    int n = nFrequencies();
164  
    var l = reversedList(oscillators);
165  
    double[] col = new[n];
166  
    for y to n: {
167  
      var l2 = l.get(y).intensities;
168  
      new Average avg;
169  
      forEach(l2, (r, val) -> {
170  
        double amplitude = val.first().abs();
171  
        
172  
        // if only a part is in the time range
173  
        double actualDuration = l(intersectDoubleRanges(r, timeRange));
174  
        
175  
        avg.add(amplitude, actualDuration);
176  
      });
177  
      col[y] = avg!;
178  
    }
179  
    double[] col2 = normalizeDoubles(col, 255);
180  
      
181  
    ret bwIntegralImageFromFunction(1, n, (x, y) -> ifloor(col2[y]));
182  
  }
183  
  
184  
  // how much horizontal area have we covered
185  
  L<Double> coverageByFreq() {
186  
    ret mapReversed(oscillators, o -> totalLengthOfDoubleRanges(keys(o.intensities)));
187  
  }
188  
  
189  
  void stepRight(double shift) {
190  
    assertNotNull(+window);
191  
    var r = window.bounds();
192  
    window.shiftRight(max(1, ifloor(shift)));
193  
194  
    for (o : oscillators) o.dropMeasurementsLeftOf(window.start());
195  
    stepTo(window.end());
196  
  }
197  
  
198  
  DoubleRange windowBounds() { ret window.bounds(); }
199  
}

download  show line numbers  debug dex  old transpilations   

Travelled to 4 computer(s): bhatertpkbcr, ekrmjmnbrukm, mowyntqkapby, mqqgnosmbjvj

No comments. add comment

Snippet ID: #1032970
Snippet name: PianoSampler [dev.]
Eternal ID of this version: #1032970/58
Text MD5: 16206552e3383e53a76f46517a272ed0
Transpilation MD5: b1d20b360e5c5cceb4e23436d38322ed
Author: stefan
Category: javax / audio analysis
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2021-10-11 15:53:09
Source code size: 6085 bytes / 199 lines
Pitched / IR pitched: No / No
Views / Downloads: 215 / 504
Version history: 57 change(s)
Referenced in: [show references]