/ source / audiolib / src / multivoc.cpp
multivoc.cpp
   1  /*
   2  Copyright (C) 1994-1995 Apogee Software, Ltd.
   3  Copyright (C) 2015 EDuke32 developers
   4  Copyright (C) 2015 Voidpoint, LLC
   5  
   6  This program is free software; you can redistribute it and/or
   7  modify it under the terms of the GNU General Public License
   8  as published by the Free Software Foundation; either version 2
   9  of the License, or (at your option) any later version.
  10  
  11  This program is distributed in the hope that it will be useful,
  12  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14  
  15  See the GNU General Public License for more details.
  16  
  17  You should have received a copy of the GNU General Public License
  18  along with this program; if not, write to the Free Software
  19  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  20  
  21  */
  22  /**********************************************************************
  23     module: MULTIVOC.C
  24  
  25     author: James R. Dose
  26     date:   December 20, 1993
  27  
  28     Routines to provide multichannel digitized sound playback for
  29     Sound Blaster compatible sound cards.
  30  
  31     (c) Copyright 1993 James R. Dose.  All Rights Reserved.
  32  **********************************************************************/
  33  
  34  #include "multivoc.h"
  35  
  36  #include "_multivc.h"
  37  #include "baselayer.h"
  38  #include "compat.h"
  39  #include "drivers.h"
  40  #include "fx_man.h"
  41  #include "libasync_config.h"
  42  #include "linklist.h"
  43  #include "osd.h"
  44  #include "pitch.h"
  45  #include "pragmas.h"
  46  
  47  #ifdef HAVE_XMP
  48  # define BUILDING_STATIC
  49  # include "libxmp-lite/xmp.h"
  50  
  51  int MV_XMPInterpolation = XMP_INTERP_NEAREST;
  52  #endif
  53  
  54  
  55  static void MV_StopVoice(VoiceNode *voice, bool useCallBack = true);
  56  static void MV_ServiceVoc(void);
  57  
  58  static VoiceNode *MV_GetVoice(int handle);
  59  
  60  static int MV_ReverbLevel;
  61  static int MV_ReverbDelay;
  62  static fix16_t MV_ReverbVolume;
  63  
  64  Pan MV_PanTable[MV_NUMPANPOSITIONS][MV_MAXVOLUME + 1];
  65  
  66  int MV_Installed;
  67  
  68  int MV_BufferSize = MV_MIXBUFFERSIZE;
  69  static int MV_BufferLength;
  70  
  71  static int MV_NumberOfBuffers = MV_NUMBEROFBUFFERS;
  72  
  73  int MV_MaxVoices = 1;
  74  int MV_Channels = 1;
  75  int MV_MixRate;
  76  void *MV_InitDataPtr;
  77  
  78  int MV_LazyAlloc = true;
  79  
  80  #ifdef ASS_REVERSESTEREO
  81  static int MV_ReverseStereo;
  82  #endif
  83  
  84  static int MV_BufferEmpty[MV_NUMBEROFBUFFERS];
  85  char *MV_MixBuffer[(MV_NUMBEROFBUFFERS << 1) + 1];
  86  
  87  VoiceNode *MV_Voices;
  88  VoiceNode  VoiceList;
  89  VoiceNode  VoicePool;
  90  
  91  static int MV_MixPage;
  92  
  93  static void (*MV_CallBackFunc)(intptr_t);
  94  
  95  char *MV_MixDestination;
  96  int MV_SampleSize = 1;
  97  int MV_RightChannelOffset;
  98  
  99  int MV_ErrorCode = MV_NotInstalled;
 100  
 101  fix16_t MV_GlobalVolume = fix16_one;
 102  fix16_t MV_VolumeSmoothFactor = fix16_one;
 103  
 104  thread_local int MV_Locked;
 105  char *MV_MusicBuffer;
 106  static void (*MV_MusicCallback)(void);
 107  
 108  static VoiceNode **MV_Handles;
 109  
 110  static bool MV_Mix(VoiceNode * const voice, int const buffer)
 111  {
 112      if (voice->task.valid())
 113      {
 114          if (!voice->task.ready())
 115              return true;
 116  
 117          auto result = voice->task.get();
 118  
 119          if (result != MV_Ok)
 120          {
 121              LOG_F(ERROR, "Error playing sound 0x%08" PRIxPTR ": %s", voice->callbackval, MV_ErrorString(result));
 122              return false;
 123          }
 124      }
 125  
 126      if (voice->length == 0 && voice->GetSound(voice) != KeepPlaying)
 127          return false;
 128  
 129      fix16_t const gv = MV_GlobalVolume;
 130  
 131      if (voice->priority == FX_MUSIC_PRIORITY)
 132          MV_GlobalVolume = fix16_one;
 133  
 134      int            length = MV_MIXBUFFERSIZE;
 135      uint32_t       bufsiz = voice->FixedPointBufferSize;
 136      uint32_t const rate   = voice->RateScale;
 137  
 138      MV_MixDestination = MV_MixBuffer[buffer];
 139  
 140      // Add this voice to the mix
 141      do
 142      {
 143          int            mixlen   = length;
 144          uint32_t const position = voice->position;
 145          uint32_t const voclen   = voice->length;
 146  
 147          // Check if the last sample in this buffer would be
 148          // beyond the length of the sample block
 149          if ((position + bufsiz) >= voclen)
 150          {
 151              if (position >= voclen - voice->channels)
 152              {
 153                  if (voice->GetSound(voice) != KeepPlaying)
 154                  {
 155                      MV_GlobalVolume = gv;
 156                      return false;
 157                  }
 158  
 159                  break;
 160              }
 161  
 162              mixlen = (voclen - position + rate - voice->channels) / rate;
 163          }
 164  
 165          voice->position = voice->mix(voice, mixlen);
 166          length -= mixlen;
 167  
 168          if (voice->position >= voclen - voice->channels)
 169          {
 170              // Get the next block of sound
 171              if (voice->GetSound(voice) != KeepPlaying)
 172              {
 173                  MV_GlobalVolume = gv;
 174                  return false;
 175              }
 176  
 177              // Get the position of the last sample in the buffer
 178              if (length > (voice->channels - 1))
 179                  bufsiz = voice->RateScale * (length - voice->channels);
 180          }
 181      } while (length > 0);
 182  
 183      MV_GlobalVolume = gv;
 184      return true;
 185  }
 186  
 187  void MV_PlayVoice(VoiceNode *voice)
 188  {
 189      MV_Lock();
 190      LL::SortedInsert(&VoiceList, voice, &VoiceNode::priority);
 191      voice->PannedVolume = voice->GoalVolume;
 192      voice->Paused.store(false, std::memory_order_release);
 193      MV_Unlock();
 194  }
 195  
 196  static void MV_FreeHandle(VoiceNode* voice)
 197  {
 198      if (voice->handle < MV_MINVOICEHANDLE)
 199          return;
 200  
 201      MV_Handles[voice->handle - MV_MINVOICEHANDLE] = nullptr;
 202      voice->handle = 0;
 203      voice->length = 0;
 204      voice->sound = nullptr;
 205      voice->wavetype = FMT_UNKNOWN;
 206      LL::Move(voice, &VoicePool);
 207  }
 208  
 209  static void MV_CleanupVoice(VoiceNode* voice, bool useCallBack = true)
 210  {
 211      if (useCallBack && MV_CallBackFunc)
 212          MV_CallBackFunc(voice->callbackval);
 213  
 214      switch (voice->wavetype)
 215      {
 216  #ifdef HAVE_VORBIS
 217          case FMT_VORBIS: MV_ReleaseVorbisVoice(voice); break;
 218  #endif
 219  #ifdef HAVE_FLAC
 220          case FMT_FLAC:   MV_ReleaseFLACVoice(voice); break;
 221  #endif
 222          case FMT_XA:     MV_ReleaseXAVoice(voice); break;
 223  #ifdef HAVE_XMP
 224          case FMT_XMP:    MV_ReleaseXMPVoice(voice); break;
 225  #endif
 226          default:
 227              // these are in the default case of this switch instead of down below because the functions above only zero them if MV_LazyAlloc is false
 228              voice->rawdataptr = nullptr;
 229              voice->rawdatasiz = 0;
 230              break;
 231      }
 232  }
 233  
 234  void MV_StopVoice(VoiceNode *voice, bool useCallBack)
 235  {
 236      MV_CleanupVoice(voice, useCallBack);
 237      MV_Lock();
 238      // move the voice from the play list to the free list
 239      MV_FreeHandle(voice);
 240      MV_Unlock();
 241  }
 242  
 243  /*---------------------------------------------------------------------
 244     JBF: no synchronisation happens inside MV_ServiceVoc nor the
 245          supporting functions it calls. This would cause a deadlock
 246          between the mixer thread in the driver vs the nested
 247          locking in the user-space functions of MultiVoc. The call
 248          to MV_ServiceVoc is synchronised in the driver.
 249  ---------------------------------------------------------------------*/
 250  static void MV_ServiceVoc(void)
 251  {
 252      // Toggle which buffer we'll mix next
 253      ++MV_MixPage;
 254      MV_MixPage &= MV_NumberOfBuffers-1;
 255  
 256      if (MV_ReverbLevel == 0)
 257      {
 258          if (!MV_BufferEmpty[MV_MixPage])
 259          {
 260              Bmemset(MV_MixBuffer[MV_MixPage], 0, MV_BufferSize);
 261              MV_BufferEmpty[MV_MixPage] = TRUE;
 262          }
 263      }
 264      else
 265      {
 266          char const *const __restrict end    = MV_MixBuffer[0] + MV_BufferLength;
 267          char *            __restrict dest   = MV_MixBuffer[MV_MixPage];
 268          char const *      __restrict source = MV_MixBuffer[MV_MixPage] - MV_ReverbDelay;
 269  
 270          if (source < MV_MixBuffer[0])
 271              source += MV_BufferLength;
 272  
 273          int length = MV_BufferSize;
 274  
 275          do
 276          {
 277              int const count = (source + length > end) ? (end - source) : length;
 278  
 279              MV_Reverb<int16_t>(source, dest, MV_ReverbVolume, count >> 1);
 280  
 281              // if we go through the loop again, it means that we've wrapped around the buffer
 282              source  = MV_MixBuffer[0];
 283              dest   += count;
 284              length -= count;
 285          } while (length > 0);
 286      }
 287  
 288      VoiceNode *MusicVoice = nullptr;
 289  
 290      if (VoiceList.next && VoiceList.next != &VoiceList)
 291      {
 292          auto voice = VoiceList.next;
 293          VoiceNode *next;
 294  
 295          do
 296          {
 297              next = voice->next;
 298  
 299              if (voice->Paused.load(std::memory_order_acquire))
 300                  continue;
 301  
 302              if (voice->priority == FX_MUSIC_PRIORITY)
 303              {
 304                  MusicVoice = voice;
 305                  continue;
 306              }
 307  
 308              MV_BufferEmpty[ MV_MixPage ] = FALSE;
 309  
 310              // Is this voice done?
 311              if (!MV_Mix(voice, MV_MixPage))
 312              {
 313                  MV_CleanupVoice(voice);
 314                  MV_FreeHandle(voice);
 315              }
 316          }
 317          while ((voice = next) != &VoiceList);
 318      }
 319  
 320      Bmemcpy(MV_MixBuffer[MV_MixPage+MV_NumberOfBuffers], MV_MixBuffer[MV_MixPage], MV_BufferSize);
 321  
 322      if (MV_MusicCallback)
 323      {
 324          MV_MusicCallback();
 325          int16_t * __restrict source = (int16_t*)MV_MusicBuffer;
 326          int16_t * __restrict dest = (int16_t*)MV_MixBuffer[MV_MixPage+MV_NumberOfBuffers];
 327          for (int32_t i = 0; i < MV_BufferSize>>1; i++, dest++)
 328              *dest = clamp(*dest + *source++,INT16_MIN, INT16_MAX);
 329      }
 330  
 331      if (MusicVoice && !MV_Mix(MusicVoice, MV_MixPage + MV_NumberOfBuffers))
 332      {
 333          MV_CleanupVoice(MusicVoice);
 334          MV_FreeHandle(MusicVoice);
 335      }
 336  }
 337  
 338  static VoiceNode *MV_GetVoice(int handle)
 339  {
 340      if (handle < MV_MINVOICEHANDLE || handle > MV_MaxVoices)
 341      {
 342          LOG_F(WARNING, "No voice found for handle 0x%08x", handle);
 343          return nullptr;
 344      }
 345  
 346      if (MV_Handles[handle - MV_MINVOICEHANDLE] != nullptr)
 347          return MV_Handles[handle - MV_MINVOICEHANDLE];
 348  
 349      MV_SetErrorCode(MV_VoiceNotFound);
 350      return nullptr;
 351  }
 352  
 353  VoiceNode *MV_BeginService(int handle)
 354  {
 355      if (!MV_Installed)
 356          return nullptr;
 357  
 358      auto voice = MV_GetVoice(handle);
 359  
 360      if (voice == nullptr)
 361      {
 362          MV_SetErrorCode(MV_VoiceNotFound);
 363          return nullptr;
 364      }
 365  
 366      if (voice->task.valid() && !voice->task.ready())
 367          voice->task.wait();
 368  
 369      MV_Lock();
 370  
 371      return voice;
 372  }
 373  
 374  static inline void MV_EndService(void) { MV_Unlock(); }
 375  
 376  int MV_VoicePlaying(int handle)
 377  {
 378      Bassert(handle <= MV_MaxVoices);
 379      auto voice = MV_Handles[handle - MV_MINVOICEHANDLE];
 380      return MV_Installed && voice != nullptr && !voice->Paused.load(std::memory_order_relaxed);
 381  }
 382  
 383  int MV_KillAllVoices(bool useCallBack)
 384  {
 385      if (!MV_Installed)
 386          return MV_Error;
 387  
 388      MV_Lock();
 389  
 390      if (&VoiceList == VoiceList.next)
 391      {
 392          MV_Unlock();
 393          return MV_Ok;
 394      }
 395  
 396      auto voice = VoiceList.prev;
 397  
 398      // Remove all the voices from the list
 399      while (voice != &VoiceList)
 400      {
 401          if (voice->priority == MV_MUSIC_PRIORITY)
 402          {
 403              voice = voice->prev;
 404              continue;
 405          }
 406  
 407          MV_Kill(voice->handle, useCallBack);
 408          voice = VoiceList.prev;
 409      }
 410  
 411      MV_Unlock();
 412  
 413      return MV_Ok;
 414  }
 415  
 416  int MV_Kill(int handle, bool useCallBack)
 417  {
 418      auto voice = MV_BeginService(handle);
 419  
 420      if (voice == nullptr)
 421          return MV_Error;
 422  
 423      MV_StopVoice(voice, useCallBack);
 424      MV_EndService();
 425  
 426      return MV_Ok;
 427  }
 428  
 429  int MV_VoicesPlaying(void)
 430  {
 431      if (!MV_Installed)
 432          return 0;
 433  
 434      MV_Lock();
 435  
 436      int NumVoices = 0;
 437  
 438      for (auto voice = VoiceList.next; voice != &VoiceList; voice = voice->next)
 439          NumVoices++;
 440  
 441      MV_Unlock();
 442  
 443      return NumVoices;
 444  }
 445  
 446  static inline VoiceNode *MV_GetLowestPriorityVoice(void)
 447  {
 448      auto voice = VoiceList.next;
 449  
 450      // find the voice with the lowest priority and volume
 451      for (auto node = voice; node != &VoiceList; node = node->next)
 452      {
 453          if (node->priority < voice->priority
 454              || (node->priority == voice->priority && node->PannedVolume.Left < voice->PannedVolume.Left && node->PannedVolume.Right < voice->PannedVolume.Right))
 455              voice = node;
 456      }
 457  
 458      return voice;
 459  }
 460  
 461  static inline void MV_FinishAllocation(VoiceNode* voice, uint32_t const allocsize)
 462  {
 463      if (voice->rawdataptr != nullptr && voice->rawdatasiz == allocsize)
 464          return;
 465      else if (voice->rawdataptr != nullptr && voice->wavetype >= FMT_VORBIS)
 466      {
 467          // this is sort of a hack... wavetypes less than FMT_VORBIS never do their own allocations, so don't bother trying to free them
 468          ALIGNED_FREE_AND_NULL(voice->rawdataptr);
 469      }
 470  
 471      voice->rawdatasiz = allocsize;
 472      voice->rawdataptr = Xaligned_alloc(16, allocsize);
 473      Bmemset(voice->rawdataptr, 0, allocsize);
 474  }
 475  
 476  VoiceNode *MV_AllocVoice(int priority, uint32_t allocsize /* = 0 */)
 477  {
 478      MV_Lock();
 479  
 480      // Check if we have any free voices
 481      if (LL::Empty(&VoicePool))
 482      {
 483          auto voice = MV_GetLowestPriorityVoice();
 484  
 485          if (voice != &VoiceList && voice->priority <= priority && voice->handle >= MV_MINVOICEHANDLE && FX_SoundValidAndActive(voice->handle))
 486              MV_Kill(voice->handle);
 487  
 488          if (LL::Empty(&VoicePool))
 489          {
 490              // No free voices
 491              MV_Unlock();
 492              return nullptr;
 493          }
 494      }
 495  
 496      auto voice = VoicePool.next;
 497      LL::Remove(voice);
 498  
 499      int handle = MV_MINVOICEHANDLE;
 500  
 501      // Find a free voice handle
 502      do
 503      {
 504          if (++handle > MV_MaxVoices)
 505              handle = MV_MINVOICEHANDLE;
 506      } while (MV_Handles[handle - MV_MINVOICEHANDLE] != nullptr);
 507      MV_Handles[handle - MV_MINVOICEHANDLE] = voice;
 508  
 509      voice->length = 0;
 510      voice->BlockLength = 0;
 511      voice->handle = handle;
 512      voice->next = voice->prev = nullptr;
 513      MV_Unlock();
 514  
 515      if (allocsize)
 516          MV_FinishAllocation(voice, allocsize);
 517  
 518      return voice;
 519  }
 520  
 521  int MV_VoiceAvailable(int priority)
 522  {
 523      // Check if we have any free voices
 524      if (!LL::Empty(&VoicePool))
 525          return TRUE;
 526  
 527      MV_Lock();
 528      auto const voice = MV_GetLowestPriorityVoice();
 529      MV_Unlock();
 530  
 531      return (voice == &VoiceList || voice->priority > priority) ? FALSE : TRUE;
 532  }
 533  
 534  void MV_SetVoicePitch(VoiceNode *voice, uint32_t rate, int pitchoffset)
 535  {
 536      voice->SamplingRate = rate;
 537      voice->PitchScale   = PITCH_GetScale(pitchoffset);
 538      voice->RateScale    = divideu64((uint64_t)rate * voice->PitchScale, MV_MixRate);
 539  
 540      // Multiply by MV_MIXBUFFERSIZE - 1
 541      voice->FixedPointBufferSize = (voice->RateScale * MV_MIXBUFFERSIZE) -
 542                                    voice->RateScale;
 543  }
 544  
 545  int MV_SetPitch(int handle, int pitchoffset)
 546  {
 547      auto voice = MV_BeginService(handle);
 548  
 549      if (voice == nullptr)
 550          return MV_Error;
 551  
 552      MV_SetVoicePitch(voice, voice->SamplingRate, pitchoffset);
 553      MV_EndService();
 554  
 555      return MV_Ok;
 556  }
 557  
 558  int MV_SetFrequency(int handle, int frequency)
 559  {
 560      auto voice = MV_BeginService(handle);
 561  
 562      if (voice == nullptr)
 563          return MV_Error;
 564  
 565      MV_SetVoicePitch(voice, frequency, 0);
 566      MV_EndService();
 567  
 568      return MV_Ok;
 569  }
 570  
 571  int MV_GetFrequency(int handle, int *frequency)
 572  {
 573      auto voice = MV_BeginService(handle);
 574  
 575      if (voice == NULL || !frequency)
 576          return MV_Error;
 577  
 578      if (voice->SamplingRate == 0)
 579          voice->GetSound(voice);
 580  
 581      *frequency = voice->SamplingRate;
 582      MV_EndService();
 583  
 584      return MV_Ok;
 585  }
 586  
 587  /*---------------------------------------------------------------------
 588     Function: MV_SetVoiceMixMode
 589  
 590     Selects which method should be used to mix the voice.
 591  
 592     16Bit        16Bit |  8Bit  16Bit  8Bit  16Bit |
 593     Mono         Ster  |  Mono  Mono   Ster  Ster  |  Mixer
 594     Out          Out   |  In    In     In    In    |
 595  ----------------------+---------------------------+-------------
 596      X                 |         X                 | MixMono<int16_t, int16_t>
 597      X                 |   X                       | MixMono<uint8_t, int16_t>
 598                   X    |         X                 | MixStereo<int16_t, int16_t>
 599                   X    |   X                       | MixStereo<uint8_t, int16_t>
 600  ----------------------+---------------------------+-------------
 601                   X    |                      X    | MixStereoStereo<int16_t, int16_t>
 602                   X    |                X          | MixStereoStereo<uint8_t, int16_t>
 603      X                 |                      X    | MixMonoStereo<int16_t, int16_t>
 604      X                 |                X          | MixMonoStereo<uint8_t, int16_t>
 605  ---------------------------------------------------------------------*/
 606  
 607  void MV_SetVoiceMixMode(VoiceNode *voice)
 608  {
 609      // stereo look-up table
 610      static constexpr decltype(voice->mix) mixslut[]
 611      = { MV_MixStereo<uint8_t, int16_t>,       MV_MixMono<uint8_t, int16_t>,       MV_MixStereo<int16_t, int16_t>,       MV_MixMono<int16_t, int16_t>,
 612          MV_MixStereoStereo<uint8_t, int16_t>, MV_MixMonoStereo<uint8_t, int16_t>, MV_MixStereoStereo<int16_t, int16_t>, MV_MixMonoStereo<int16_t, int16_t> };
 613  
 614      // corresponds to T_MONO, T_16BITSOURCE, and T_STEREOSOURCE
 615      voice->mix = mixslut[(MV_Channels == 1) | ((voice->bits == 16) << 1) | ((voice->channels == 2) << 2)];
 616  }
 617  
 618  void MV_SetVoiceVolume(VoiceNode *voice, int vol, int left, int right, fix16_t volume)
 619  {
 620      if (MV_Channels == 1)
 621          left = right = vol;
 622  #ifdef ASS_REVERSESTEREO
 623      else if (MV_ReverseStereo)
 624          swap(&left, &right);
 625  #endif
 626  
 627      voice->GoalVolume = { fix16_smul(fix16_from_int(left), F16(1.f/MV_MAXTOTALVOLUME)), fix16_smul(fix16_from_int(right), F16(1.f/MV_MAXTOTALVOLUME)) };
 628      voice->volume = volume;
 629  
 630      MV_SetVoiceMixMode(voice);
 631  }
 632  
 633  int MV_PauseVoice(int handle, int pause)
 634  {
 635      auto voice = MV_BeginService(handle);
 636  
 637      if (voice == nullptr)
 638          return MV_Error;
 639  
 640      voice->Paused.store(pause, std::memory_order_release);
 641      MV_EndService();
 642  
 643      return MV_Ok;
 644  }
 645  
 646  int MV_GetPosition(int handle, int *position)
 647  {
 648      auto voice = MV_BeginService(handle);
 649  
 650      if (voice == nullptr)
 651          return MV_Error;
 652  
 653      switch (voice->wavetype)
 654      {
 655  #ifdef HAVE_VORBIS
 656          case FMT_VORBIS: *position = MV_GetVorbisPosition(voice); break;
 657  #endif
 658  #ifdef HAVE_FLAC
 659          case FMT_FLAC:   *position = MV_GetFLACPosition(voice); break;
 660  #endif
 661          case FMT_XA:     *position = MV_GetXAPosition(voice); break;
 662  #ifdef HAVE_XMP
 663          case FMT_XMP:    *position = MV_GetXMPPosition(voice); break;
 664  #endif
 665          default:         *position = (int)max<intptr_t>(0, (((intptr_t)voice->NextBlock + (intptr_t)voice->position - (intptr_t)voice->rawdataptr) >> 16) * ((voice->channels * voice->bits) >> 3)); break;
 666      }
 667  
 668      MV_EndService();
 669  
 670      return MV_Ok;
 671  }
 672  
 673  int MV_SetPosition(int handle, int position)
 674  {
 675      auto voice = MV_BeginService(handle);
 676  
 677      if (voice == nullptr)
 678          return MV_Error;
 679  
 680      switch (voice->wavetype)
 681      {
 682  #ifdef HAVE_VORBIS
 683          case FMT_VORBIS: MV_SetVorbisPosition(voice, position); break;
 684  #endif
 685  #ifdef HAVE_FLAC
 686          case FMT_FLAC:   MV_SetFLACPosition(voice, position); break;
 687  #endif
 688          case FMT_XA:     MV_SetXAPosition(voice, position); break;
 689  #ifdef HAVE_XMP
 690          case FMT_XMP:    MV_SetXMPPosition(voice, position); break;
 691  #endif
 692          default: break;
 693      }
 694  
 695      MV_EndService();
 696  
 697      return MV_Ok;
 698  }
 699  
 700  int MV_EndLooping(int handle)
 701  {
 702      auto voice = MV_BeginService(handle);
 703  
 704      if (voice == nullptr)
 705          return MV_Error;
 706  
 707      voice->Loop = {};
 708  
 709      MV_EndService();
 710  
 711      return MV_Ok;
 712  }
 713  
 714  int MV_SetPan(int handle, int vol, int left, int right)
 715  {
 716      auto voice = MV_BeginService(handle);
 717  
 718      if (voice == nullptr)
 719          return MV_Error;
 720  
 721      MV_SetVoiceVolume(voice, vol, left, right, voice->volume);
 722      MV_EndService();
 723      return MV_Ok;
 724  }
 725  
 726  int MV_Pan3D(int handle, int angle, int distance)
 727  {
 728      if (distance < 0)
 729      {
 730          distance = -distance;
 731          angle += MV_NUMPANPOSITIONS / 2;
 732      }
 733  
 734      int const volume = MIX_VOLUME(distance);
 735  
 736      angle &= MV_MAXPANPOSITION;
 737  
 738      return MV_SetPan(handle, max(0, 255 - distance),
 739          MV_PanTable[angle][volume].left,
 740          MV_PanTable[angle][volume].right);
 741  }
 742  
 743  void MV_SetReverb(int reverb)
 744  {
 745      MV_ReverbLevel = MIX_VOLUME(reverb);
 746      MV_ReverbVolume = fix16_smul(fix16_from_int(MV_ReverbLevel), F16(1.f/MV_MAXVOLUME));
 747  }
 748  
 749  int MV_GetMaxReverbDelay(void) { return MV_MIXBUFFERSIZE * MV_NumberOfBuffers; }
 750  int MV_GetReverbDelay(void) { return tabledivide32(MV_ReverbDelay, MV_SampleSize); }
 751  
 752  void MV_SetReverbDelay(int delay)
 753  {
 754      MV_ReverbDelay = max(MV_MIXBUFFERSIZE, min(delay, MV_GetMaxReverbDelay())) * MV_SampleSize;
 755  }
 756  
 757  static int MV_SetMixMode(int numchannels)
 758  {
 759      if (!MV_Installed)
 760          return MV_Error;
 761  
 762      MV_Channels = 1 + (numchannels == 2);
 763      MV_SampleSize = sizeof(int16_t) * MV_Channels;
 764  
 765      MV_BufferSize = MV_MIXBUFFERSIZE * MV_SampleSize;
 766      MV_NumberOfBuffers = tabledivide32(MV_TOTALBUFFERSIZE, MV_BufferSize);
 767      Bassert(isPow2(MV_NumberOfBuffers));
 768      MV_BufferLength = MV_TOTALBUFFERSIZE;
 769  
 770      MV_RightChannelOffset = MV_SampleSize >> 1;
 771  
 772      return MV_Ok;
 773  }
 774  
 775  static int MV_StartPlayback(void)
 776  {
 777      // Initialize the buffers
 778      Bmemset(MV_MixBuffer[0], 0, MV_TOTALBUFFERSIZE << 1);
 779  
 780      for (int buffer = 0; buffer < MV_NumberOfBuffers; buffer++)
 781          MV_BufferEmpty[buffer] = TRUE;
 782  
 783      MV_MixPage = 1;
 784  
 785      if (SoundDriver_PCM_BeginPlayback(MV_MixBuffer[MV_NumberOfBuffers], MV_BufferSize, MV_NumberOfBuffers, MV_ServiceVoc) != MV_Ok)
 786          return MV_SetErrorCode(MV_DriverError);
 787  
 788      return MV_Ok;
 789  }
 790  
 791  static void MV_StopPlayback(void)
 792  {
 793      SoundDriver_PCM_StopPlayback();
 794  
 795      // Make sure all callbacks are done.
 796      MV_Lock();
 797  
 798      for (VoiceNode *voice = VoiceList.next, *next; voice != &VoiceList; voice = next)
 799      {
 800          next = voice->next;
 801          MV_StopVoice(voice);
 802      }
 803  
 804      MV_Unlock();
 805  }
 806  
 807  static void MV_CalcPanTable(void)
 808  {
 809      const int HalfAngle = MV_NUMPANPOSITIONS / 2;
 810      const int QuarterAngle = HalfAngle / 2;
 811  
 812      for (int distance = 0; distance <= MV_MAXVOLUME; distance++)
 813      {
 814          const int level = (255 * (MV_MAXVOLUME - distance)) / MV_MAXVOLUME;
 815  
 816          for (int angle = 0; angle <= QuarterAngle; angle++)
 817          {
 818              const int ramp = level - (level * angle) / QuarterAngle;
 819  
 820              MV_PanTable[angle][distance].left = ramp;
 821              MV_PanTable[angle][distance].right = level;
 822  
 823              MV_PanTable[HalfAngle - angle][distance].left = ramp;
 824              MV_PanTable[HalfAngle - angle][distance].right = level;
 825  
 826              MV_PanTable[HalfAngle + angle][distance].left = level;
 827              MV_PanTable[HalfAngle + angle][distance].right = ramp;
 828  
 829              MV_PanTable[MV_MAXPANPOSITION - angle][distance].left = level;
 830              MV_PanTable[MV_MAXPANPOSITION - angle][distance].right = ramp;
 831          }
 832      }
 833  }
 834  
 835  void MV_SetVolume(int volume) { MV_GlobalVolume = fix16_smul(fix16_from_int(volume), F16(1.f/MV_MAXTOTALVOLUME)); }
 836  
 837  int MV_GetVolume(void) { return Blrintf(fix16_to_float(MV_GlobalVolume) * MV_MAXTOTALVOLUME); }
 838  
 839  void MV_SetCallBack(void (*function)(intptr_t)) { MV_CallBackFunc = function; }
 840  
 841  #ifdef ASS_REVERSESTEREO
 842  void MV_SetReverseStereo(int setting) { MV_ReverseStereo = setting; }
 843  int MV_GetReverseStereo(void) { return MV_ReverseStereo; }
 844  #endif
 845  
 846  int MV_Init(int soundcard, int MixRate, int Voices, int numchannels, void *initdata)
 847  {
 848      if (MV_Installed)
 849          MV_Shutdown();
 850  
 851      MV_SetErrorCode(MV_Ok);
 852  
 853      int const totalmem = Voices * sizeof(VoiceNode) + (MV_TOTALBUFFERSIZE * sizeof(int16_t)) + (MV_MIXBUFFERSIZE * numchannels * sizeof(int16_t));
 854  
 855      char *ptr = (char *) Xaligned_calloc(16, 1, totalmem);
 856  
 857      MV_Voices = (VoiceNode *)ptr;
 858      ptr += Voices * sizeof(VoiceNode);
 859      Bassert(Voices < MV_MAXVOICES);
 860  
 861      MV_MaxVoices = Voices;
 862  
 863      LL::Reset((VoiceNode*) &VoiceList);
 864      LL::Reset((VoiceNode*) &VoicePool);
 865  
 866      for (int index = 0; index < Voices; index++)
 867          LL::Insert(&VoicePool, &MV_Voices[index]);
 868  
 869      MV_Handles = (VoiceNode **)Xaligned_calloc(16, Voices, sizeof(intptr_t));
 870  #ifdef ASS_REVERSESTEREO
 871      MV_SetReverseStereo(FALSE);
 872  #endif
 873  
 874      ASS_PCMSoundDriver = soundcard;
 875  
 876      // Initialize the sound card
 877  
 878      if (SoundDriver_PCM_Init(&MixRate, &numchannels, initdata) != MV_Ok)
 879          MV_SetErrorCode(MV_DriverError);
 880  
 881      if (MV_ErrorCode != MV_Ok)
 882      {
 883          ALIGNED_FREE_AND_NULL(MV_Voices);
 884  
 885          return MV_Error;
 886      }
 887  
 888      MV_Installed    = TRUE;
 889      MV_InitDataPtr  = initdata;
 890      MV_CallBackFunc = nullptr;
 891      MV_ReverbLevel  = 0;
 892      MV_ReverbVolume = 0.f;
 893  
 894      // Set the sampling rate
 895      MV_MixRate = MixRate;
 896  
 897      // Set Mixer to play stereo digitized sound
 898      MV_SetMixMode(numchannels);
 899      MV_ReverbDelay = MV_BufferSize * 3;
 900  
 901      // Make sure we don't cross a physical page
 902      MV_MixBuffer[MV_NumberOfBuffers<<1] = ptr;
 903      for (int buffer = 0; buffer < MV_NumberOfBuffers<<1; buffer++)
 904      {
 905          MV_MixBuffer[buffer] = ptr;
 906          ptr += MV_BufferSize;
 907      }
 908  
 909      MV_MusicBuffer = ptr;
 910  
 911      // Calculate pan table
 912      MV_CalcPanTable();
 913  
 914      MV_VolumeSmoothFactor = fix16_from_float(1.f-powf(0.1f, 30.f/MixRate));
 915  
 916      // Start the playback engine
 917      if (MV_StartPlayback() != MV_Ok)
 918      {
 919          // Preserve error code while we shutdown.
 920          int status = MV_ErrorCode;
 921          MV_Shutdown();
 922          return MV_SetErrorCode(status);
 923      }
 924  
 925      return MV_Ok;
 926  }
 927  
 928  int MV_Shutdown(void)
 929  {
 930      if (!MV_Installed)
 931          return MV_Ok;
 932  
 933      MV_KillAllVoices();
 934  
 935      MV_Installed = FALSE;
 936  
 937      // Stop the sound playback engine
 938      MV_StopPlayback();
 939  
 940      // Shutdown the sound card
 941      SoundDriver_PCM_Shutdown();
 942  
 943      // Free any voices we allocated
 944      ALIGNED_FREE_AND_NULL(MV_Voices);
 945  
 946      LL::Reset((VoiceNode*) &VoiceList);
 947      LL::Reset((VoiceNode*) &VoicePool);
 948  
 949      ALIGNED_FREE_AND_NULL(MV_Handles);
 950  
 951      MV_MaxVoices = 1;
 952  
 953      // Release the descriptor from our mix buffer
 954      for (int buffer = 0; buffer < MV_NUMBEROFBUFFERS<<1; buffer++)
 955          MV_MixBuffer[buffer] = nullptr;
 956  
 957      MV_SetErrorCode(MV_NotInstalled);
 958  
 959      return MV_Ok;
 960  }
 961  
 962  void MV_HookMusicRoutine(void(*callback)(void))
 963  {
 964      MV_Lock();
 965      MV_MusicCallback = callback;
 966      MV_Unlock();
 967  }
 968  
 969  void MV_UnhookMusicRoutine(void)
 970  {
 971      if (MV_MusicCallback)
 972      {
 973          MV_Lock();
 974          MV_MusicCallback = nullptr;
 975          MV_Unlock();
 976      }
 977  }
 978  
 979  MV_MusicRoutineBuffer MV_GetMusicRoutineBuffer()
 980  {
 981      return MV_MusicRoutineBuffer{ MV_MusicBuffer, MV_BufferSize };
 982  }
 983  
 984  const char *loopStartTags[loopStartTagCount] = { "LOOP_START", "LOOPSTART", "LOOP" };
 985  const char *loopEndTags[loopEndTagCount] = { "LOOP_END", "LOOPEND" };
 986  const char *loopLengthTags[loopLengthTagCount] = { "LOOP_LENGTH", "LOOPLENGTH" };
 987  
 988  const char *MV_ErrorString(int ErrorNumber)
 989  {
 990      switch (ErrorNumber)
 991      {
 992          case MV_Error:
 993              return MV_ErrorString(MV_ErrorCode);
 994          case MV_Ok:
 995              return "Multivoc ok.";
 996          case MV_NotInstalled:
 997              return "Multivoc not installed.";
 998          case MV_DriverError:
 999              return SoundDriver_PCM_ErrorString(SoundDriver_PCM_GetError());
1000          case MV_NoVoices:
1001              return "No free voices available to Multivoc.";
1002          case MV_VoiceNotFound:
1003              return "No voice with matching handle found.";
1004          case MV_InvalidFile:
1005              return "Invalid file passed in to Multivoc.";
1006          default:
1007              return "Unknown Multivoc error code.";
1008      }
1009  }
1010  
1011  static playbackstatus MV_GetNextDemandFeedBlock(VoiceNode* voice)
1012  {
1013      if (voice->BlockLength > 0)
1014      {
1015          voice->position -= voice->length;
1016          voice->sound += voice->length >> 16;
1017          voice->length = min(voice->BlockLength, 0x8000u);
1018          voice->BlockLength -= voice->length;
1019          voice->length <<= 16;
1020  
1021          return KeepPlaying;
1022      }
1023  
1024      if (voice->DemandFeed == NULL)
1025          return NoMoreData;
1026  
1027      voice->position = 0;
1028      (voice->DemandFeed)(&voice->sound, &voice->BlockLength, voice->rawdataptr);
1029      voice->length = min(voice->BlockLength, 0x8000u);
1030      voice->BlockLength -= voice->length;
1031      voice->length <<= 16;
1032  
1033      if (voice->length > 0 && voice->sound != NULL)
1034          return KeepPlaying;
1035  
1036      return NoMoreData;
1037  }
1038  
1039  int MV_StartDemandFeedPlayback(void (*function)(const char** ptr, uint32_t* length, void* userdata), int bitdepth, int channels, int rate,
1040      int pitchoffset, int vol, int left, int right, int priority, fix16_t volume, intptr_t callbackval, void* userdata)
1041  {
1042      if (!MV_Installed)
1043          return MV_SetErrorCode(MV_NotInstalled);
1044  
1045      // Request a voice from the voice pool
1046      auto voice = MV_AllocVoice(priority);
1047      if (voice == nullptr)
1048          return MV_SetErrorCode(MV_NoVoices);
1049  
1050  //    voice->wavetype = FMT_DEMANDFED;
1051      voice->bits = bitdepth;
1052      voice->channels = channels;
1053      voice->GetSound = MV_GetNextDemandFeedBlock;
1054      voice->DemandFeed = function;
1055      voice->position = 0;
1056      voice->sound  = nullptr;
1057      voice->length = 0;
1058      voice->priority = priority;
1059      voice->callbackval = callbackval;
1060      voice->rawdataptr = userdata;
1061  
1062      voice->Loop = {};
1063  
1064      MV_SetVoicePitch(voice, rate, pitchoffset);
1065      MV_SetVoiceMixMode(voice);
1066      MV_SetVoiceVolume(voice, vol, left, right, volume);
1067      MV_PlayVoice(voice);
1068  
1069      return voice->handle;
1070  }
1071  
1072  int MV_StartDemandFeedPlayback3D(void (*function)(const char** ptr, uint32_t* length, void* userdata), int bitdepth, int channels, int rate,
1073      int pitchoffset, int angle, int distance, int priority, fix16_t volume, intptr_t callbackval, void* userdata)
1074  {
1075      if (!MV_Installed)
1076          return MV_SetErrorCode(MV_NotInstalled);
1077  
1078      if (distance < 0)
1079      {
1080          distance  = -distance;
1081          angle    += MV_NUMPANPOSITIONS / 2;
1082      }
1083  
1084      int const vol = MIX_VOLUME(distance);
1085  
1086      // Ensure angle is within 0 - 127
1087      angle &= MV_MAXPANPOSITION;
1088  
1089      return MV_StartDemandFeedPlayback(function, bitdepth, channels, rate, pitchoffset, max(0, 255 - distance),
1090          MV_PanTable[ angle ][ vol ].left, MV_PanTable[ angle ][ vol ].right, priority, volume, callbackval, userdata);
1091  }