rubberband.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // non-functional example code from the prototype phase of
  2. // the project. the code uses the single-threaded pulse "simple"
  3. // api to get audio from the default device, run it thru
  4. // rubberband to pitch shift it and then pipe it to STDOUT.
  5. //
  6. // the main value to this code is the rubberband processing,
  7. // not the old pulse code that can't be multi-threaded
  8. #define PULSE_BUFFERSIZE 2046
  9. static pa_simple *s = NULL;
  10. static char name_buf[] = "PulseAudio default device";
  11. int lyrebird_pulse_start() {
  12. int error;
  13. static const pa_sample_spec ispec = {
  14. .format = PA_SAMPLE_S16LE, /* 16 bit low endian */
  15. .rate = 44100, /* 44 khz sampling rate */
  16. .channels = 1
  17. };
  18. if (!(s = pa_simple_new(NULL, "Lyrebird C Test", PA_STREAM_RECORD, NULL, "Lyrebird Recording", &ispec, NULL, NULL, &error))) {
  19. printf("Error: pa_simple_new() failed: %s\n", pa_strerror(error));
  20. return 1;
  21. }
  22. return 0;
  23. }
  24. int lyrebird_pulse_stop() {
  25. if (s != NULL) {
  26. pa_simple_free(s);
  27. s = NULL;
  28. }
  29. return 0;
  30. }
  31. int lyrebird_pulse_read(int16_t *buf, int sample_num) {
  32. int error;
  33. int cnt, bufsize;
  34. bufsize = sample_num * sizeof(int16_t);
  35. if (bufsize > PULSE_BUFFERSIZE) bufsize = PULSE_BUFFERSIZE;
  36. if (pa_simple_read(s, buf, bufsize, &error) < 0) {
  37. printf("Error: pa_sample_read() failed: %s\n", pa_strerror(error));
  38. }
  39. cnt = bufsize / sizeof(int16_t);
  40. return (cnt);
  41. }
  42. int16_t buffer[PULSE_BUFFERSIZE];
  43. RubberBandState testing_rb_state;
  44. int real_time_loop_active = 1;
  45. void sigint_handler(int signum) {
  46. real_time_loop_active = 0;
  47. lyrebird_pulse_stop();
  48. lyrebird_rubberband_stop(testing_rb_state);
  49. if (lyrebird_pulse_unload_sinks() != 0) {
  50. printf("WARNING: May have failed to unload PulseAudio modules\n");
  51. }
  52. }
  53. /**
  54. NOTES:
  55. - Raw data can be converted to a file using SoX, pipe the raw data to stdout and run
  56. `sox -t raw -b 16 -e signed-integer -r 44100 test.raw test.wav`
  57. IMPORTANT! Before you listen to any data PLEASE take off your headphones or lower the
  58. volume of your speakers, it is sometimes VERY BAD AUDIO!
  59. */
  60. int main() {
  61. // Temporary RubberBand state struct for testing
  62. testing_rb_state = lyrebird_rubberband_setup(44100, 1);
  63. rubberband_set_pitch_scale(testing_rb_state, lyrebird_semitones_pitch(1));
  64. // Start Pulse
  65. lyrebird_pulse_start();
  66. signal(SIGINT, sigint_handler);
  67. // Run forever
  68. while (real_time_loop_active) {
  69. // Find out how many samples RubberBand wants and pull that many from Pulse, in
  70. // reality this won't work in reality since pulling any samples over 32 makes
  71. // inaudible sounds
  72. unsigned int samples_required = rubberband_get_samples_required(testing_rb_state);
  73. /*int pulse_samples_recv = */lyrebird_pulse_read(buffer, samples_required);
  74. // DEBUG: Write raw Pulse data to stdout, will sounds bad unless 32 samples
  75. // fwrite(buffer, sizeof(int16_t), samples_required, stdout);
  76. // Creating the first (and only) channel for RubberBand
  77. float in_samples_chan1[samples_required];
  78. memset(in_samples_chan1, 0, samples_required);
  79. for (unsigned int i = 0; i < samples_required; i++) {
  80. // Making sure value doesn't equal 0 or exceed/be less than -1.0f/1.0f bounds
  81. float value;
  82. if (buffer[i] == 0) {
  83. value = 0;
  84. } else {
  85. // Find float value by dividing by sample rate
  86. float calculated = (float)buffer[i] / 44100.0;
  87. if (calculated > 1) {
  88. value = 1;
  89. } else if (calculated < -1) {
  90. value = -1;
  91. } else {
  92. value = calculated;
  93. }
  94. }
  95. // Write calculated value to buffer
  96. in_samples_chan1[i] = value;
  97. }
  98. // Create final buffer for RubberBand
  99. float *in_samples[1] = { in_samples_chan1 };
  100. // Process data in RubberBand
  101. rubberband_process(testing_rb_state, (const float* const*)in_samples, samples_required, 0);
  102. // How many frames available to receive from RubberBand
  103. int available_frames = rubberband_available(testing_rb_state);
  104. if (available_frames > 0) {
  105. // More than 0, read from RubberBand
  106. float out_chan1[available_frames];
  107. memset(out_chan1, 0, available_frames);
  108. float *out[1] = { out_chan1 };
  109. // Pull samples from RubberBand
  110. /*size_t out_samples_size = */rubberband_retrieve(testing_rb_state, out, available_frames);
  111. int16_t *out_buffer = malloc(available_frames * sizeof(uint16_t));
  112. for (int i = 0; i < available_frames; i++) {
  113. out_buffer[i] = (uint16_t)(out[0][i] * 44100);
  114. }
  115. fwrite(out_buffer, sizeof(uint16_t), available_frames, stdout);
  116. }
  117. }
  118. return 0;
  119. }