Audio Sample Splitter
A program to read and split audio into instrument samples
 All Classes Functions
SampleSplitter.h
1 #include "httplib/httplib.h"
2 #include "json/json.h"
3 #include <iostream>
4 #include <ctime>
5 #include <map>
6 #include <string>
7 #include <chrono>
8 #include "elma.h"
9 #include "client.h"
10 #include <stdlib.h>
11 #include <stdexcept>
12 #include <math.h>
13 #include <stdio.h>
14 #include "AudioFile.h"
15 #include "channel.h"
16 #include <fstream>
17 #include <vector>
18 
19 using namespace std;
20 using namespace elma;
21 
23 class SampleSplitter : public Process {
24 
25  public:
32  SampleSplitter(double threshold, double grace_time, double updates_per_export_attempt):Process("sample splitter") {
33  upea = updates_per_export_attempt;
34  th = threshold;
35  gt = grace_time;
36  backlog.resize (2);
37  live = true;
38  };
42  SampleSplitter(std::string filename):Process("sample splitter")
43  {
44  audioFile.load (filename);
45  live = false;
46  };
47 
49  void init() {
50  watch("set bit depth", [this](Event& e) {
51  bit_depth = e.value();
52  });
53  watch("set sample rate", [this](Event& e) {
54  sample_rate = e.value();
55  });
56  }
57  void start() {}
58 
62  void update() {
63 
64  if ( channel("left audio").nonempty() && channel("right audio").nonempty() ) {
65 
66  read_data_packet(channel("left audio").latest(), channel("right audio").latest());
67 
68  if (backlog[0].size() > (int) (gt*sample_rate) && upea_counter > upea){
69  attempt_live_export(th, gt);
70  upea_counter = 0;
71  }
72  upea_counter++;
73  }
74  }
75  void stop() {}
76 
78  void set_threshold(double threshold);
79 
81  void set_grace_time(double grace_time);
82 
83  // --------- non-live mode functions -------------------------------------------------
84 
87  double number_of_samples();
88 
91  double get_max();
92 
95  double get_min();
96 
101  void split_samples(double threshold, double grace_time);
102 
108  void export_sample(double sample_number, std::string file_name);
109 
113  void export_all_samples();
114 
119  void export_all_samples(vector<std::string> file_names);
120 
129  void split_and_export_samples(double threshold, double grace_time, bool export_files);
130 
131  //----------- live mode functions ----------------------------------------------------
132 
137  void read_data_packet(json left_data, json right_data);
138 
144  void attempt_live_export(double threshold, double grace_time);
145 
146 
147  private:
148 
150  bool live;
151 
152  double bit_depth;
153 
154  double sample_rate;
155 
157  int upea;
158 
160  int upea_counter = 0;
161 
163  double th = 0;
164 
166  double gt = 0;
167 
169  AudioFile<double>::AudioBuffer backlog;
170 
171  AudioFile<double> audioFile;
172 
174  vector<AudioFile<double>::AudioBuffer> sample_list;
175 
177  int export_number = 1;
178 
179 };
180 
181 
182 
183 void SampleSplitter::set_threshold(double threshold){
184  th = threshold;
185 }
186 
187 void SampleSplitter::set_grace_time(double grace_time){
188  gt = grace_time;
189 }
190 
191 // --------- non-live mode functions -------------------------------------------------------------------
193  if(live){
194  std::cout << "Can't find number of samples in live mode." <<std::endl;
195  } else{
196  return sample_list.size();
197  }
198 }
199 
201  if(live){
202  std::cout << "Can't find max in live mode." <<std::endl;
203  return 0;
204  } else {
205  double max = -2;
206  // Run through audio file
207  for (int i = 0; i < audioFile.getNumSamplesPerChannel(); i++)
208  {
209  if (audioFile.samples[0][i]> max){
210  max = audioFile.samples[0][i];
211  }
212  }
213  return max;
214  }
215 }
217  if(live){
218  std::cout << "Can't find min in live mode." <<std::endl;
219  return 0;
220  } else {
221  double min = 2;
222  // Run through audio file
223  for (int i = 0; i < audioFile.getNumSamplesPerChannel(); i++)
224  {
225  if (audioFile.samples[0][i]< min){
226  min = audioFile.samples[0][i];
227  }
228  }
229  return min;
230  }
231 }
232 
233 void SampleSplitter::split_and_export_samples(double threshold, double grace_time, bool export_files){
234  if(live){
235  std::cout << "Can't manually split and export samples in live mode" << std::endl;
236  } else {
237  // Make buffer
238  AudioFile<double>::AudioBuffer buffer;
239  buffer.resize (2);
240  bool recording = false; // Is the buffer recording?
241  int grace_sample_num = (int) (audioFile.getSampleRate()*grace_time);
242  int grace_period = 0; // grace samples to be counted down
243  int file_number = 1;
244  std::string file_name;
245  AudioFile<double> output_file;
246  output_file.setBitDepth (audioFile.getBitDepth());
247  output_file.setSampleRate (audioFile.getSampleRate());
248  // Run through audio file
249  for (int i = 0; i < audioFile.getNumSamplesPerChannel(); i++)
250  {
251 
252  if ((audioFile.samples[0][i]>threshold || audioFile.samples[1][i]>threshold)
253  && grace_period <= 0 && !recording){
254  recording = true;
255  grace_period = grace_sample_num;
256  } else if ((audioFile.samples[0][i]>threshold || audioFile.samples[1][i]>threshold)
257  && grace_period <= 0 && recording){
258  if(export_files){
259  file_name = "sample_" + std::to_string(file_number) + ".wav";
260  output_file.setAudioBuffer (buffer);
261  output_file.save (file_name);
262  buffer.clear();
263  buffer.resize (2);
264  }
265  file_number++;
266  grace_period = grace_sample_num;
267  }
268 
269  if(recording){
270 
271  buffer[0].push_back(audioFile.samples[0][i]);
272  buffer[1].push_back(audioFile.samples[1][i]);
273 
274  }
275  grace_period--;
276  }
277 
278  // Export last sample
279  if(export_files){
280  file_name = "sample_" + std::to_string(file_number) + ".wav";
281  output_file.setAudioBuffer (buffer);
282  output_file.save (file_name);
283  buffer.clear();
284  buffer.resize (2);
285  }
286 
287  if (export_files){
288  std::cout << "Exported " << (file_number) << " sample files." << std::endl;
289  } else {
290  std::cout << "Would have exported " << (file_number) << " sample files." << std::endl;
291  }
292  }
293 }
294 
295 void SampleSplitter::split_samples(double threshold, double grace_time){
296  if(live){
297  std::cout << "Can't manually split samples in live mode" << std::endl;
298  } else {
299  // Make buffer
300  AudioFile<double>::AudioBuffer buffer;
301  buffer.resize (2);
302  bool recording = false; // Is the buffer recording?
303  int grace_sample_num = (int) (audioFile.getSampleRate()*grace_time);
304  int grace_period = 0; // grace samples to be counted down
305  int file_number = 1;
306  std::string file_name;
307  // Run through audio file
308  for (int i = 0; i < audioFile.getNumSamplesPerChannel(); i++)
309  {
310 
311  if ((audioFile.samples[0][i]>threshold || audioFile.samples[1][i]>threshold)
312  && grace_period <= 0 && !recording){
313  recording = true;
314  grace_period = grace_sample_num;
315  } else if ((audioFile.samples[0][i]>threshold || audioFile.samples[1][i]>threshold)
316  && grace_period <= 0 && recording){
317 
318  file_name = "sample_" + std::to_string(file_number) + ".wav";
319  sample_list.push_back(buffer);
320  buffer.clear();
321  buffer.resize (2);
322 
323  file_number++;
324  grace_period = grace_sample_num;
325  }
326 
327  if(recording){
328 
329  buffer[0].push_back(audioFile.samples[0][i]);
330  buffer[1].push_back(audioFile.samples[1][i]);
331 
332  }
333  grace_period--;
334  }
335  // Export last sample
336 
337  file_name = "sample_" + std::to_string(file_number) + ".wav";
338  sample_list.push_back(buffer);
339  buffer.clear();
340  buffer.resize (2);
341 
342  std::cout << "Split " << (file_number) << " sample files." << std::endl;
343  }
344 
345 
346 }
347 
348 void SampleSplitter::export_sample(double sample_number, std::string file_name){
349  if (live){
350  std::cout << "Can't export a specific samples in live mode" << std::endl;
351  std::cout << "No samples were exported" << std::endl;
352  } else {
353  if (sample_list.size() == 0){
354  std::cout << "No samples to export" << std::endl;
355  std::cout << "Did you split the original file into samples first?" << std::endl;
356 
357  } else if(sample_number > 0 && sample_number <= sample_list.size()){
358  AudioFile<double> output_file;
359  output_file.setBitDepth (audioFile.getBitDepth());
360  output_file.setSampleRate (audioFile.getSampleRate());
361  output_file.setAudioBuffer (sample_list.at(sample_number-1));
362  output_file.save (file_name);
363  std::cout << file_name << " was exported." << std::endl;
364  } else{
365  std::cout << "There are " << sample_list.size() << " samples." << std::endl;
366  std::cout << "You asked for sample number " << sample_number << std::endl;
367  std::cout << "No sample was exported" << std::endl;
368  }
369  }
370 }
371 
373  if(live){
374  std::cout << "Can't export all samples in live mode" << std::endl;
375  std::cout << "No samples were exported" << std::endl;
376  } else {
377  if (sample_list.size() == 0){
378  std::cout << "No samples to export" << std::endl;
379  std::cout << "Did you split the original file into samples first?" << std::endl;
380  std::cout << "No samples were exported" << std::endl;
381  } else{
382  std::string file_name;
383  for (int i = 1; i <= sample_list.size(); i++){
384  file_name = "sample_" + std::to_string(i) + ".wav";
385  export_sample(i,file_name);
386  }
387  }
388  }
389 }
390 
391 void SampleSplitter::export_all_samples(vector<std::string> file_names){
392  if(live){
393  std::cout << "Can't manually export all samples in live mode" << std::endl;
394  std::cout << "No samples were exported" << std::endl;
395  } else{
396  if (sample_list.size() == 0){
397  std::cout << "No samples to export" << std::endl;
398  std::cout << "Did you split the original file into samples first?" << std::endl;
399  std::cout << "No samples were exported" << std::endl;
400  } else if(sample_list.size() != file_names.size()){
401  std::cout << "The number of file names does not match the number of samples." << std::endl;
402  std::cout << "No samples were exported" << std::endl;
403  } else {
404  for (int i = 1; i <= sample_list.size(); i++){
405  export_sample(i,file_names.at(i-1));
406  }
407  }
408  }
409 }
410 
411 // --------- live mode functions ------------------------------------------------------------------------
412 
413 void SampleSplitter::attempt_live_export(double threshold, double grace_time){
414  if(live){
415  // Make buffer
416  AudioFile<double>::AudioBuffer buffer;
417  buffer.resize (2);
418  bool recording = false; // Is the buffer recording?
419  int grace_sample_num = (int) (sample_rate*grace_time);
420  int grace_period = 0; // grace samples to be counted down
421  int file_number = 1;
422  std::string file_name;
423  AudioFile<double> output_file;
424  output_file.setBitDepth (bit_depth);
425  output_file.setSampleRate (sample_rate);
426  // Run through backlog
427  for (int i = 0; i < backlog[0].size(); i++)
428  {
429 
430  if ((backlog[0][i]>threshold || backlog[1][i]>threshold)
431  && grace_period <= 0 && !recording){
432  recording = true;
433  grace_period = grace_sample_num;
434  } else if ((backlog[0][i]>threshold || backlog[1][i]>threshold)
435  && grace_period <= 0 && recording){
436 
437  file_name = "sample_" + std::to_string(export_number) + ".wav";
438  output_file.setAudioBuffer (buffer);
439  output_file.save (file_name);
440  std::cout << "Exported " << file_name << std::endl;
441  buffer.clear();
442  buffer.resize (2);
443 
444  export_number++;
445  grace_period = grace_sample_num;
446  }
447 
448  if(recording){
449 
450  buffer[0].push_back(backlog[0][i]);
451  buffer[1].push_back(backlog[1][i]);
452 
453  }
454  grace_period--;
455  }
456 
457  // The last "sample" becomes the new backlog
458  // I do this so that I don't export incomplete samples
459  // The result is that the last sample won't export until another sample recording has been triggered
460  // Thus to make sure your last sample exports make a loud noise to trigger the end of that sample.
461  backlog.clear();
462  backlog.resize (2);
463  for(int i = 0; i < buffer[0].size(); i++){
464  backlog[0].push_back(buffer[0][i]);
465  backlog[1].push_back(buffer[1][i]);
466  }
467  } else {
468  std::cout << "attempt_live_export is a live mode exclusive function" << std::endl;
469  }
470 }
471 
472 void SampleSplitter::read_data_packet(json left_data, json right_data){
473  if(live){
474  for (int i = 0; i < left_data.size(); i++){
475  backlog[0].push_back(left_data[i]);
476  backlog[1].push_back(right_data[i]);
477  }
478  } else {
479  std::cout << "read_data_packet is a live mode exclusive function" << std::endl;
480  }
481 }
void split_and_export_samples(double threshold, double grace_time, bool export_files)
void init()
Listens to the manager for its bit depth and sample rate when initialized.
SampleSplitter(std::string filename)
void export_all_samples()
void export_sample(double sample_number, std::string file_name)
void split_samples(double threshold, double grace_time)
void set_grace_time(double grace_time)
SampleSplitter(double threshold, double grace_time, double updates_per_export_attempt)
void set_threshold(double threshold)
double number_of_samples()
void read_data_packet(json left_data, json right_data)
void attempt_live_export(double threshold, double grace_time)
Takes audio data, splits it and exports it as several audio samples.