sequencer
portaudio.hpp
Go to the documentation of this file.
1 #pragma once
2 
5 
6 #include <exception>
7 #include <portaudio.h>
8 #include <string>
9 #include <vector>
10 
12 {
13  class exception : public std::exception
14  {
15  public:
16  explicit exception( std::string&& message ) noexcept : message_( std::move( message ) )
17  {
18  }
19 
20  const char* what() const noexcept override
21  {
22  return message_.c_str();
23  }
24 
25  private:
26  std::string message_;
27  };
28 
29  class portaudio
30  {
31  public:
33  {
34  if ( Pa_Initialize() != paNoError )
35  {
36  throw exception{"Failed to initialize portaudio."};
37  }
38  }
39 
41  {
42  Pa_Terminate();
43  }
44 
46  {
47  const auto device = Pa_GetDefaultInputDevice();
48  if ( device == paNoDevice )
49  {
50  throw exception{"No default input device."};
51  }
52  return device;
53  }
54 
56  {
57  const auto device = Pa_GetDefaultOutputDevice();
58  if ( device == paNoDevice )
59  {
60  throw exception{"No default output device"};
61  }
62  return device;
63  }
64 
65  int number_of_devices() const noexcept
66  {
67  return Pa_GetDeviceCount();
68  }
69 
70  std::vector< std::string > get_device_names() const
71  {
72  std::vector< std::string > device_names;
73  for ( auto i = 0; i < number_of_devices(); ++i )
74  {
75  device_names.push_back( Pa_GetDeviceInfo( i )->name );
76  }
77  return device_names;
78  }
79 
80  bool is_supported( int input_device_id, audio::mode_t input_mode, int output_device_id,
81  audio::mode_t output_mode, int desired_sample_rate )
82  {
83  const auto input_parameters = get_parameters( input_device_id, input_mode );
84  const auto output_parameters = get_parameters( output_device_id, output_mode );
85  const auto error =
86  Pa_IsFormatSupported( &input_parameters, &output_parameters, desired_sample_rate );
87  return error == paFormatIsSupported;
88  }
89 
90  PaStreamParameters get_parameters( int device_id,
92  {
93  PaStreamParameters parameters;
94  parameters.channelCount = static_cast< audio::underlying_t::mode_t >( mode );
95  parameters.device = device_id;
96  parameters.hostApiSpecificStreamInfo = nullptr;
97  parameters.sampleFormat = paFloat32;
98  parameters.suggestedLatency = Pa_GetDeviceInfo( device_id )->defaultLowInputLatency;
99  parameters.hostApiSpecificStreamInfo =
100  nullptr; // See you specific host's API docs for info on using this field
101  return parameters;
102  }
103  };
104 
105  class stream_t
106  {
107  public:
109  {
110  Pa_CloseStream( stream_ );
111  }
112 
113  void open_input_stream( const PaStreamParameters& input_parameters, double sample_rate,
114  unsigned long frames_per_buffer, PaStreamCallback* stream_callback,
115  void* data )
116  {
117  const auto error = Pa_OpenStream( &stream_, &input_parameters, nullptr, sample_rate,
118  frames_per_buffer, paClipOff, stream_callback, data );
119  if ( error != paNoError )
120  {
121  throw exception{"Could not open input stream, error code: " +
122  std::to_string( error )};
123  }
124  }
125 
126  void open_output_stream( const PaStreamParameters& output_parameters, double sample_rate,
127  unsigned long frames_per_buffer, PaStreamCallback* stream_callback,
128  void* data )
129  {
130  const auto error = Pa_OpenStream( &stream_, nullptr, &output_parameters, sample_rate,
131  frames_per_buffer, paClipOff, stream_callback, data );
132  if ( error != paNoError )
133  {
134  throw exception{"Could not open output stream, error code: " +
135  std::to_string( error )};
136  }
137  }
138 
139  void start()
140  {
141  const auto error = Pa_StartStream( stream_ );
142  if ( error != paNoError )
143  {
144  throw exception{"Could not start stream, error code: " + std::to_string( error )};
145  }
146  }
147 
148  bool is_active() const
149  {
150  return stream_ != nullptr && Pa_IsStreamActive( stream_ ) == 1;
151  }
152 
153  void close()
154  {
155  const auto error = Pa_CloseStream( stream_ );
156  if ( error != paNoError )
157  {
158  throw exception{"Could not close stream, error code: " + std::to_string( error )};
159  }
160  }
161 
162  private:
163  PaStream* stream_;
164  };
165 
166  inline int record_callback( const void* input_buffer, void*, unsigned long frames_per_buffer,
167  const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags,
168  void* user_data )
169  {
171  auto* writer = static_cast< sample_writer_t* >( user_data );
172  writer->write( static_cast< const sample_writer_t::frame_rep* >( input_buffer ),
173  frames_per_buffer );
174  return writer->has_frames_left() ? paContinue : paComplete;
175  }
176 
177  template < class Reader >
178  inline int play_callback( const void*, void* output_buffer, unsigned long frames_per_buffer,
179  const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags,
180  void* user_data )
181  {
182  auto* reader = static_cast< Reader* >( user_data );
183  reader->read( static_cast< typename Reader::frame_rep* >( output_buffer ),
184  frames_per_buffer );
185  return reader->continue_reading() ? paContinue : paComplete;
186  }
187 } // namespace sequencer::portaudio
~portaudio()
Definition: portaudio.hpp:40
const char * what() const noexcept override
Definition: portaudio.hpp:20
~stream_t()
Definition: portaudio.hpp:108
Definition: portaudio.hpp:105
void close()
Definition: portaudio.hpp:153
exception(std::string &&message) noexcept
Definition: portaudio.hpp:16
int record_callback(const void *input_buffer, void *, unsigned long frames_per_buffer, const PaStreamCallbackTimeInfo *, PaStreamCallbackFlags, void *user_data)
Definition: portaudio.hpp:166
void open_output_stream(const PaStreamParameters &output_parameters, double sample_rate, unsigned long frames_per_buffer, PaStreamCallback *stream_callback, void *data)
Definition: portaudio.hpp:126
bool is_active() const
Definition: portaudio.hpp:148
Definition: portaudio.hpp:29
PaStreamParameters get_parameters(int device_id, audio::mode_t mode=audio::mode_t::stereo) const
Definition: portaudio.hpp:90
mode_t
Definition: sample.hpp:17
void write(const frame_rep *data, std::size_t frames_per_buffer)
Definition: sample.hpp:166
Definition: portaudio.hpp:11
void open_input_stream(const PaStreamParameters &input_parameters, double sample_rate, unsigned long frames_per_buffer, PaStreamCallback *stream_callback, void *data)
Definition: portaudio.hpp:113
portaudio()
Definition: portaudio.hpp:32
int get_default_output_device() const
Definition: portaudio.hpp:55
std::vector< std::string > get_device_names() const
Definition: portaudio.hpp:70
std::string_view to_string(percussion_key key)
Definition: percussion_key.hpp:69
bool is_supported(int input_device_id, audio::mode_t input_mode, int output_device_id, audio::mode_t output_mode, int desired_sample_rate)
Definition: portaudio.hpp:80
int get_default_input_device() const
Definition: portaudio.hpp:45
void start()
Definition: portaudio.hpp:139
Definition: sample.hpp:161
Definition: portaudio.hpp:13
int number_of_devices() const noexcept
Definition: portaudio.hpp:65
std::uint8_t mode_t
Definition: sample.hpp:14
int play_callback(const void *, void *output_buffer, unsigned long frames_per_buffer, const PaStreamCallbackTimeInfo *, PaStreamCallbackFlags, void *user_data)
Definition: portaudio.hpp:178