11#define PDEBUG(...)             Ase::debug ("alsa", "PCM: " __VA_ARGS__) 
   12#define MDEBUG(...)             Ase::debug ("alsa", "MIDI: " __VA_ARGS__) 
   14#define ALSAQUIET(expr)         ({ silence_error_handler++; auto __ret_ = (expr); silence_error_handler--; __ret_; }) 
   15#define WITH_MIDI_POLL  0 
   17#define alsa_alloca0(struc)     ({ struc##_t *ptr = (struc##_t*) alloca (struc##_sizeof()); memset (ptr, 0, struc##_sizeof()); ptr; }) 
   18#define return_error(reason, aerror, ERRMEMB)           do {    \ 
   19    const Error __ase_error = ase_error_from_errno (-aerror, Ase::Error::ERRMEMB); \ 
   20    Ase::debug ("alsa", "%s: %s: %s", alsadev_, reason,                 \ 
   21                ase_error_blurb (__ase_error));                         \ 
   52#if __has_include(<alsa/asoundlib.h>) 
   53#include <alsa/asoundlib.h> 
   56static_assert (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__, 
"endianess unimplemented");
 
   63chars2string (
const char *s)
 
   69cxfree (
char *mallocedstring, 
const char *fallback = 
"")
 
   73      const String string = mallocedstring;
 
   74      free (mallocedstring);
 
   83  std::string::size_type l = 0;
 
   85  for (std::string::size_type i = input.
find (from, 0); i != std::string::npos; l = i + 1, i = input.
find (from, l))
 
   87      target.
append (input, l, i - l);
 
   97ase_handle_alsa_error (
const char *file, 
int line, 
const char *function, 
int err, 
const char *fmt, ...)
 
   99  if (silence_error_handler != 0)
 
  101  constexpr const int MAXBUFFER = 8 * 1024;
 
  102  char buffer[MAXBUFFER + 2] = { 0, }, *b = buffer, *e = b + MAXBUFFER;
 
  105  const int plen = 
vsnprintf (b, e - b, fmt, argv);
 
  109  if (file && line > 0 && function)
 
  111  else if (file && line > 0)
 
  113  else if (file && function)
 
  115  else if (file || function)
 
  117  Ase::debug (
"alsa", 
"Error: %s", s);
 
  120static snd_output_t *snd_output = 
nullptr; 
 
  125  static const bool ASE_USED initialized = [] {
 
  126    snd_lib_error_set_handler (ase_handle_alsa_error);
 
  127    return snd_output_stdio_attach (&snd_output, stderr, 0);
 
  132mixer_elem_get_channels (snd_mixer_elem_t *
const mel,
 
  133                         const std::function<
int (snd_mixer_elem_t*, snd_mixer_selem_channel_id_t)> &mixer_has_channel,
 
  138    for (snd_mixer_selem_channel_id_t i = SND_MIXER_SCHN_MONO; i <= SND_MIXER_SCHN_LAST;
 
  139         i = snd_mixer_selem_channel_id_t (i + 1))
 
  140      if (mixer_has_channel (mel, i))
 
  141        channels.push_back (i);
 
  148  snd_mixer_t *mixer = 
nullptr;
 
  149  snd_mixer_selem_regopt regopt = { .ver = 1, .abstract = SND_MIXER_SABSTRACT_NONE, .device = card_hw.
c_str() };
 
  150  snd_mixer_selem_id_t *selem_id = 
nullptr;
 
  152  int bseen = 0, iseen = 0, oseen = 0, maxin = 0, maxout = 0;
 
  153  int err = snd_mixer_open (&mixer, 0);
 
  154  if (err < 0) 
goto error_out;
 
  155  err = snd_mixer_selem_register (mixer, ®opt, 
nullptr);
 
  156  if (err < 0) 
goto error_out;
 
  157  err = snd_mixer_load (mixer);
 
  158  if (err < 0) 
goto error_out;
 
  159  err = snd_mixer_selem_id_malloc (&selem_id);
 
  160  if (err < 0) 
goto error_out;
 
  161  PDEBUG (
"CARD(%s): %s [%s]", card_hw, long_name, mixer_name);
 
  162  PDEBUG (
"M-------- %-6s %2u %s %s - %s", 
"MIXER", snd_mixer_get_count (mixer), card_hw, mixer_name, long_name);
 
  163  for (snd_mixer_elem_t *mel = snd_mixer_first_elem (mixer); mel; mel = snd_mixer_elem_next (mel))
 
  165      if (snd_mixer_elem_get_type (mel) != SND_MIXER_ELEM_SIMPLE)
 
  168      const snd_mixer_selem_channel_id_t c0 = SND_MIXER_SCHN_MONO;
 
  169      const bool cv = snd_mixer_selem_has_capture_volume (mel);
 
  170      const bool pv = snd_mixer_selem_has_playback_volume (mel);
 
  171      const bool S = snd_mixer_selem_has_common_switch (mel) || snd_mixer_selem_has_playback_switch (mel) || snd_mixer_selem_has_capture_switch (mel);
 
  172      const bool e = snd_mixer_selem_is_enumerated (mel); 
 
  173      const char *tname = pv ? cv ? 
"INOUT" : 
"OUT" : cv ? 
"IN" : S ? 
"SWITCH" : e ? 
"ENUM" : 
"-";
 
  174      const bool a = snd_mixer_selem_is_active (mel);
 
  175      const bool j = snd_mixer_selem_has_playback_volume_joined (mel) || snd_mixer_selem_has_capture_volume_joined (mel);
 
  176      const bool m = snd_mixer_selem_has_playback_switch (mel) && snd_mixer_selem_get_playback_switch (mel, c0, &v) == 0 && !v;
 
  177      const bool M = m && snd_mixer_selem_has_playback_switch_joined (mel);
 
  178      const bool c = snd_mixer_selem_has_capture_switch (mel) && snd_mixer_selem_get_capture_switch (mel, c0, &v) == 0 && v;
 
  179      const bool C = c && snd_mixer_selem_has_capture_switch_joined (mel);
 
  180      const bool x = snd_mixer_selem_has_capture_switch_exclusive (mel);
 
  181      const auto p = mixer_elem_get_channels (mel, snd_mixer_selem_has_playback_channel, pv);
 
  182      const auto d = mixer_elem_get_channels (mel, snd_mixer_selem_has_capture_channel, cv);
 
  183      maxout = 
std::max (maxout, 
int (p.size()));
 
  184      maxin = 
std::max (maxin, 
int (d.size()));
 
  193      for (
const auto ch : p)
 
  194        if ((ch == 0 || !snd_mixer_selem_has_playback_volume_joined (mel)) &&
 
  195            0 == snd_mixer_selem_get_playback_volume (mel, ch, &l))
 
  197      for (
const auto ch : d)
 
  198        if ((ch == 0 || !snd_mixer_selem_has_capture_volume_joined (mel)) &&
 
  199            0 == snd_mixer_selem_get_capture_volume (mel, ch, &l))
 
  201      val = val.
empty() ? 
"" : 
": " + val;
 
  202      PDEBUG (
"-%c%c%c%c%c%c%c%c %-6s %2u %s%s",
 
  203              cv ? 
'r' : 
'-', pv ? 
'w' : 
'-', a ? 
'-' : 
'i',
 
  205              M ? 
'M' : m ? 
'm' : 
'-',
 
  207              C ? 
'C' : c ? 
'c' : 
'-',
 
  210              snd_mixer_selem_get_name (mel),
 
  214    hints += (hints.empty() ? 
"" : 
", ") + 
String (
"surround");
 
  215  if (oseen == 1 && bseen + iseen == 1)
 
  216    hints += (hints.empty() ? 
"" : 
", ") + 
String (
"headset");
 
  217  if (oseen + bseen == 0 && iseen >= 1)
 
  218    hints += (hints.empty() ? 
"" : 
", ") + 
String (
"recorder");
 
  220    hints += (hints.empty() ? 
"" : 
", ") + 
String (
"multi-track");
 
  222    PDEBUG (
"(%s)", hints);
 
  225    snd_mixer_close (mixer);
 
  227    snd_mixer_selem_id_free (selem_id);
 
  232list_alsa_drivers (Driver::EntryVec &entries)
 
  236  bool seen_plughw = 
false; 
 
  237  void **nhints = 
nullptr;
 
  238  if (ALSAQUIET (snd_device_name_hint (-1, 
"pcm", &nhints)) >= 0) 
 
  241      for (
void **hint = nhints; *hint; hint++)
 
  243          name = cxfree (snd_device_name_get_hint (*hint, 
"NAME"));           
 
  244          desc = cxfree (snd_device_name_get_hint (*hint, 
"DESC"));           
 
  245          ioid = cxfree (snd_device_name_get_hint (*hint, 
"IOID"), 
"Duplex"); 
 
  246          seen_plughw = seen_plughw || 
strncmp (name.c_str(), 
"plughw:", 7) == 0;
 
  249              PDEBUG (
"DISCOVER: %s - %s - %s", name, ioid, substitute_string (
"\n", 
" ", desc));
 
  252              entry.device_name = desc;
 
  253              entry.device_info = 
"Routing via the PulseAudio sound system";
 
  254              entry.notice = 
"Note: PulseAudio routing is not realtime capable";
 
  255              entry.readonly = 
"Input" == ioid;
 
  256              entry.writeonly = 
"Output" == ioid;
 
  257              entry.priority = Driver::PULSE;
 
  258              entries.push_back (entry);
 
  261      snd_device_name_free_hint (nhints);
 
  264  snd_ctl_card_info_t *cinfo = alsa_alloca0 (snd_ctl_card_info);
 
  266  while (snd_card_next (&cindex) == 0 && cindex >= 0)
 
  268      snd_ctl_card_info_clear (cinfo);
 
  269      snd_ctl_t *chandle = 
nullptr;
 
  271      if (snd_ctl_open (&chandle, card_hw.c_str(), SND_CTL_NONBLOCK) < 0 || !chandle)
 
  273      if (snd_ctl_card_info (chandle, cinfo) < 0)
 
  275          snd_ctl_close (chandle);
 
  278      const String card_id = chars2string (snd_ctl_card_info_get_id (cinfo));
 
  279      const String card_driver = chars2string (snd_ctl_card_info_get_driver (cinfo));
 
  280      const String card_name = chars2string (snd_ctl_card_info_get_name (cinfo));
 
  281      const String card_longname = chars2string (snd_ctl_card_info_get_longname (cinfo));
 
  282      const String card_mixername = chars2string (snd_ctl_card_info_get_mixername (cinfo));
 
  284      const String mixer_keywords = mixer_info (card_hw, card_mixername, card_longname);
 
  287      snd_pcm_info_t *wpi = alsa_alloca0 (snd_pcm_info);
 
  288      snd_pcm_info_t *rpi = alsa_alloca0 (snd_pcm_info);
 
  290      while (snd_ctl_pcm_next_device (chandle, &dindex) == 0 && dindex >= 0)
 
  292          snd_pcm_info_set_device (wpi, dindex);
 
  293          snd_pcm_info_set_subdevice (wpi, 0);
 
  294          snd_pcm_info_set_stream (wpi, SND_PCM_STREAM_PLAYBACK);
 
  295          const bool writable = snd_ctl_pcm_info (chandle, wpi) == 0;
 
  296          snd_pcm_info_set_device (rpi, dindex);
 
  297          snd_pcm_info_set_subdevice (rpi, 0);
 
  298          snd_pcm_info_set_stream (rpi, SND_PCM_STREAM_CAPTURE);
 
  299          const bool readable = snd_ctl_pcm_info (chandle, rpi) == 0;
 
  300          const auto pcmclass = snd_pcm_info_get_class (writable ? wpi : rpi);
 
  301          if (!writable && !readable)
 
  303          const int total_playback_subdevices = writable ? snd_pcm_info_get_subdevices_count (wpi) : 0;
 
  304          const int avail_playback_subdevices = writable ? snd_pcm_info_get_subdevices_avail (wpi) : 0;
 
  306          if (total_playback_subdevices && total_playback_subdevices != avail_playback_subdevices)
 
  307            wdevs = 
string_format (
"%u*playback (%u busy)", total_playback_subdevices, total_playback_subdevices - avail_playback_subdevices);
 
  308          else if (total_playback_subdevices)
 
  309            wdevs = 
string_format (
"%u*playback", total_playback_subdevices);
 
  310          const int total_capture_subdevices = readable ? snd_pcm_info_get_subdevices_count (rpi) : 0;
 
  311          const int avail_capture_subdevices = readable ? snd_pcm_info_get_subdevices_avail (rpi) : 0;
 
  312          if (total_capture_subdevices && total_capture_subdevices != avail_capture_subdevices)
 
  313            rdevs = 
string_format (
"%u*capture (%u busy)", total_capture_subdevices, total_capture_subdevices - avail_capture_subdevices);
 
  314          else if (total_capture_subdevices)
 
  315            rdevs = 
string_format (
"%u*capture", total_capture_subdevices);
 
  316          const String joiner = !wdevs.
empty() && !rdevs.empty() ? 
" + " : 
"";
 
  318          entry.devid = 
string_format (
"hw:CARD=%s,DEV=%u", card_id, dindex);
 
  319          const bool is_usb = 
string_startswith (chars2string (snd_pcm_info_get_id (writable ? wpi : rpi)), 
"USB Audio");
 
  320          entry.device_name = chars2string (snd_pcm_info_get_name (writable ? wpi : rpi));
 
  321          entry.device_name += 
" - " + card_name;
 
  322          entry.hints = mixer_keywords;
 
  323          if (card_name != card_mixername && !card_mixername.empty())
 
  324            entry.device_name += 
" [" + card_mixername + 
"]";
 
  325          if (pcmclass == SND_PCM_CLASS_GENERIC)
 
  326            entry.capabilities = readable && writable ? 
"Full-Duplex Audio" : readable ? 
"Audio Input" : 
"Audio Output";
 
  328            entry.capabilities = readable && writable ? 
"Full-Duplex Modem" : readable ? 
"Modem Input" : 
"Modem Output";
 
  329          entry.capabilities += 
", streams: " + wdevs + joiner + rdevs;
 
  331            entry.device_info = card_longname;
 
  332          entry.readonly = !writable;
 
  333          entry.writeonly = !readable;
 
  335          entry.priority = (is_usb ? Driver::ALSA_USB : Driver::ALSA_KERN) + Driver::WCARD * cindex + Driver::WDEV * dindex;
 
  336          entry.priority &= 
string_option_check (mixer_options, 
"surround") ? ~Driver::SURROUND : ~0; 
 
  338          entry.priority &= 
string_option_check (mixer_options, 
"recorder") ? ~Driver::RECORDER : ~0; 
 
  339          entries.push_back (entry);
 
  340          PDEBUG (
"DISCOVER: %s - %s", entry.devid, entry.device_name);
 
  342      snd_ctl_close (chandle);
 
  347class AlsaPcmDriver : 
public PcmDriver {
 
  348  snd_pcm_t    *read_handle_ = 
nullptr;
 
  349  snd_pcm_t    *write_handle_ = 
nullptr;
 
  351  uint          n_channels_ = 0;
 
  353  int           period_size_ = 0;       
 
  354  int16        *period_buffer_ = 
nullptr;
 
  355  uint          read_write_count_ = 0;
 
  358  explicit      AlsaPcmDriver (
const String &driver, 
const String &devid) : PcmDriver (driver, devid) {}
 
  360  create (
const String &devid)
 
  368      snd_pcm_close (read_handle_);
 
  370      snd_pcm_close (write_handle_);
 
  371    delete[] period_buffer_;
 
  374  pcm_n_channels ()
 const override 
  379  pcm_mix_freq ()
 const override 
  384  pcm_block_length ()
 const override 
  392    PDEBUG (
"CLOSE: %s: r=%d w=%d", alsadev_, !!read_handle_, !!write_handle_);
 
  395        snd_pcm_drop (read_handle_);
 
  396        snd_pcm_close (read_handle_);
 
  397        read_handle_ = 
nullptr;
 
  401        snd_pcm_nonblock (write_handle_, 0);
 
  402        snd_pcm_drain (write_handle_);
 
  403        snd_pcm_close (write_handle_);
 
  404        write_handle_ = 
nullptr;
 
  406    delete[] period_buffer_;
 
  407    period_buffer_ = 
nullptr;
 
  408    flags_ &= ~size_t (Flags::OPENED | Flags::READABLE | Flags::WRITABLE);
 
  412  open (IODir iodir, 
const PcmDriverConfig &config)
 override 
  414    Error error = 
open (devid_, iodir, config);
 
  415    if (error != Error::NONE && strncmp (
"hw:", devid_.c_str(), 3) == 0)
 
  416      error = 
open (
"plug" + devid_, iodir, config);
 
  420  open (
const String &alsadev, IODir iodir, 
const PcmDriverConfig &config)
 
  426    const bool require_readable = iodir == READONLY || iodir == READWRITE;
 
  427    const bool require_writable = iodir == WRITEONLY || iodir == READWRITE;
 
  428    flags_ |= Flags::READABLE * require_readable;
 
  429    flags_ |= Flags::WRITABLE * require_writable;
 
  430    n_channels_ = config.n_channels;
 
  432    if (!aerror && require_readable)
 
  433      aerror = snd_pcm_open (&read_handle_, alsadev_.c_str(), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
 
  434    if (!aerror && require_writable)
 
  435      aerror = snd_pcm_open (&write_handle_, alsadev_.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
 
  437    const uint period_size = config.block_length;
 
  438    Error error = !aerror ? Error::NONE : ase_error_from_errno (-aerror, Error::FILE_OPEN_FAILED);
 
  439    uint rh_freq = config.mix_freq, rh_n_periods = 2, rh_period_size = period_size;
 
  440    if (!aerror && read_handle_)
 
  441      error = alsa_device_setup (read_handle_, config.latency_ms, &rh_freq, &rh_n_periods, &rh_period_size);
 
  442    uint wh_freq = config.mix_freq, wh_n_periods = 2, wh_period_size = period_size;
 
  443    if (!aerror && write_handle_)
 
  444      error = alsa_device_setup (write_handle_, config.latency_ms, &wh_freq, &wh_n_periods, &wh_period_size);
 
  446    if (!error && read_handle_ && write_handle_)
 
  448        const bool linked = snd_pcm_link (read_handle_, write_handle_) == 0;
 
  449        if (rh_freq != wh_freq || rh_n_periods != wh_n_periods || rh_period_size != wh_period_size || !linked)
 
  450          error = Error::DEVICES_MISMATCH;
 
  451        PDEBUG (
"OPEN: %s: %s: %f==%f && %d*%d==%d*%d && linked==%d", alsadev_,
 
  452                error != 0 ? 
"MISMATCH" : 
"LINKED", rh_freq, wh_freq, rh_n_periods, rh_period_size, wh_n_periods, wh_period_size, linked);
 
  454    mix_freq_ = read_handle_ ? rh_freq : wh_freq;
 
  455    n_periods_ = read_handle_ ? rh_n_periods : wh_n_periods;
 
  456    period_size_ = read_handle_ ? rh_period_size : wh_period_size;
 
  457    if (!error && (!read_handle_ || !write_handle_))
 
  458      PDEBUG (
"OPEN: %s: %s: mix=%.1fHz n=%d period=%d", alsadev_,
 
  459              read_handle_ ? 
"READONLY" : 
"WRITEONLY", mix_freq_, n_periods_, period_size_);
 
  461      aerror = snd_pcm_prepare (read_handle_ ? read_handle_ : write_handle_);
 
  462      error = !aerror ? Error::NONE : ase_error_from_errno (-aerror, Error::FILE_OPEN_FAILED);
 
  467        period_buffer_ = 
new int16[period_size_ * n_channels_];
 
  468        flags_ |= Flags::OPENED;
 
  473          snd_pcm_close (read_handle_);
 
  474        read_handle_ = 
nullptr;
 
  476          snd_pcm_close (write_handle_);
 
  477        write_handle_ = 
nullptr;
 
  479    PDEBUG (
"OPEN: %s: opening readable=%d writable=%d: %s", alsadev_, readable(), writable(), ase_error_blurb (error));
 
  485  alsa_device_setup (snd_pcm_t *phandle, uint latency_ms, uint *mix_freq, uint *n_periodsp, uint *period_sizep)
 
  488    if (
int aerror = snd_pcm_nonblock (phandle, 0); aerror < 0)
 
  489      return_error (
"snd_pcm_nonblock", aerror, FILE_OPEN_FAILED);
 
  491    snd_pcm_hw_params_t *hparams = alsa_alloca0 (snd_pcm_hw_params);
 
  492    if (
int aerror = snd_pcm_hw_params_any (phandle, hparams); aerror < 0) 
 
  493      return_error (
"snd_pcm_hw_params_any", aerror, FILE_OPEN_FAILED);
 
  494    if (
int aerror = snd_pcm_hw_params_set_channels (phandle, hparams, n_channels_); aerror < 0)
 
  495      return_error (
"snd_pcm_hw_params_set_channels", aerror, DEVICE_CHANNELS);
 
  496    if (
int aerror = snd_pcm_hw_params_set_access (phandle, hparams, SND_PCM_ACCESS_RW_INTERLEAVED); aerror < 0)
 
  497      return_error (
"snd_pcm_hw_params_set_access", aerror, DEVICE_FORMAT);
 
  498    if (
int aerror = snd_pcm_hw_params_set_format (phandle, hparams, SND_PCM_FORMAT_S16_LE); aerror < 0)
 
  499      return_error (
"snd_pcm_hw_params_set_format", aerror, DEVICE_FORMAT);
 
  501    uint rate = *mix_freq;
 
  502    if (
int aerror = snd_pcm_hw_params_set_rate (phandle, hparams, rate, 0); aerror < 0)
 
  503      return_error (
"snd_pcm_hw_params_set_rate", aerror, DEVICE_FREQUENCY);
 
  504    if (rate != *mix_freq)
 
  505      return_error (
"snd_pcm_hw_params_set_rate", -EINVAL, DEVICE_FREQUENCY);
 
  506    PDEBUG (
"SETUP: %s: rate: %d", alsadev_, rate);
 
  508    snd_pcm_uframes_t period_min = 2, period_max = 1048576;
 
  509    snd_pcm_hw_params_get_period_size_min (hparams, &period_min, 
nullptr);
 
  510    snd_pcm_hw_params_get_period_size_max (hparams, &period_max, 
nullptr);
 
  511    const snd_pcm_uframes_t latency_frames = rate * latency_ms / 1000; 
 
  512    snd_pcm_uframes_t period_size = 32; 
 
  513    if (alsadev_ == 
"pulse")            
 
  514      period_size = 
MAX (period_size, 384);
 
  515    while (period_size + 16 <= latency_frames / 3)
 
  517    period_size = 
CLAMP (period_size, period_min, period_max);
 
  518    period_size = 
MIN (period_size, *period_sizep); 
 
  520    if (
int aerror = snd_pcm_hw_params_set_period_size_near (phandle, hparams, &period_size, &dir); aerror < 0)
 
  521      return_error (
"snd_pcm_hw_params_set_period_size_near", aerror, DEVICE_LATENCY);
 
  522    PDEBUG (
"SETUP: %s: period_size: %d (dir=%+d, min=%d max=%d)", alsadev_,
 
  523            period_size, dir, period_min, period_max);
 
  525    const uint want_nperiods = latency_ms == 0 ? 2 : 
CLAMP (latency_frames / period_size, 2, 1023) + 1;
 
  526    uint nperiods = want_nperiods;
 
  527    if (
int aerror = snd_pcm_hw_params_set_periods_near (phandle, hparams, &nperiods, 
nullptr); aerror < 0)
 
  528      return_error (
"snd_pcm_hw_params_set_periods", aerror, DEVICE_LATENCY);
 
  529    PDEBUG (
"SETUP: %s: n_periods: %d (requested: %d)", alsadev_, nperiods, want_nperiods);
 
  530    if (
int aerror = snd_pcm_hw_params (phandle, hparams); aerror < 0)
 
  531      return_error (
"snd_pcm_hw_params", aerror, FILE_OPEN_FAILED);
 
  533    snd_pcm_uframes_t buffer_size_min = 0, buffer_size_max = 0, buffer_size = 0;
 
  534    if (
int aerror = snd_pcm_hw_params_get_buffer_size (hparams, &buffer_size); aerror < 0)
 
  535      return_error (
"snd_pcm_hw_params_get_buffer_size", aerror, DEVICE_BUFFER);
 
  536    if (
int aerror = snd_pcm_hw_params_get_buffer_size_min (hparams, &buffer_size_min); aerror < 0)
 
  537      return_error (
"snd_pcm_hw_params_get_buffer_size_min", aerror, DEVICE_BUFFER);
 
  538    if (
int aerror = snd_pcm_hw_params_get_buffer_size_max (hparams, &buffer_size_max); aerror < 0)
 
  539      return_error (
"snd_pcm_hw_params_get_buffer_size_max", aerror, DEVICE_BUFFER);
 
  540    PDEBUG (
"SETUP: %s: buffer_size: %d (min=%d, max=%d)", alsadev_, buffer_size, buffer_size_min, buffer_size_max);
 
  542    snd_pcm_sw_params_t *sparams = alsa_alloca0 (snd_pcm_sw_params);
 
  543    if (
int aerror = snd_pcm_sw_params_current (phandle, sparams); aerror < 0)
 
  544      return_error (
"snd_pcm_sw_params_current", aerror, FILE_OPEN_FAILED);
 
  545    if (
int aerror = snd_pcm_sw_params_set_start_threshold (phandle, sparams, (buffer_size / period_size) * period_size); aerror < 0)
 
  546      return_error (
"snd_pcm_sw_params_set_start_threshold", aerror, DEVICE_BUFFER);
 
  547    snd_pcm_uframes_t availmin = 0;
 
  548    if (
int aerror = snd_pcm_sw_params_set_avail_min (phandle, sparams, period_size); aerror < 0)
 
  549      return_error (
"snd_pcm_sw_params_set_avail_min", aerror, DEVICE_LATENCY);
 
  550    if (
int aerror = snd_pcm_sw_params_get_avail_min (sparams, &availmin); aerror < 0)
 
  551      return_error (
"snd_pcm_sw_params_get_avail_min", aerror, DEVICE_LATENCY);
 
  552    PDEBUG (
"SETUP: %s: avail_min: %d", alsadev_, availmin);
 
  553    if (
int aerror = snd_pcm_sw_params_set_stop_threshold (phandle, sparams, LONG_MAX); aerror < 0) 
 
  554      return_error (
"snd_pcm_sw_params_set_stop_threshold", aerror, DEVICE_BUFFER);
 
  555    snd_pcm_uframes_t stopthreshold = 0;
 
  556    if (
int aerror = snd_pcm_sw_params_get_stop_threshold (sparams, &stopthreshold); aerror < 0)
 
  557      return_error (
"snd_pcm_sw_params_get_stop_threshold", aerror, DEVICE_BUFFER);
 
  558    PDEBUG (
"SETUP: %s: stop_threshold: %d", alsadev_, stopthreshold);
 
  559    if (
int aerror = snd_pcm_sw_params_set_silence_threshold (phandle, sparams, 0); aerror < 0)   
 
  560      return_error (
"snd_pcm_sw_params_set_silence_threshold", aerror, DEVICE_BUFFER);
 
  561    if (
int aerror = snd_pcm_sw_params_set_silence_size (phandle, sparams, LONG_MAX); aerror < 0) 
 
  562      return_error (
"snd_pcm_sw_params_set_silence_size", aerror, DEVICE_BUFFER);
 
  563    if (
int aerror = snd_pcm_sw_params (phandle, sparams); aerror < 0)
 
  564      return_error (
"snd_pcm_sw_params", aerror, FILE_OPEN_FAILED);
 
  567    *n_periodsp = nperiods;
 
  568    *period_sizep = period_size;
 
  569    PDEBUG (
"SETUP: %s: OPEN: r=%d w=%d n_channels=%d sample_freq=%d nperiods=%u period=%u (%u) bufsz=%u",
 
  570            alsadev_, phandle == read_handle_, phandle == write_handle_,
 
  571            n_channels_, *mix_freq, *n_periodsp, *period_sizep,
 
  572            nperiods * period_size, buffer_size);
 
  579    silence_error_handler++;
 
  580    PDEBUG (
"RETRIGGER: %s: retriggering device (r=%s w=%s)...",
 
  581            alsadev_, !read_handle_ ? 
"<CLOSED>" : snd_pcm_state_name (snd_pcm_state (read_handle_)),
 
  582            !write_handle_ ? 
"<CLOSED>" : snd_pcm_state_name (snd_pcm_state (write_handle_)));
 
  583    snd_pcm_prepare (read_handle_ ? read_handle_ : write_handle_);
 
  586      snd_pcm_drop (read_handle_);
 
  588      snd_pcm_drain (write_handle_); 
 
  590    int aerror = snd_pcm_prepare (read_handle_ ? read_handle_ : write_handle_);
 
  592      printerr (
"ALSA: %s: failed to prepare for io: %s\n", __func__, snd_strerror (-aerror));
 
  596        const size_t needed_zeros = period_size_ / 2; 
 
  597        assert_return (needed_zeros <= AUDIO_BLOCK_FLOAT_ZEROS_SIZE);
 
  599        for (
size_t i = 0; i < n_periods_; i++)
 
  603              n = snd_pcm_writei (write_handle_, zeros, period_size_);
 
  604            while (n == -EAGAIN); 
 
  608    silence_error_handler--;
 
  611  pcm_check_io (int64 *timeoutp)
 override 
  615        snd_pcm_state_t 
ws = SND_PCM_STATE_DISCONNECTED, rs = SND_PCM_STATE_DISCONNECTED;
 
  616        snd_pcm_status_t *
stat = alsa_alloca0 (snd_pcm_status);
 
  619            snd_pcm_status (read_handle_, stat);
 
  620            rs = snd_pcm_state (read_handle_);
 
  622        int rn = snd_pcm_status_get_avail (stat);
 
  625            snd_pcm_status (write_handle_, stat);
 
  626            ws = snd_pcm_state (write_handle_);
 
  628        int wn = snd_pcm_status_get_avail (stat);
 
  629        printerr (
"ALSA: check_io: read=%4u/%4u (%s) write=%4u/%4u (%s) block=%u: %s\n",
 
  630                  rn, period_size_ * n_periods_, snd_pcm_state_name (rs),
 
  631                  wn, period_size_ * n_periods_, snd_pcm_state_name (ws),
 
  632                  period_size_, rn >= period_size_ ? 
"true" : 
"false");
 
  635    int n_frames_avail = snd_pcm_avail_update (read_handle_ ? read_handle_ : write_handle_);
 
  636    if (n_frames_avail < 0 ||   
 
  637        (n_frames_avail == 0 && 
 
  638         snd_pcm_state (read_handle_ ? read_handle_ : write_handle_) != SND_PCM_STATE_RUNNING))
 
  640    if (n_frames_avail < period_size_)
 
  643        snd_pcm_hwsync (read_handle_ ? read_handle_ : write_handle_);
 
  644        n_frames_avail = snd_pcm_avail_update (read_handle_ ? read_handle_ : write_handle_);
 
  645        n_frames_avail = 
MAX (n_frames_avail, 0);
 
  648    if (n_frames_avail >= period_size_)
 
  651    const uint diff_frames = period_size_ - n_frames_avail;
 
  652    *timeoutp = diff_frames * 1000 / mix_freq_;
 
  656  pcm_latency (uint *rlatency, uint *wlatency)
 const override 
  658    snd_pcm_sframes_t rdelay, wdelay;
 
  659    if (!read_handle_ || snd_pcm_delay (read_handle_, &rdelay) < 0)
 
  661    if (!write_handle_ || snd_pcm_delay (write_handle_, &wdelay) < 0)
 
  663    const int buffer_length = n_periods_ * period_size_; 
 
  665    *rlatency = 
CLAMP (rdelay, 0, buffer_length);
 
  666    *wlatency = 
CLAMP (wdelay, 0, buffer_length);
 
  669  pcm_read (
size_t n, 
float *values)
 override 
  672    float *dest = values;
 
  673    size_t n_left = period_size_;
 
  674    const size_t n_values = n_left * n_channels_;
 
  676    read_write_count_ += 1;
 
  679        ssize_t n_frames = snd_pcm_readi (read_handle_, period_buffer_, n_left);
 
  682            PDEBUG (
"READ: %s: read() error: %s", alsadev_, snd_strerror (n_frames));
 
  683            silence_error_handler++;
 
  684            snd_pcm_prepare (read_handle_);     
 
  685            silence_error_handler--;
 
  687            const size_t frame_size = n_channels_ * 
sizeof (period_buffer_[0]);
 
  688            memset (period_buffer_, 0, n_frames * frame_size);
 
  692            convert_samples (n_frames * n_channels_, 
const_cast<const int16_t*
> (period_buffer_), dest, __BYTE_ORDER__);
 
  693            dest += n_frames * n_channels_;
 
  702  pcm_write (
size_t n, 
const float *values)
 override 
  705    if (read_handle_ && read_write_count_ < 1)
 
  707        silence_error_handler++; 
 
  708        snd_pcm_forward (read_handle_, period_size_);
 
  709        silence_error_handler--;
 
  710        read_write_count_ += 1;
 
  712    read_write_count_ -= 1;
 
  713    const float *floats = values;
 
  714    size_t n_left = period_size_;       
 
  717        convert_clip_samples (n_left * n_channels_, floats, period_buffer_, __BYTE_ORDER__);
 
  718        floats += n_left * n_channels_;
 
  720        n = snd_pcm_writei (write_handle_, period_buffer_, n_left);
 
  723            PDEBUG (
"WRITE: %s: write() error: %s", alsadev_, snd_strerror (n));
 
  724            silence_error_handler++;
 
  725            snd_pcm_prepare (write_handle_);    
 
  726            silence_error_handler--;
 
  734static const String alsa_pcm_driverid = PcmDriver::register_driver (
"alsa",
 
  735                                                                    AlsaPcmDriver::create,
 
  736                                                                    [] (Driver::EntryVec &entries) {
 
  737                                                                      list_alsa_drivers (entries);
 
  741class AlsaSeqMidiDriver : 
public MidiDriver {
 
  742  using PortSubscribe = 
std::unique_ptr<snd_seq_port_subscribe_t, 
decltype (&snd_seq_port_subscribe_free)>;
 
  743  snd_seq_t        *seq_ = 
nullptr;
 
  744  int               queue_ = -1, iport_ = -1, total_fds_ = 0;
 
  745  snd_midi_event_t *evparser_ = 
nullptr;
 
  747  bool              mdebug_ = 
false;
 
  749  make_port_subscribe (snd_seq_port_subscribe_t *other = 
nullptr)
 
  751    snd_seq_port_subscribe_t *subs = 
nullptr;
 
  752    snd_seq_port_subscribe_malloc (&subs);
 
  754      return { 
nullptr, snd_seq_port_subscribe_free };
 
  756      snd_seq_port_subscribe_copy (subs, other);
 
  757    return { subs, snd_seq_port_subscribe_free };
 
  761  create (
const String &devid)
 
  767  AlsaSeqMidiDriver (
const String &driver, 
const String &devid) :
 
  768    MidiDriver (driver, devid), subs_ { nullptr, nullptr }
 
  782      aerror = snd_seq_open (&seq_, 
"default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK);
 
  784      aerror = snd_seq_set_client_name (seq_, myname.
c_str());
 
  786      queue_ = snd_seq_alloc_named_queue (seq_, (myname + 
" SeqQueue").c_str());
 
  787    snd_seq_queue_tempo_t *qtempo = alsa_alloca0 (snd_seq_queue_tempo);
 
  788    snd_seq_queue_tempo_set_tempo (qtempo, 60 * 1000000 / 480); 
 
  789    snd_seq_queue_tempo_set_ppq (qtempo, 1920); 
 
  791      aerror = snd_seq_set_queue_tempo (seq_, queue_, qtempo);
 
  793      snd_seq_start_queue (seq_, queue_, 
nullptr);
 
  795      aerror = snd_seq_drain_output (seq_);
 
  797      MDEBUG (
"SndSeq: %s: initialization failed: %s", myname, snd_strerror (-aerror));
 
  799      MDEBUG (
"SndSeq: %s: queue started: %.5f", myname, queue_now());
 
  800    return ase_error_from_errno (-aerror, Error::FILE_OPEN_FAILED);
 
  806    auto is_identifier_char = [] (
int ch) {
 
  807      return ( (ch >= 
'A' && ch <= 
'Z') ||
 
  808               (ch >= 
'a' && ch <= 
'z') ||
 
  809               (ch >= 
'0' && ch <= 
'9') ||
 
  810               ch == 
'_' || ch == 
'$' );
 
  812    for (
size_t i = 0; i < 
string.size() && 
string[i]; ++i)
 
  813      if (is_identifier_char (
string[i]))
 
  814        normalized += 
string[i];
 
  815      else if (normalized.
size() && normalized[normalized.
size() - 1] != 
'-')
 
  820  make_devid (
int card, uint type, 
const std::string &clientname, 
int client, uint caps)
 
  822    if (0 == (type & SND_SEQ_PORT_TYPE_MIDI_GENERIC))
 
  825    if ((type & SND_SEQ_PORT_TYPE_SYNTHESIZER) && (type & SND_SEQ_PORT_TYPE_HARDWARE))
 
  827    else if ((type & SND_SEQ_PORT_TYPE_SYNTHESIZER) && (type & SND_SEQ_PORT_TYPE_SOFTWARE))
 
  828      devid = 
"softsynth:";
 
  829    else if (type & SND_SEQ_PORT_TYPE_SYNTHESIZER)
 
  831    else if (type & SND_SEQ_PORT_TYPE_APPLICATION)
 
  833    else if (type & SND_SEQ_PORT_TYPE_HARDWARE)
 
  835    else if (type & SND_SEQ_PORT_TYPE_SOFTWARE)
 
  842        snd_ctl_t *chandle = 
nullptr;
 
  844        if (snd_ctl_open (&chandle, sbuf.c_str(), SND_CTL_NONBLOCK) >= 0 && chandle)
 
  846            snd_ctl_card_info_t *cinfo = alsa_alloca0 (snd_ctl_card_info);
 
  847            if (snd_ctl_card_info (chandle, cinfo) >= 0)
 
  849                const char *cid = snd_ctl_card_info_get_id (cinfo);
 
  853            snd_ctl_close (chandle);
 
  858    else if (!clientname.
empty())
 
  866  enumerate (Driver::EntryVec *entries, snd_seq_port_info_t *sinfo = 
nullptr, 
const std::string &selector = 
"", uint need_caps = 0)
 
  869    snd_seq_client_info_t *cinfo = alsa_alloca0 (snd_seq_client_info);
 
  870    snd_seq_client_info_set_client (cinfo, -1);
 
  871    while (snd_seq_query_next_client (seq_, cinfo) == 0)
 
  873        const int client = snd_seq_client_info_get_client (cinfo);
 
  876        snd_seq_port_info_t *pinfo = alsa_alloca0 (snd_seq_port_info);
 
  877        snd_seq_port_info_set_client (pinfo, client);
 
  878        snd_seq_port_info_set_port (pinfo, -1);
 
  879        while (snd_seq_query_next_port (seq_, pinfo) == 0)
 
  881            const uint tmask = SND_SEQ_PORT_TYPE_MIDI_GENERIC |
 
  882                               SND_SEQ_PORT_TYPE_SYNTHESIZER |
 
  883                               SND_SEQ_PORT_TYPE_APPLICATION;
 
  884            const int type = snd_seq_port_info_get_type (pinfo);
 
  885            if (0 == (type & tmask))
 
  887            const uint cmask = SND_SEQ_PORT_CAP_READ |
 
  888                               SND_SEQ_PORT_CAP_WRITE |
 
  889                               SND_SEQ_PORT_CAP_DUPLEX;
 
  890            const int caps = snd_seq_port_info_get_capability (pinfo);
 
  891            if (0 == (caps & cmask) || need_caps != (need_caps & caps))
 
  893            const int card = snd_seq_client_info_get_card (cinfo);
 
  894            const std::string clientname = snd_seq_client_info_get_name (cinfo);
 
  895            std::string devportid = make_devid (card, type, clientname, client, caps);
 
  896            if (devportid.
empty())
 
  898            const int cport = snd_seq_port_info_get_port (pinfo);
 
  906                    if (snd_card_get_longname (card, &str) == 0 && str)
 
  910                    if (snd_card_get_name (card, &str) == 0 && str)
 
  915                const bool is_usb = longname.
find (
" at usb-") != std::string::npos;
 
  916                const bool is_kern = snd_seq_client_info_get_type (cinfo) == SND_SEQ_KERNEL_CLIENT;
 
  917                const bool is_thru = is_kern && clientname == 
"Midi Through";
 
  920                entry.devid = devportid;
 
  921                entry.device_name = 
string_capitalize (snd_seq_port_info_get_name (pinfo), 1, 
false);
 
  922                if (!string_startswith (entry.device_name, devname))
 
  923                  entry.device_name = devname + 
" " + entry.device_name;
 
  924                if (!cardname.
empty())
 
  925                  entry.device_name += 
" - " + cardname;
 
  926                if (caps & SND_SEQ_PORT_CAP_DUPLEX)
 
  927                  entry.capabilities = 
"Full-Duplex MIDI";
 
  928                else if ((caps & SND_SEQ_PORT_CAP_READ) && (caps & SND_SEQ_PORT_CAP_WRITE))
 
  929                  entry.capabilities = 
"MIDI In-Out";
 
  930                else if (caps & SND_SEQ_PORT_CAP_READ)
 
  931                  entry.capabilities = 
"MIDI Output";
 
  932                else if (caps & SND_SEQ_PORT_CAP_WRITE)
 
  933                  entry.capabilities = 
"MIDI Input";
 
  934                if (!string_startswith (longname, cardname + 
" at "))
 
  935                  entry.device_info = longname;
 
  936                if (type & SND_SEQ_PORT_TYPE_APPLICATION || !is_kern)
 
  937                  entry.notice = 
"Note: MIDI device is provided by an application";
 
  938                entry.readonly = (caps & SND_SEQ_PORT_CAP_READ) && !(caps & SND_SEQ_PORT_CAP_WRITE);
 
  939                entry.writeonly = (caps & SND_SEQ_PORT_CAP_WRITE) && !(caps & SND_SEQ_PORT_CAP_READ);
 
  940                entry.priority = is_thru ? Driver::MIDI_THRU :
 
  941                                 is_usb ? Driver::ALSA_USB :
 
  942                                 is_kern ? Driver::ALSA_KERN :
 
  944                entry.priority += Driver::WCARD * 
MAX (0, card);
 
  945                entry.priority += Driver::WDEV * client; 
 
  946                entry.priority += Driver::WSUB * cport;
 
  947                entries->push_back (entry);
 
  948                MDEBUG (
"DISCOVER: %s - %s", entry.devid, entry.device_name);
 
  950            const bool match = selector == devportid;
 
  953                snd_seq_port_info_copy (sinfo, pinfo);
 
  961  list_drivers (Driver::EntryVec &entries)
 
  963    AlsaSeqMidiDriver smd (
"?", 
"");
 
  964    if (smd.initialize (
program_alias() + 
" Probing") == Error::NONE)
 
  965      smd.enumerate (&entries);
 
  968  open (IODir iodir)
 override 
  975    PortSubscribe psub = make_port_subscribe();
 
  978    Error error = seq_ ? Error::NONE : initialize (myname);
 
  979    if (error != Error::NONE)
 
  983    const bool require_readable = iodir == READONLY || iodir == READWRITE;
 
  984    const bool require_writable = iodir == WRITEONLY || iodir == READWRITE;
 
  985    const uint caps = require_writable * (SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ) +
 
  986                      require_readable * (SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE);
 
  987    snd_seq_port_info_t *pinfo = alsa_alloca0 (snd_seq_port_info);
 
  988    const bool match_devid = enumerate (
nullptr, pinfo, devid_, caps);
 
  990      return Error::DEVICE_NOT_AVAILABLE;
 
  991    flags_ |= Flags::READABLE * require_readable;
 
  992    flags_ |= Flags::WRITABLE * require_writable;
 
  994    snd_seq_port_info_t *minfo = alsa_alloca0 (snd_seq_port_info);
 
  995    snd_seq_port_info_set_port (minfo, 0); 
 
  996    snd_seq_port_info_set_port_specified (minfo, 
true);
 
  997    snd_seq_port_info_set_name (minfo, (myname + 
" LSP-0").c_str()); 
 
  998    snd_seq_port_info_set_type (minfo, SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION);
 
  999    const int intracaps = SND_SEQ_PORT_CAP_NO_EXPORT | SND_SEQ_PORT_CAP_WRITE;
 
 1000    snd_seq_port_info_set_capability (minfo, intracaps);
 
 1001    snd_seq_port_info_set_midi_channels (minfo, 16);
 
 1002    snd_seq_port_info_set_timestamping (minfo, 
true);
 
 1003    snd_seq_port_info_set_timestamp_real (minfo, 
true);
 
 1004    snd_seq_port_info_set_timestamp_queue (minfo, queue_);
 
 1005    int aerror = snd_seq_create_port (seq_, minfo);
 
 1008        iport_ = snd_seq_port_info_get_port (minfo);
 
 1013    snd_seq_addr_t qaddr = {};
 
 1014    qaddr.client = snd_seq_port_info_get_client (pinfo);
 
 1015    qaddr.port = snd_seq_port_info_get_port (pinfo);
 
 1016    snd_seq_port_subscribe_set_sender (&*psub, &qaddr);
 
 1017    qaddr.client = snd_seq_client_id (seq_);
 
 1018    qaddr.port = iport_; 
 
 1019    snd_seq_port_subscribe_set_dest (&*psub, &qaddr);
 
 1020    snd_seq_port_subscribe_set_queue (&*psub, queue_);
 
 1021    snd_seq_port_subscribe_set_time_update (&*psub, 
true);
 
 1022    snd_seq_port_subscribe_set_time_real (&*psub, 
true);
 
 1024      aerror = snd_seq_subscribe_port (seq_, &*psub);
 
 1027        subs_ = make_port_subscribe (&*psub);
 
 1033      snd_seq_drain_output (seq_);
 
 1035      aerror = snd_midi_event_new (1024, &evparser_);
 
 1038        snd_midi_event_init (evparser_);
 
 1039        snd_midi_event_no_status (evparser_, 
true);
 
 1045        total_fds_ = snd_seq_poll_descriptors_count (seq_, POLLIN);
 
 1048            struct pollfd *pfds = (
struct pollfd*) alloca (total_fds_ * 
sizeof (
struct pollfd));
 
 1049            if (snd_seq_poll_descriptors (seq_, pfds, total_fds_, POLLIN) > 0)
 
 1052                AseTrans *trans = ase_trans_open ();
 
 1053                static_assert (
sizeof (
struct pollfd) == 
sizeof (GPollFD));
 
 1054                AseJob *job = ase_job_add_poll (pollin_func, (
void*) 
this, pollfree_func, total_fds_, (
const GPollFD*) pfds);
 
 1055                ase_trans_add (trans, job);
 
 1056                ase_trans_commit (trans);
 
 1062        flags_ |= Flags::OPENED;
 
 1064    error = !aerror ? Error::NONE : ase_error_from_errno (-aerror, Error::FILE_OPEN_FAILED);
 
 1065    MDEBUG (
"SndSeq: %s: opening readable=%d writable=%d: %s", devid_, readable(), writable(), ase_error_blurb (error));
 
 1066    if (error != Error::NONE)
 
 1079        AseTrans *trans = ase_trans_open ();
 
 1080        AseJob *job = ase_job_remove_poll (pollin_func, (
void*) 
this);
 
 1081        ase_trans_add (trans, job);
 
 1082        ase_trans_commit (trans);
 
 1087        snd_midi_event_free (evparser_);
 
 1088        evparser_ = 
nullptr;
 
 1092        snd_seq_unsubscribe_port (seq_, &*subs_);
 
 1097        snd_seq_delete_port (seq_, iport_);
 
 1102        snd_seq_free_queue (seq_, queue_);
 
 1107        snd_seq_close (seq_);
 
 1116    MDEBUG (
"SndSeq: %s: CLOSE: r=%d w=%d", devid_, readable(), writable());
 
 1117    flags_ &= ~size_t (Flags::OPENED | Flags::READABLE | Flags::WRITABLE);
 
 1122  pollfree_func (
void *data)
 
 1130    union { 
uint64_t u64[16]; 
char c[1]; } stbuf = {};
 
 1131    assert_return (snd_seq_queue_status_sizeof() <= 
sizeof (stbuf), NAN);
 
 1132    snd_seq_queue_status_t *
stat = (snd_seq_queue_status_t*) &stbuf;
 
 1133    int aerror = snd_seq_get_queue_status (seq_, queue_, stat);
 
 1136        const snd_seq_real_time_t *rt = snd_seq_queue_status_get_real_time (stat);
 
 1137        return rt->tv_sec + 1e-9 * rt->tv_nsec;
 
 1142  has_events ()
 override 
 1145    const bool pull_fifo = 
true;
 
 1146    return snd_seq_event_input_pending (seq_, pull_fifo) > 0;
 
 1149  fetch_events (MidiEventOutput &estream, 
double samplerate)
 override 
 1152    const size_t old_size = estream.size();
 
 1154    snd_seq_event_t *ev = 
nullptr;
 
 1155    const double now = queue_now();
 
 1156    const auto mkid = [] (
uint note, 
uint channel) {
 
 1157      return (channel + 1) * 128 + note;
 
 1159    bool must_sort = 
false;
 
 1160    const auto add = [&] (MidiEventOutput &estream, 
const snd_seq_event_t *ev, 
const MidiEvent &event) {
 
 1161      const double t = ev->time.time.tv_sec + 1e-9 * ev->time.time.tv_nsec;
 
 1162      const double diff = t - now;
 
 1163      int64_t frames = diff * samplerate;
 
 1164      if (event.type == event.NOTE_OFF)
 
 1166          const auto last_frame = estream.last_frame();
 
 1167          frames = 
std::max (frames, last_frame);
 
 1170      must_sort |= estream.append_unsorted (frame_delay, event);
 
 1173    while (r = snd_seq_event_input (seq_, &ev), r >= 0)
 
 1176        case SND_SEQ_EVENT_NOTEON:
 
 1178               make_note_on (ev->data.note.channel, ev->data.note.note,
 
 1179                             ev->data.note.velocity * (1.0 / 127.0), 0,
 
 1180                             mkid (ev->data.note.note, ev->data.note.channel)));
 
 1182        case SND_SEQ_EVENT_NOTEOFF:
 
 1184               make_note_off (ev->data.note.channel, ev->data.note.note,
 
 1185                              ev->data.note.velocity * (1.0 / 127.0), 0,
 
 1186                              mkid (ev->data.note.note, ev->data.note.channel)));
 
 1188        case SND_SEQ_EVENT_KEYPRESS:
 
 1190               make_aftertouch (ev->data.note.channel, ev->data.note.note,
 
 1191                                ev->data.note.velocity * (1.0 / 127.0), 0,
 
 1192                                mkid (ev->data.note.note, ev->data.note.channel)));
 
 1194        case SND_SEQ_EVENT_CONTROLLER:
 
 1196               make_control8 (ev->data.control.channel, ev->data.control.param,
 
 1197                              ev->data.control.value));
 
 1199        case SND_SEQ_EVENT_PGMCHANGE:
 
 1201               make_program (ev->data.control.channel, ev->data.control.value));
 
 1203        case SND_SEQ_EVENT_CHANPRESS:
 
 1205               make_pressure (ev->data.control.channel, ev->data.control.value * (1.0 / 127.0)));
 
 1207        case SND_SEQ_EVENT_PITCHBEND:
 
 1209               make_pitch_bend (ev->data.control.channel,
 
 1210                                ev->data.control.value *
 
 1211                                (ev->data.control.value < 0 ? 1.0 / 8192.0 : 1.0 / 8191.0)));
 
 1213        case SND_SEQ_EVENT_SYSEX:
 
 1214          MDEBUG (
"%+4d ch=%-2u SYSEX: %s",
 
 1215                  int (samplerate * (ev->time.time.tv_sec + 1e-9 * ev->time.time.tv_nsec - now)),
 
 1216                  ev->data.control.channel, hex_str (ev->data.ext.len, (
const uint8*) ev->data.ext.ptr));
 
 1218        case SND_SEQ_EVENT_CLOCK:
 
 1221        case SND_SEQ_EVENT_CONTROL14:
 
 1222        case SND_SEQ_EVENT_NONREGPARAM:
 
 1223        case SND_SEQ_EVENT_REGPARAM:
 
 1224        case SND_SEQ_EVENT_NOTE:  
 
 1226          MDEBUG (
"%+4d ch=%-2u SND_SEQ_EVENT_... %u",
 
 1227                  int (samplerate * (ev->time.time.tv_sec + 1e-9 * ev->time.time.tv_nsec - now)),
 
 1228                  ev->data.control.channel, ev->type);
 
 1232    if (r < 0 && r != -EAGAIN) 
 
 1233      MDEBUG (
"SndSeq: %s: snd_seq_event_input: %s", devid_, snd_strerror (r));
 
 1235      for (
size_t i = old_size; i < estream.
size(); i++)
 
 1236        MDEBUG (
"%s", (estream.begin() + i)->to_string());
 
 1238      estream.ensure_order();
 
 1239    return estream.size() - old_size;
 
 1243static const String alsa_seqmidi_driverid = MidiDriver::register_driver (
"alsa",
 
 1244                                                                         AlsaSeqMidiDriver::create,
 
 1245                                                                         AlsaSeqMidiDriver::list_drivers);
 
 1251  for (
uint i = 0; i < 16 && i < len; i++)
 
#define ASE_UNLIKELY(expr)
Compiler hint to optimize for expr evaluating to false.
 
#define assert_return(expr,...)
Return from the current function if expr is unmet and issue an assertion warning.
 
#define MIN(a, b)
Yield minimum of a and b.
 
#define CLAMP(v, mi, ma)
Yield v clamped to [mi … ma].
 
#define MAX(a, b)
Yield maximum of a and b.
 
String normalize(const String &path)
Convert path to normal form.
 
The Anklang C++ API namespace.
 
std::string string_format(const char *format, const Args &...args) __attribute__((__format__(__printf__
Format a string similar to sprintf(3) with support for std::string and std::ostringstream convertible...
 
bool debug_key_enabled(const char *conditional)
Check if conditional is enabled by $ASE_DEBUG.
 
String string_join(const String &junctor, const StringS &strvec)
 
int16_t int16
A 16-bit signed integer.
 
float const_float_zeros[AUDIO_BLOCK_FLOAT_ZEROS_SIZE]
Block of const floats allof value 0.
 
uint8_t uint8
An 8-bit unsigned integer.
 
bool string_option_check(const String &optionlist, const String &feature)
Check if an option is set/unset in an options list string.
 
String string_capitalize(const String &str, size_t maxn, bool rest_tolower)
Capitalize words, so the first letter is upper case, the rest lower case.
 
Error
Enum representing Error states.
 
String string_from_int(int64 value)
Convert a 64bit signed integer into a string.
 
StringS string_split_any(const String &string, const String &splitchars, size_t maxn)
 
String program_alias()
Retrieve the program name as used for logging or debug messages.
 
std::string String
Convenience alias for std::string.
 
uint32_t uint
Provide 'uint' as convenience type.
 
String string_from_type(Type value)
Create a string from a templated argument value, such as bool, int, double.
 
bool string_startswith(const String &string, const String &fragment)
Returns whether string starts with fragment.