sequencer
synth.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <sequencer/assert.hpp>
19 
20 #include <chrono>
21 #include <cmath>
22 #include <experimental/filesystem>
23 #include <future>
24 #include <mutex>
25 #include <string>
26 #include <vector>
27 
29 {
30  inline std::vector< float > create_blackman_table( int N )
31  {
32  std::vector< float > table( N + 1, 0 );
33  for ( auto n = 0; n <= N; ++n )
34  {
35  table[ n ] = float( audio::window::blackman( n, N ) );
36  }
37  return table;
38  }
39 
40  template < int M >
41  inline auto create_kernels( int N, float lowpass_cutoff, float highpass_cutoff )
42  {
43  std::vector< float > highpass_kernel( 2 * N, 0.f );
44  std::vector< float > lowpass_kernel( 2 * N, 0.f );
45  static auto blackman_table = create_blackman_table( M );
46  for ( auto i = 0; i <= M; ++i )
47  {
48  if ( i == M / 2 )
49  {
50  highpass_kernel[ i ] =
51  blackman_table[ M / 2 ] * ( 1.f - wave_form::sinc( highpass_cutoff, 0 ) );
52  }
53  else
54  {
55  highpass_kernel[ i ] =
56  -blackman_table[ i ] * wave_form::sinc( highpass_cutoff, ( i - M / 2 ) );
57  }
58  lowpass_kernel[ i ] =
59  blackman_table[ i ] * wave_form::sinc( lowpass_cutoff, ( i - M / 2 ) );
60  }
61  return std::make_pair( lowpass_kernel, highpass_kernel );
62  }
63 
64  template < int M >
65  inline auto create_filter_response( int N, float lowpass_cutoff, float highpass_cutoff )
66  {
67  std::vector< float > lowpass_kernel;
68  std::vector< float > highpass_kernel;
69  std::tie( lowpass_kernel, highpass_kernel ) =
70  create_kernels< M >( N, lowpass_cutoff, highpass_cutoff );
71  auto low = std::async( std::launch::async, [&] { return audio::fft( lowpass_kernel ); } );
72  auto high = std::async( std::launch::async, [&] { return audio::fft( highpass_kernel ); } );
73  return std::make_pair( low.get(), high.get() );
74  }
75 
76  constexpr double make_vca( double signal )
77  {
78  return std::max( signal, 0.0 );
79  }
80 
81  struct chain_t
82  {
83  static constexpr auto sub_sample_size = 4 * 1024;
84  static constexpr auto M = 256;
85 
86  using spectrum_t = std::vector< std::complex< float > >;
87 
88  double operator()( double pos )
89  {
90  auto rm = vca_enabled ? ring_modulation( pos ) : 1.0;
91  if ( vca_mode )
92  {
93  rm = make_vca( rm );
94  }
95  return envelope( pos ) * rm * oscillator( pos, frequency_modulation );
96  }
97 
98  auto get_sample( int frame_pos, int sample_rate )
99  {
100  sample_.clean_and_move( sub_sample_size );
101  std::vector< float > osc( 2 * sub_sample_size, 0.f );
102  for ( auto i = 0; i < sub_sample_size; ++i )
103  {
104  const auto pos = double( frame_pos ) / sample_rate;
105  auto scale = 0.0;
106  if ( !silent_ )
107  {
108  scale = ( osc_fade_out_ > 0 )
109  ? ( osc_fade_out_-- ) / double( fade_sample_count_ )
110  : 1.0;
111  }
112  osc[ std::size_t( i ) ] = scale * ( *this )( pos );
113  ++frame_pos;
114  }
115  auto spectrum = audio::fft( osc );
116  filter( spectrum );
117  osc = audio::inverse_fft( spectrum );
118  for ( auto k = 0u; k < osc.size(); ++k )
119  {
120  sample_[ k ] += osc[ k ];
121  }
122 
123  using std::begin;
124  std::vector< std::pair< float, float > > result( sub_sample_size );
125  for ( auto k = 0u; k < result.size(); ++k )
126  {
127  result[ k ] = delay( sample_[ k ] );
128  }
129  return result;
130  }
131 
132  void set_highpass_frequency( double frequency )
133  {
134  highpass_frequency = frequency;
135  update_filter_spectrum( sub_sample_size );
136  }
137 
138  void set_lowpass_frequency( double frequency )
139  {
140  lowpass_frequency = frequency;
141  update_filter_spectrum( sub_sample_size );
142  }
143 
145  {
146  auto [ lowpass_filter_response, highpass_filter_response ] =
147  create_filter_response< M >( N, lowpass_frequency / sample_rate,
148  highpass_frequency / sample_rate );
149  std::lock_guard lock{filter_mutex};
150  filter_spectrum.resize( lowpass_filter_response.size() );
151  for ( auto i = 0u; i < filter_spectrum.size(); ++i )
152  {
153  filter_spectrum[ i ] = lowpass_filter_response[ i ] * highpass_filter_response[ i ];
154  }
155  }
156 
157  void filter( spectrum_t& spectrum ) const
158  {
159  std::lock_guard lock{filter_mutex};
160  // spectrum.size() == filter_spectrum.size());
161  if ( filter_spectrum.size() != spectrum.size() )
162  {
163  return;
164  }
165  for ( auto i = 0u; i < spectrum.size(); ++i )
166  {
167  spectrum[ i ] *= filter_spectrum[ i ];
168  }
169  }
170 
181 
182  std::atomic_bool silent_{false};
183  std::atomic_int osc_fade_out_{0};
185 
186  private:
187  mutable std::mutex filter_mutex;
188  copyable_atomic< double > lowpass_frequency{22000};
189  copyable_atomic< double > highpass_frequency{20};
190  spectrum_t filter_spectrum = spectrum_t( sub_sample_size );
191  audio::ring_buffer_t< float > sample_{2 * sub_sample_size};
192  };
193 
194  inline auto convolution( const std::vector< float >& signal,
195  const std::vector< float >& reverb )
196  {
197  std::vector< float > output( signal.size() + reverb.size(), 0 );
198 
199  // const auto start_time = std::chrono::steady_clock::now();
200  std::vector< std::future< void > > done;
201  const auto n_threads = 8;
202  const auto parallel_offset = output.size() / n_threads;
203  for ( auto l = 0; l < n_threads; ++l )
204  {
205  done.push_back( std::async( std::launch::async, [&, l] {
206  for ( auto j = l * parallel_offset; j < ( l + 1 ) * parallel_offset; ++j )
207  {
208  for ( auto k = std::max( 0, int( j + 1 - reverb.size() ) );
209  k < std::min( j + 1, signal.size() ); ++k )
210  {
211  output[ j ] += reverb[ j - k ] * signal[ k ];
212  }
213  }
214  } ) );
215  }
216 
217  for ( auto& d : done )
218  {
219  d.wait();
220  } /*
221  auto elapsed =
222  std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() -
223  start_time).count(); std::cout << "elapsed: " << elapsed << "ms" << std::endl;*/
224  return output;
225  }
226 
227  template < class spectrum_t >
229  const spectrum_t& spectrum_left, const spectrum_t& spectrum_right,
230  const std::vector< std::pair< spectrum_t, spectrum_t > >& filters,
231  std::vector< std::future< std::pair< std::vector< float >, std::vector< float > > > >& done,
232  bool first_long_part )
233  {
234  // std::vector< std::future< std::tuple< int, std::vector< float >, std::vector<
235  // float > > > >
236  // done;
237  // done[0] = std::async(
238  // std::launch::async, [spectrum_left, spectrum_right, filter =
239  // filters[1]] {
240  // auto s = spectrum_left;
241  // auto t = spectrum_right;
242  // for ( auto k = 0u; k < s.size(); ++k )
243  // {
244  // s[ k ] *= 0.5f * filter.first[ k ];
245  // t[ k ] *= 0.5f * filter.second[ k ];
246  // }
247 
248  // return std::pair{audio::inverse_fft( s ), audio::inverse_fft( t
249  // )};
250  // } );
251  // done[first_long_part ? 1 : 2] = std::async(std::launch::async,
252  // [spectrum_left, spectrum_right, filter1
253  // = filters[2], filter2 = filters[3]]
254  // {
255  // auto s = spectrum_left;
256  // auto t = spectrum_right;
257  // for ( auto k = 0u; k < s.size(); ++k )
258  // {
259  // s[ k ] *= 0.5f * filter1.first[ k ];
260  // t[ k ] *= 0.5f * filter1.second[ k ];
261  // }
262 
263  // auto left = audio::inverse_fft(s);
264  // auto right = audio::inverse_fft(t);
265  // const auto offset = left.size()/2;
266  // left.resize(left.size() + offset, 0);
267  // right.resize(right.size() + offset, 0);
268 
269  // s = spectrum_left;
270  // t = spectrum_right;
271  // for ( auto k = 0u; k < s.size(); ++k )
272  // {
273  // s[ k ] *= 0.5f * filter2.first[ k ];
274  // t[ k ] *= 0.5f * filter2.second[ k ];
275  // }
276 
277  // auto left2 = audio::inverse_fft(s);
278  // auto right2 = audio::inverse_fft(t);
279  // for(auto i=0u; i<left2.size(); ++i)
280  // {
281  // left[offset + i] += left2[i];
282  // right[offset + i] += right2[i];
283  // }
284 
285  // return std::pair{std::move(left), std::move(right)};
286  // });
287 
288  // for ( auto j = 1; j < filters.size(); ++j )
289  // {
291  // auto g0 = std::async(
292  // std::launch::async, [&spectrum_left, &spectrum_right, j, doff, &filters]()
293  // mutable {
294  auto lf = std::async( std::launch::async, [&] {
295  auto s = spectrum_left;
296  for ( auto k = 0u; k < s.size(); ++k )
297  {
298  s[ k ] *= 0.5f * filters[ 0 ].first[ k ];
299  }
300  return audio::inverse_fft( s );
301  } );
302  auto s = spectrum_right;
303  for ( auto k = 0u; k < s.size(); ++k )
304  {
305  s[ k ] *= 0.5f * filters[ 0 ].first[ k ];
306  }
307  auto rf = audio::inverse_fft( s );
308  return std::tuple{lf.get(), rf};
309  // auto s = spectrum_left;
310  // auto t = spectrum_right;
311  // for ( auto k = 0u; k < s.size(); ++k )
312  // {
313  // s[ k ] *= 0.5f * filters[ 0 ].first[ k ];
314  // t[ k ] *= 0.5f * filters[ 0 ].second[ k ];
315  // }
316 
317  // return std::tuple{audio::inverse_fft( s ), audio::inverse_fft( t )};
318  // } );
319  // done.push_back( std::move( g0 ) );
320  // }
321 
322  // std::vector< float > tmp_left( spectrum_left.size() + filters.size() *
323  // spectrum_left.size(),
324  // 0 );
325  // std::vector< float > tmp_right(
326  // spectrum_right.size() + filters.size() * spectrum_left.size(), 0 );
327 
328  // for ( auto& d : done )
329  // {
330  // const auto& [ offset2, lhs, rhs ] = d.get();
331  // for ( auto k = 0u; k < lhs.size(); ++k )
332  // {
333  // const auto idx = offset2 + k;
334  // if ( idx >= tmp_left.size() )
335  // break;
336  // tmp_left[ idx ] += lhs[ k ];
337  // tmp_right[ idx ] += rhs[ k ];
338  // }
339  // }
340 
341  // return std::pair{std::move( tmp_left ), std::move( tmp_right )};
342  }
343 
344  template < class ClockReceiver >
345  class backend_t : public ClockReceiver
346  {
347  public:
348  using size_type = std::vector< chain_t >::size_type;
349 
350  static constexpr auto number_of_oscillators = 2u;
351  static constexpr auto sub_sample_size = chain_t::sub_sample_size;
352  static constexpr auto M = chain_t::M;
353 
354  template < class Callback >
355  explicit backend_t( Callback callback )
356  : ClockReceiver{callback}, chains_( number_of_oscillators ), clock_dt_( 24, 0 )
357  {
358  for ( auto& chain : chains_ )
359  {
360  chain.update_filter_spectrum( sub_sample_size );
361  }
362 
363  generating_thread_terminated_ = std::async( std::launch::async, [this] {
364  using namespace sequencer::audio;
365  constexpr auto N = sub_sample_size;
367  const auto initial_size = buffer.frames.size();
368 
369  static auto blackman_table = create_blackman_table( M );
370 
371  std::vector< float > last_osc1( N, 0.f );
372 
373  auto write_buffer = [&] {
374  using namespace std::chrono;
375  const auto start_time = steady_clock::now();
376  auto signal0_f = std::async( std::launch::async, [&] {
377  return chain( 0 ).get_sample( frame_pos_, sample_rate_ );
378  } );
379 
380  auto signal1 = chain( 1 ).get_sample( frame_pos_, sample_rate_ );
381  auto signal0 = signal0_f.get();
382  std::vector< float > left( 2 * sub_sample_size, 0 );
383  std::vector< float > right( 2 * sub_sample_size, 0 );
384  for ( auto k = 0u; k < signal0.size(); ++k )
385  {
386  left[ k ] = signal0[ k ].first + signal1[ k ].first;
387  right[ k ] = signal0[ k ].second + signal1[ k ].second;
388  }
389 
390  bool use_reverb = false;
391  spectrum_t spectrum_left;
392  spectrum_t spectrum_right;
393  {
394  std::lock_guard lock{reverb_mutex_};
395  if ( !reverb_spectra_.empty() )
396  {
397  use_reverb = true;
398 
399  auto spectrum0_f = std::async( std::launch::async,
400  [&] { return audio::fft( left ); } );
401  spectrum_right = audio::fft( right );
402  spectrum_left = spectrum0_f.get();
403  const auto [ tmp_l, tmp_r ] =
404  overlay_add_sub( spectrum_left, spectrum_right, reverb_spectra_,
405  sub_parts_, first_double_part_ );
406  // first_long_part_ = !first_long_part_;
407  {
408  std::lock_guard lock{left_mutex_};
409  for ( auto k = 0u; k < tmp_l.size(); ++k )
410  {
411  last_osc0_lhs_before_filter[ k ] += tmp_l[ k ];
412  }
413  }
414  {
415  std::lock_guard lock{right_mutex_};
416  for ( auto k = 0u; k < tmp_r.size(); ++k )
417  {
418  last_osc0_rhs_before_filter[ k ] += tmp_r[ k ];
419  }
420  }
421  if ( sub_parts_[ 0 ].valid() )
422  {
423  const auto [ lhs1, rhs1 ] = sub_parts_[ 0 ].get();
424  for ( auto k = 0u; k < lhs1.size(); ++k )
425  {
426  last_osc0_lhs_before_filter[ k ] += lhs1[ k ];
427  last_osc0_rhs_before_filter[ k ] += rhs1[ k ];
428  }
429  }
430 
431  if ( sub_parts_[ 1 ].valid() && sub_parts_[ 2 ].valid() )
432  {
433  const auto [ lhs2, rhs2 ] =
434  sub_parts_[ first_double_part_ ? 1 : 2 ].get();
435  for ( auto k = 0u; k < lhs2.size(); ++k )
436  {
437  last_osc0_lhs_before_filter[ k ] += lhs2[ k ];
438  last_osc0_rhs_before_filter[ k ] += rhs2[ k ];
439  }
440  }
441 
442  if ( sub_parts_[ 3 + quad_part_id_ ].valid() )
443  {
444  const auto [ lhs, rhs ] = sub_parts_[ 3 + quad_part_id_ ].get();
445  for ( auto k = 0u; k < lhs.size(); ++k )
446  {
447  last_osc0_lhs_before_filter[ k ] += lhs[ k ];
448  last_osc0_rhs_before_filter[ k ] += rhs[ k ];
449  }
450  }
451  }
452  }
453 
454  frame_pos_ += N;
455  buffer.frames.resize( initial_size );
456  if ( !use_reverb )
457  {
458  for ( auto i = 0; i < N; ++i )
459  {
460  buffer.frames[ size_type( 2 * i ) ] = 0.5 * left[ i ];
461  buffer.frames[ size_type( 2 * i + 1 ) ] = 0.5 * right[ i ];
462  }
463  }
464  else
465  {
466  for ( auto i = 0; i < N; ++i )
467  {
468  buffer.frames[ size_type( 2 * i ) ] =
469  0.5 * ( dry_reverb_ratio_ * left[ i ] +
470  wet_reverb_ratio_ * last_osc0_lhs_before_filter[ i ] );
471  buffer.frames[ size_type( 2 * i + 1 ) ] =
472  0.5 * ( dry_reverb_ratio_ * right[ i ] +
473  wet_reverb_ratio_ * last_osc0_rhs_before_filter[ i ] );
474  }
475  }
476 
477  double_buffer_.swap_write_buffer( buffer );
478  {
479  std::cout << "elapsed: "
480  << duration_cast< milliseconds >( steady_clock::now() -
481  start_time )
482  .count()
483  << std::endl;
484  if ( use_reverb )
485  {
486  sub_parts_[ 0 ] = std::async( std::launch::async, [spectrum_left,
487  spectrum_right,
488  filter =
489  reverb_spectra_
490  [ 1 ]] {
491  auto s = spectrum_left;
492  auto t = spectrum_right;
493  for ( auto k = 0u; k < s.size(); ++k )
494  {
495  s[ k ] *= 0.5f * filter.first[ k ];
496  t[ k ] *= 0.5f * filter.second[ k ];
497  }
498 
499  return std::pair{audio::inverse_fft( s ), audio::inverse_fft( t )};
500  } );
501  sub_parts_[ first_double_part_ ? 1 : 2 ] =
502  std::async( std::launch::async, [spectrum_left, spectrum_right,
503  filter1 = reverb_spectra_[ 2 ],
504  filter2 = reverb_spectra_[ 3 ]] {
505  auto s = spectrum_left;
506  auto t = spectrum_right;
507  for ( auto k = 0u; k < s.size(); ++k )
508  {
509  s[ k ] *= 0.5f * filter1.first[ k ];
510  t[ k ] *= 0.5f * filter1.second[ k ];
511  }
512 
513  auto left = audio::inverse_fft( s );
514  auto right = audio::inverse_fft( t );
515  const auto offset = left.size() / 2;
516  left.resize( left.size() + offset, 0 );
517  right.resize( right.size() + offset, 0 );
518 
519  s = spectrum_left;
520  t = spectrum_right;
521  for ( auto k = 0u; k < s.size(); ++k )
522  {
523  s[ k ] *= 0.5f * filter2.first[ k ];
524  t[ k ] *= 0.5f * filter2.second[ k ];
525  }
526 
527  auto left2 = audio::inverse_fft( s );
528  auto right2 = audio::inverse_fft( t );
529  for ( auto i = 0u; i < left2.size(); ++i )
530  {
531  left[ offset + i ] += left2[ i ];
532  right[ offset + i ] += right2[ i ];
533  }
534 
535  return std::pair{std::move( left ), std::move( right )};
536  } );
537  sub_parts_[ 3 + quad_part_id_ ] = std::async(
538  std::launch::async,
539  [spectrum_left = std::move( spectrum_left ),
540  spectrum_right = std::move( spectrum_right ), this] {
541  auto s = spectrum_left;
542  auto t = spectrum_right;
543  for ( auto k = 0u; k < s.size(); ++k )
544  {
545  s[ k ] *= 0.5f * reverb_spectra_[ 4 ].first[ k ];
546  t[ k ] *= 0.5f * reverb_spectra_[ 4 ].second[ k ];
547  }
548 
549  auto left = audio::inverse_fft( s );
550  auto right = audio::inverse_fft( t );
551  const auto offset = left.size() / 2;
552  left.resize( left.size() + 3 * offset, 0 );
553  right.resize( right.size() + 3 * offset, 0 );
554 
555  s = spectrum_left;
556  t = spectrum_right;
557  for ( auto k = 0u; k < s.size(); ++k )
558  {
559  s[ k ] *= 0.5f * reverb_spectra_[ 5 ].first[ k ];
560  t[ k ] *= 0.5f * reverb_spectra_[ 5 ].second[ k ];
561  }
562 
563  auto left2 = audio::inverse_fft( s );
564  auto right2 = audio::inverse_fft( t );
565  for ( auto i = 0u; i < left2.size(); ++i )
566  {
567  left[ offset + i ] += left2[ i ];
568  right[ offset + i ] += right2[ i ];
569  }
570 
571  s = spectrum_left;
572  t = spectrum_right;
573  for ( auto k = 0u; k < s.size(); ++k )
574  {
575  s[ k ] *= 0.5f * reverb_spectra_[ 6 ].first[ k ];
576  t[ k ] *= 0.5f * reverb_spectra_[ 6 ].second[ k ];
577  }
578 
579  left2 = audio::inverse_fft( s );
580  right2 = audio::inverse_fft( t );
581  for ( auto i = 0u; i < left2.size(); ++i )
582  {
583  left[ 2 * offset + i ] += left2[ i ];
584  right[ 2 * offset + i ] += right2[ i ];
585  }
586 
587  s = spectrum_left;
588  t = spectrum_right;
589  for ( auto k = 0u; k < s.size(); ++k )
590  {
591  s[ k ] *= 0.5f * reverb_spectra_[ 7 ].first[ k ];
592  t[ k ] *= 0.5f * reverb_spectra_[ 7 ].second[ k ];
593  }
594 
595  left2 = audio::inverse_fft( s );
596  right2 = audio::inverse_fft( t );
597  for ( auto i = 0u; i < left2.size(); ++i )
598  {
599  left[ 3 * offset + i ] += left2[ i ];
600  right[ 3 * offset + i ] += right2[ i ];
601  }
602 
603  return std::pair{std::move( left ), std::move( right )};
604  } );
605  first_double_part_ = !first_double_part_;
606  quad_part_id_ = ( ++quad_part_id_ ) % 4;
607  }
608  std::lock_guard lock_left{left_mutex_};
609  std::lock_guard lock_right{right_mutex_};
610  last_osc0_lhs_before_filter.clean_and_move( N );
611  last_osc0_rhs_before_filter.clean_and_move( N );
612  }
613  };
614 
615  write_buffer();
616  auto at_end = false;
617  while ( !stopped_ )
618  {
619  if ( running_ && !double_buffer_.has_new_data() )
620  {
621  if ( at_end )
622  {
623  double_buffer_reader_->set_continue_reading( false );
624  break;
625  }
626  double_buffer_.swap_buffers();
627 
628  write_buffer();
629  }
630  }
631  } );
632  }
633 
635  {
636  stopped_ = true;
637  generating_thread_terminated_.wait();
638  }
639 
640  chain_t& chain( size_type idx ) noexcept
641  {
642  return chains_[ idx ];
643  }
644 
645  const chain_t& chain( size_type idx ) const noexcept
646  {
647  return chains_[ idx ];
648  }
649 
650  void start() noexcept
651  {
652  if ( device_id_ < 0 )
653  {
654  return;
655  }
656  std::lock_guard lock{stream_mutex_};
657  if ( stream_.is_active() )
658  {
659  running_ = true;
660  return;
661  }
662 
663  const auto parameters = portaudio_.get_parameters( device_id_ );
664  stream_.open_output_stream( parameters, sample_rate_, frames_per_buffer_,
666  std::decay_t< decltype( *double_buffer_reader_ ) > >,
667  double_buffer_reader_.get() );
668  stream_.start();
669 
670  running_ = true;
671  }
672 
673  void stop() noexcept
674  {
675  running_ = false;
676 
677  std::lock_guard lock{stream_mutex_};
678  if ( stream_.is_active() )
679  {
680  stream_.close();
681  }
682  }
683 
684  void trigger() noexcept
685  {
686  frame_pos_ = 0;
687  }
688 
689  void set_device( int device_id )
690  {
691  device_id_ = device_id;
692  stop();
693  }
694 
695  std::vector< std::string > available_audio_devices() const
696  {
697  return portaudio_.get_device_names();
698  }
699 
700  template < int N >
701  void receive_message( double dt, const midi::message_t< N >& message )
702  {
703  if constexpr ( N == 1 )
704  {
705  if ( message == midi::realtime::realtime_clock() )
706  {
707  clock_dt_[ clock_dt_counter_++ ] = dt;
708  if ( clock_dt_counter_ == clock_dt_.size() )
709  {
710  clock_dt_counter_ = 0;
711  auto beat_dt = std::accumulate( begin( clock_dt_ ), end( clock_dt_ ), 0.0 );
712  const auto bpm = int( std::round( 60 / beat_dt * 10 ) +
713  std::numeric_limits< double >::epsilon() ) /
714  10.0;
715  set_bpm_( beat_duration{bpm} );
716  }
717  }
718  return;
719  }
720 
721  if constexpr ( N == 3 )
722  {
723  if ( message[ 0 ] == midi::byte::note_on )
724  {
725  trigger();
726  chain( 0 ).silent_ = false;
727  chain( 1 ).silent_ = false;
728  return;
729  }
730  if ( message[ 0 ] == midi::byte::note_off )
731  {
732  chain( 0 ).silent_ = true;
733  chain( 1 ).silent_ = true;
734 
735  chain( 0 ).osc_fade_out_ = chain( 0 ).fade_sample_count_;
736  chain( 1 ).osc_fade_out_ = chain( 1 ).fade_sample_count_;
737  return;
738  }
739  }
740  }
741 
742  template < class F >
743  void set_bpm_functor( F f )
744  {
745  set_bpm_ = f;
746  }
747 
748  std::vector< std::string > available_reverb_banks()
749  {
750  reverb_banks_.clear();
751  std::vector< std::string > folders;
752  const auto path = std::experimental::filesystem::current_path() /
753  std::experimental::filesystem::path(
754  "impulse_responses/EchoThiefImpulseResponseLibrary/" );
755  for ( auto& entry : std::experimental::filesystem::directory_iterator( path ) )
756  {
757  if ( !entry.path().has_extension() )
758  {
759  reverb_banks_.emplace_back( entry.path() );
760  folders.emplace_back( entry.path().filename() );
761  }
762  }
763  return folders;
764  }
765 
766  void set_reverb_bank_id( int id )
767  {
768  SEQUENCER_ASSERT( id < reverb_banks_.size() + 1 )
769  if ( id > 0 )
770  {
771  current_reverb_bank_ = reverb_banks_[ id - 1 ];
772  }
773  set_reverb_type_id( 0 );
774  }
775 
776  std::vector< std::string > available_reverbs()
777  {
778  if ( current_reverb_bank_.empty() )
779  {
780  return {};
781  }
782 
783  std::vector< std::string > reverbs;
784  reverb_files_.clear();
785  for ( auto& entry :
786  std::experimental::filesystem::directory_iterator( current_reverb_bank_ ) )
787  {
788  if ( entry.path().has_stem() )
789  {
790  const auto filename = entry.path().filename();
791  if ( filename.has_extension() && filename.extension() == ".wav" )
792  {
793  reverb_files_.emplace_back( entry.path() );
794  reverbs.emplace_back( filename.stem() );
795  }
796  }
797  }
798  return reverbs;
799  }
800 
801  void set_reverb_type_id( int id )
802  {
803  if ( id <= 0 || current_reverb_bank_.empty() )
804  {
805  std::lock_guard lock{reverb_mutex_};
806  reverb_spectra_.clear();
807  std::lock_guard lock_left{left_mutex_};
808  last_osc0_lhs_before_filter = audio::ring_buffer_t< float >( 2 * sub_sample_size );
809  std::lock_guard lock_right{right_mutex_};
810  last_osc0_rhs_before_filter = audio::ring_buffer_t< float >( 2 * sub_sample_size );
811  return;
812  }
813 
814  auto reverb_channels = audio::wave::read( reverb_files_[ id - 1 ] );
815 
816  reverb_channels[ 0 ].resize( 32 * 1024 );
817  reverb_channels[ 1 ].resize( 32 * 1024 );
818 
819  const auto start_time = std::chrono::steady_clock::now();
820  const auto n_filters = reverb_channels[ 0 ].size() / ( sub_sample_size );
821  const auto filter_offset = reverb_channels[ 0 ].size() / n_filters;
822  std::vector< std::future< std::pair< spectrum_t, spectrum_t > > > done;
823  for ( auto i = 0u; i < n_filters; ++i )
824  {
825  done.push_back(
826  std::async( std::launch::async, [i, filter_offset, &reverb_channels] {
827  auto left = std::vector< float >(
828  begin( reverb_channels[ 0 ] ) + i * filter_offset,
829  begin( reverb_channels[ 0 ] ) + ( i + 1 ) * filter_offset );
830  auto right = std::vector< float >(
831  begin( reverb_channels[ 1 ] ) + i * filter_offset,
832  begin( reverb_channels[ 1 ] ) + ( i + 1 ) * filter_offset );
833  left.resize( 2 * filter_offset, 0 );
834  right.resize( 2 * filter_offset, 0 );
835  return std::make_pair( audio::fft( left ), audio::fft( right ) );
836  } ) );
837  }
838  sub_parts_.resize( 7 );
839 
840  std::lock_guard lock{reverb_mutex_};
841  reverb_spectra_.resize( n_filters );
842  for ( auto i = 0; i < n_filters; ++i )
843  {
844  reverb_spectra_[ i ] = done[ i ].get();
845  }
846 
847  const auto elapsed = std::chrono::duration_cast< std::chrono::milliseconds >(
848  std::chrono::steady_clock::now() - start_time )
849  .count();
850  std::cout << "set reverb in " << elapsed << "ms" << std::endl;
851  std::lock_guard lock_left{left_mutex_};
852  last_osc0_lhs_before_filter =
853  audio::ring_buffer_t< float >( sub_sample_size + n_filters * filter_offset );
854  std::lock_guard lock_right{right_mutex_};
855  last_osc0_rhs_before_filter =
856  audio::ring_buffer_t< float >( sub_sample_size + n_filters * filter_offset );
857  }
858 
859  void set_dry_wet_ratio( double ratio ) noexcept
860  {
861  dry_reverb_ratio_ = audio::compute_dry_ratio( ratio );
862  wet_reverb_ratio_ = audio::compute_wet_ratio( ratio );
863  }
864 
865  private:
866  portaudio::portaudio portaudio_{};
867  std::mutex stream_mutex_{};
869  std::vector< chain_t > chains_{};
870  audio::double_buffer_t double_buffer_{};
871  std::shared_ptr< audio::double_buffer_reader_t > double_buffer_reader_{
872  std::make_shared< audio::double_buffer_reader_t >( double_buffer_ )};
873  std::future< void > generating_thread_terminated_;
874  int sample_rate_{44100};
875  int device_id_{-1};
876  std::atomic_int frame_pos_{0};
877  std::size_t frames_per_buffer_{256};
878  std::atomic_bool running_{false};
879  std::atomic_bool stopped_{false};
880  std::function< void( beat_duration ) > set_bpm_ = []( beat_duration ) {};
881  std::vector< double > clock_dt_;
882  std::vector< double >::size_type clock_dt_counter_{0};
883 
884  std::mutex reverb_mutex_;
885  using spectrum_t = std::vector< std::complex< float > >;
886  std::vector< std::pair< spectrum_t, spectrum_t > > reverb_spectra_;
887 
888  std::mutex left_mutex_;
889  std::mutex right_mutex_;
890  audio::ring_buffer_t< float > last_osc0_lhs_before_filter{2 * sub_sample_size};
891  audio::ring_buffer_t< float > last_osc0_rhs_before_filter{2 * sub_sample_size};
892 
893  std::vector< std::experimental::filesystem::path > reverb_banks_{};
894  std::vector< std::experimental::filesystem::path > reverb_files_{};
895  std::experimental::filesystem::path current_reverb_bank_{};
896 
897  std::atomic< double > dry_reverb_ratio_{1};
898  std::atomic< double > wet_reverb_ratio_{0};
899 
900  std::vector< std::future< std::pair< std::vector< float >, std::vector< float > > > >
901  sub_parts_{};
902  bool first_double_part_{true};
903  int quad_part_id_{0};
904  };
905 } // namespace sequencer::backend::synth
void set_lowpass_frequency(double frequency)
Definition: synth.hpp:138
std::vector< std::complex< float > > spectrum_t
Definition: synth.hpp:86
Definition: synth.hpp:81
std::vector< std::complex< T > > fft(const std::vector< T > &x)
Definition: fft.hpp:167
constexpr T compute_wet_ratio(T x) noexcept
Definition: dry_wet.hpp:30
Definition: synth.hpp:345
chain_t & chain(size_type idx) noexcept
Definition: synth.hpp:640
constexpr message_t< 1 > realtime_clock() noexcept
Definition: realtime.hpp:8
copyable_atomic< double > highpass_gain
Definition: synth.hpp:179
const auto F
Definition: note.hpp:40
auto get_sample(int frame_pos, int sample_rate)
Definition: synth.hpp:98
void set_dry_wet_ratio(double ratio) noexcept
Definition: synth.hpp:859
Definition: portaudio.hpp:105
std::vector< chain_t >::size_type size_type
Definition: synth.hpp:348
void start() noexcept
Definition: synth.hpp:650
Definition: oscillator.hpp:20
std::conditional_t< greater_than< number_of_bytes, 0 >::value, std::array< std::byte, number_of_bytes >, std::vector< std::byte > > message_t
Definition: message_type.hpp:18
double blackman(int n, int N)
Definition: transfer_function.hpp:74
#define SEQUENCER_ASSERT(cond)
Definition: assert.hpp:8
backend_t(Callback callback)
Definition: synth.hpp:355
static constexpr auto sub_sample_size
Definition: synth.hpp:83
audio::dry_wet_t< audio::oscillator_t > frequency_modulation
Definition: synth.hpp:173
Definition: beat_duration.hpp:13
std::chrono::duration< double, std::milli > milliseconds
Definition: units.hpp:7
auto overlay_add_sub(const spectrum_t &spectrum_left, const spectrum_t &spectrum_right, const std::vector< std::pair< spectrum_t, spectrum_t > > &filters, std::vector< std::future< std::pair< std::vector< float >, std::vector< float > > > > &done, bool first_long_part)
Definition: synth.hpp:228
Definition: envelope.hpp:11
void update_filter_spectrum(int N)
Definition: synth.hpp:144
auto create_filter_response(int N, float lowpass_cutoff, float highpass_cutoff)
Definition: synth.hpp:65
Definition: sample.hpp:74
std::vector< float > create_blackman_table(int N)
Definition: synth.hpp:30
audio::dry_wet_t< audio::oscillator_t > ring_modulation
Definition: synth.hpp:172
void stop() noexcept
Definition: synth.hpp:673
Definition: delay.hpp:12
void clean_and_move(size_type N) noexcept
Definition: ring_buffer.hpp:115
void receive_message(double dt, const midi::message_t< N > &message)
Definition: synth.hpp:701
constexpr double make_vca(double signal)
Definition: synth.hpp:76
Definition: portaudio.hpp:29
double sinc(double cutoff, int i)
Definition: wave_form.hpp:71
double operator()(double pos)
Definition: synth.hpp:88
auto convolution(const std::vector< float > &signal, const std::vector< float > &reverb)
Definition: synth.hpp:194
copyable_atomic< int > sample_rate
Definition: synth.hpp:180
std::vector< std::string > available_reverb_banks()
Definition: synth.hpp:748
std::atomic_int osc_fade_out_
Definition: synth.hpp:183
auto create_kernels(int N, float lowpass_cutoff, float highpass_cutoff)
Definition: synth.hpp:41
void set_reverb_type_id(int id)
Definition: synth.hpp:801
int fade_sample_count_
Definition: synth.hpp:184
void set_reverb_bank_id(int id)
Definition: synth.hpp:766
std::atomic_bool silent_
Definition: synth.hpp:182
Definition: dry_wet.hpp:36
copyable_atomic< double > lowpass_gain
Definition: synth.hpp:178
constexpr auto note_on
Definition: byte.hpp:9
void filter(spectrum_t &spectrum) const
Definition: synth.hpp:157
void set_bpm_functor(F f)
Definition: synth.hpp:743
std::vector< T > inverse_fft(const std::vector< std::complex< T > > &x)
Definition: fft.hpp:260
constexpr auto note_off
Definition: byte.hpp:10
audio::dry_wet_t< audio::stereo_repeated_delay_t, true > delay
Definition: synth.hpp:175
copyable_atomic< bool > vca_mode
Definition: synth.hpp:176
int play_callback(const void *, void *output_buffer, unsigned long frames_per_buffer, const PaStreamCallbackTimeInfo *, PaStreamCallbackFlags, void *user_data)
Definition: portaudio.hpp:178
static constexpr auto M
Definition: synth.hpp:84
audio::oscillator_t oscillator
Definition: synth.hpp:171
void set_device(int device_id)
Definition: synth.hpp:689
std::vector< std::vector< float > > read(const std::vector< std::uint8_t > &data)
Definition: wave_reader.hpp:91
copyable_atomic< bool > vca_enabled
Definition: synth.hpp:177
void set_highpass_frequency(double frequency)
Definition: synth.hpp:132
Definition: double_buffer.hpp:11
void trigger() noexcept
Definition: synth.hpp:684
Definition: synth.hpp:28
std::vector< std::string > available_audio_devices() const
Definition: synth.hpp:695
~backend_t()
Definition: synth.hpp:634
constexpr T compute_dry_ratio(T x) noexcept
Definition: dry_wet.hpp:24
audio::envelope_t envelope
Definition: synth.hpp:174
std::vector< std::string > available_reverbs()
Definition: synth.hpp:776
const chain_t & chain(size_type idx) const noexcept
Definition: synth.hpp:645