예제 #1
0
파일: flac.c 프로젝트: sbrown345/edukejs
void error_flac_stream(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
{
   // flac_data * fd = (flac_data *) client_data;
    UNREFERENCED_PARAMETER(client_data);
    UNREFERENCED_PARAMETER(decoder);
    MV_Printf("%s\n", FLAC__StreamDecoderErrorStatusString[status]);
   // FLAC__stream_decoder_flush(fd->stream);
}
예제 #2
0
void DirectSoundDrv_PCM_Lock(void)
{
    DWORD err;
    
    err = WaitForSingleObject(mutex, INFINITE);
    if (err != WAIT_OBJECT_0) {
        if (MV_Printf)
            MV_Printf( "DirectSound lock: wfso %d\n", (int32_t) err);
    }
}
예제 #3
0
static DWORD WINAPI fillDataThread(LPVOID lpParameter)
{
    DWORD waitret, waitret2;
    HANDLE handles[] = { handles[0] = notifyPositions[0].hEventNotify, 
                         handles[1] = notifyPositions[1].hEventNotify,
                         handles[2] = notifyPositions[2].hEventNotify };
    
    UNREFERENCED_PARAMETER(lpParameter);

	do {
        waitret = WaitForMultipleObjects(3, handles, FALSE, INFINITE); 
        switch (waitret) {
            case WAIT_OBJECT_0:
            case WAIT_OBJECT_0+1:
                waitret2 = WaitForSingleObject(mutex, INFINITE);
                if (waitret2 == WAIT_OBJECT_0) {
                    FillBuffer(WAIT_OBJECT_0 + 1 - waitret);
                    ReleaseMutex(mutex);
                } else {
                    if (MV_Printf)
                        MV_Printf( "DirectSound fillDataThread: wfso err %d\n", (int32_t) waitret2);
                }
                break;
            case WAIT_OBJECT_0+2:
//                initprintf( "DirectSound fillDataThread: exiting\n");
                ExitThread(0);
                break;
            default:
                if (MV_Printf)
                    MV_Printf( "DirectSound fillDataThread: wfmo err %d\n", (int32_t) waitret);
                break;
        }
	} while (1);
	
	return 0;
}
예제 #4
0
static void FillBuffer(int32_t bufnum)
{
    HRESULT err;
    LPVOID ptr, ptr2;
    DWORD remaining, remaining2;
    int32_t retries = 1;
    
    //initprintf( "DirectSound FillBuffer: filling %d\n", bufnum);

    do {
        err = IDirectSoundBuffer_Lock(lpdsbsec,
                  notifyPositions[bufnum].dwOffset,
                  notifyPositions[1].dwOffset,
                  &ptr, &remaining,
                  &ptr2, &remaining2,
                  0);
        if (FAILED(err)) {
            if (err == DSERR_BUFFERLOST) {
                err = IDirectSoundBuffer_Restore(lpdsbsec);
                if (FAILED(err)) {
                    return;
                }

                if (retries-- > 0) {
                    continue;
                }
            }
            if (MV_Printf)
                MV_Printf("DirectSound FillBuffer: err %x\n", (uint32_t) err);
            return;
        }
        break;
    } while (1);
    
    if (ptr) {
        FillBufferPortion((char *) ptr, remaining);
    }
    if (ptr2) {
        FillBufferPortion((char *) ptr2, remaining2);
    }
    
    IDirectSoundBuffer_Unlock(lpdsbsec, ptr, remaining, ptr2, remaining2);
}
예제 #5
0
static void TeardownDSound(HRESULT err)
{
    if (FAILED(err)) {
        if (MV_Printf)
            MV_Printf( "Dying error: %x\n", (uint32_t) err);
    }

    if (lpdsnotify)   IDirectSoundNotify_Release(lpdsnotify);
    if (notifyPositions[0].hEventNotify) CloseHandle(notifyPositions[0].hEventNotify);
    if (notifyPositions[1].hEventNotify) CloseHandle(notifyPositions[1].hEventNotify);
    if (notifyPositions[2].hEventNotify) CloseHandle(notifyPositions[2].hEventNotify);
    if (mutex) CloseHandle(mutex);
    if (lpdsbsec)     IDirectSoundBuffer_Release(lpdsbsec);
    if (lpdsbprimary) IDirectSoundBuffer_Release(lpdsbprimary);
    if (lpds)         IDirectSound_Release(lpds);
    notifyPositions[0].hEventNotify =
    notifyPositions[1].hEventNotify =
    notifyPositions[2].hEventNotify = 0;
    mutex = NULL;
    lpdsnotify = NULL;
    lpdsbsec = NULL;
    lpdsbprimary = NULL;
    lpds = NULL;
}
예제 #6
0
파일: multivoc.c 프로젝트: dahlor/Duke3DS
static VoiceNode *MV_GetVoice(int32_t handle)
{
    if (handle < MV_MINVOICEHANDLE || handle > MV_MaxVoices)
    {
        if (MV_Printf)
            MV_Printf("MV_GetVoice(): bad handle (%d)!\n", handle);
        return NULL;
    }

    DisableInterrupts();

    for (VoiceNode *voice = VoiceList.next; voice != &VoiceList; voice = voice->next)
    {
        if (handle == voice->handle)
        {
            RestoreInterrupts();
            return voice;
        }
    }

    RestoreInterrupts();
    MV_SetErrorCode(MV_VoiceNotFound);
    return NULL;
}
예제 #7
0
파일: flac.c 프로젝트: sbrown345/edukejs
int32_t MV_PlayFLAC
(
 char *ptr,
 uint32_t ptrlength,
 int32_t   loopstart,
 int32_t   loopend,
 int32_t   pitchoffset,
 int32_t   vol,
 int32_t   left,
 int32_t   right,
 int32_t   priority,
 uint32_t callbackval
 )

{
   VoiceNode   *voice;
   flac_data * fd = 0;
   FLAC__Metadata_Chain* metadata_chain;

   UNREFERENCED_PARAMETER(loopend);

   if ( !MV_Installed )
   {
      MV_SetErrorCode( MV_NotInstalled );
      return MV_Error;
   }

   fd = (flac_data *) malloc( sizeof(flac_data) );
   if (!fd) {
      MV_SetErrorCode( MV_InvalidFLACFile );
      return MV_Error;
   }

   memset(fd, 0, sizeof(flac_data));
   fd->ptr = ptr;
   fd->pos = 0;
   fd->blocksize = 0;
   fd->length = ptrlength;

   fd->block = NULL;

   fd->stream = FLAC__stream_decoder_new();
   fd->sample_pos = 0;

    FLAC__stream_decoder_set_metadata_ignore_all(fd->stream);

   if (FLAC__stream_decoder_init_stream(fd->stream,
            read_flac_stream,
            seek_flac_stream,
            tell_flac_stream,
            length_flac_stream,
            eof_flac_stream,
            write_flac_stream,
            /*metadata_flac_stream*/ NULL,
            error_flac_stream,
            (void*) fd) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
      MV_Printf("MV_PlayFLAC: %s\n", FLAC__stream_decoder_get_resolved_state_string(fd->stream));
      MV_SetErrorCode( MV_InvalidFLACFile );
      return MV_Error;
   }

   // Request a voice from the voice pool
   voice = MV_AllocVoice( priority );
   if ( voice == NULL )
   {
      FLAC__stream_decoder_finish(fd->stream);
      FLAC__stream_decoder_delete(fd->stream);
      free(fd);
      MV_SetErrorCode( MV_NoVoices );
      return MV_Error;
   }

   fd->owner = voice;

   voice->wavetype    = FLAC;
   voice->extra       = (void*)fd;
   voice->GetSound    = MV_GetNextFLACBlock;
   voice->NextBlock   = fd->block;
   voice->DemandFeed  = NULL;
   voice->LoopCount   = 0;
   voice->BlockLength = 0;
   voice->PitchScale  = PITCH_GetScale( pitchoffset );
   voice->next        = NULL;
   voice->prev        = NULL;
   voice->priority    = priority;
   voice->callbackval = callbackval;

   voice->Playing     = TRUE;
   voice->Paused      = FALSE;

   voice->LoopStart   = 0;
   voice->LoopEnd     = 0;
   voice->LoopSize    = (loopstart >= 0 ? 1 : 0);

    // parse metadata
    // loop parsing designed with multiple repetitions in mind
    // In retrospect, it may be possible to MV_GetVorbisCommentLoops(voice, (vorbis_comment *) tags->data.vorbis_comment)
    // but libvorbisfile may be confused by the signedness of char* vs FLAC__byte* and this code does not depend on HAVE_VORBIS.
    metadata_chain = FLAC__metadata_chain_new();
    if (metadata_chain != NULL)
    {
        if (FLAC__metadata_chain_read_with_callbacks(metadata_chain, fd, flac_callbacks))
        {
            FLAC__Metadata_Iterator* metadata_iterator = FLAC__metadata_iterator_new();
            if (metadata_iterator != NULL)
            {
                char *vc_loopstart = NULL;
                char *vc_loopend = NULL;
                char *vc_looplength = NULL;

                FLAC__metadata_iterator_init(metadata_iterator, metadata_chain);

                do
                {
                    FLAC__StreamMetadata *tags = FLAC__metadata_iterator_get_block(metadata_iterator);

                    if (tags->type == FLAC__METADATA_TYPE_STREAMINFO)
                    {
                        const FLAC__StreamMetadata_StreamInfo *info = &tags->data.stream_info;

                        if (info->channels != 1 && info->channels != 2) {
                           FLAC__metadata_object_delete(tags);
                           FLAC__metadata_iterator_delete(metadata_iterator);
                          // FLAC__metadata_chain_delete(metadata_chain);
                           FLAC__stream_decoder_finish(fd->stream);
                           FLAC__stream_decoder_delete(fd->stream);
                           free(fd);
                           MV_SetErrorCode( MV_InvalidFLACFile );
                           return MV_Error;
                        }

                        voice->channels     = info->channels;
                        voice->bits         = info->bits_per_sample;
                        voice->SamplingRate = info->sample_rate;
                    }

                    // load loop tags from metadata
                    if (tags->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
                    {
                        FLAC__uint32 comment;
                        uint8_t loopTagCount;
                        for (comment = 0; comment < tags->data.vorbis_comment.num_comments; ++comment)
                        {
                            const char *entry = (const char *) tags->data.vorbis_comment.comments[comment].entry;
                            if (entry != NULL && entry[0] != '\0')
                            {
                                const char *value = strchr(entry,'=');
                                const size_t field = value-entry;
                                value += 1;

                                for (loopTagCount = 0; loopTagCount < loopStartTagCount && vc_loopstart == NULL; ++loopTagCount)
                                    if (strncasecmp(entry, loopStartTags[loopTagCount], field) == 0)
                                        vc_loopstart = strdup(value);

                                for (loopTagCount = 0; loopTagCount < loopEndTagCount && vc_loopend == NULL; ++loopTagCount)
                                    if (strncasecmp(entry, loopEndTags[loopTagCount], field) == 0)
                                        vc_loopend = strdup(value);

                                for (loopTagCount = 0; loopTagCount < loopLengthTagCount && vc_looplength == NULL; ++loopTagCount)
                                    if (strncasecmp(entry, loopLengthTags[loopTagCount], field) == 0)
                                        vc_looplength = strdup(value);
                            }
                        }
                    }

                    FLAC__metadata_object_delete(tags); // If it wasn't for this I would assign pointers instead of strdup().
                }
                while (FLAC__metadata_iterator_next(metadata_iterator));

                if (vc_loopstart != NULL)
                {
                    {
                        const FLAC__int64 flac_loopstart = atol(vc_loopstart);
                        if (flac_loopstart >= 0) // a loop starting at 0 is valid
                        {
                            voice->LoopStart = (const char *) (intptr_t) flac_loopstart;
                            voice->LoopSize = 1;
                        }
                    }
                    free(vc_loopstart);
                }
                if (vc_loopend != NULL)
                {
                    if (voice->LoopSize > 0)
                    {
                        const FLAC__int64 flac_loopend = atol(vc_loopend);
                        if (flac_loopend > 0) // a loop ending at 0 is invalid
                            voice->LoopEnd = (const char *) (intptr_t) flac_loopend;
                    }
                    free(vc_loopend);
                }
                if (vc_looplength != NULL)
                {
                    if (voice->LoopSize > 0 && voice->LoopEnd == 0)
                    {
                        const FLAC__int64 flac_looplength = atol(vc_looplength);
                        if (flac_looplength > 0) // a loop of length 0 is invalid
                            voice->LoopEnd = (const char *) ((intptr_t) flac_looplength + (intptr_t) voice->LoopStart);
                    }
                    free(vc_looplength);
                }

                FLAC__metadata_iterator_delete(metadata_iterator);
            }
            else
                MV_Printf("Error allocating FLAC__Metadata_Iterator!\n");
        }
        else
            MV_Printf("%s\n", FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(metadata_chain)]);

       // FLAC__metadata_chain_delete(metadata_chain); // when run with GDB, this throws SIGTRAP about freed heap memory being modified
    }
    else
        MV_Printf("Error allocating FLAC__Metadata_Chain!\n");

   // CODEDUP multivoc.c MV_SetVoicePitch
   voice->RateScale    = ( voice->SamplingRate * voice->PitchScale ) / MV_MixRate;
   voice->FixedPointBufferSize = ( voice->RateScale * MV_MIXBUFFERSIZE ) -
      voice->RateScale;
   MV_SetVoiceMixMode( voice );

   MV_SetVoiceVolume( voice, vol, left, right );
   MV_PlayVoice( voice );

   return voice->handle;
}
예제 #8
0
파일: flac.c 프로젝트: sbrown345/edukejs
static playbackstatus MV_GetNextFLACBlock
(
 VoiceNode *voice
 )

{
    flac_data * fd = (flac_data *) voice->extra;
    FLAC__StreamDecoderState decode_state;
   // FLAC__bool decode_status;

    voice->Playing = TRUE;

    if ((FLAC__uint64)(uintptr_t)voice->LoopEnd > 0 && fd->sample_pos >= (FLAC__uint64)(uintptr_t)voice->LoopEnd)
        if (!FLAC__stream_decoder_seek_absolute(fd->stream, (FLAC__uint64)(uintptr_t)voice->LoopStart))
            MV_Printf("MV_GetNextFLACBlock FLAC__stream_decoder_seek_absolute: LOOP_START %ul, LOOP_END %ul\n",
                (FLAC__uint64)(uintptr_t)voice->LoopStart, (FLAC__uint64)(uintptr_t)voice->LoopEnd);

    /*decode_status =*/ FLAC__stream_decoder_process_single(fd->stream);
    decode_state = FLAC__stream_decoder_get_state(fd->stream);

/*
    if (!decode_status)
    {
        MV_Printf("MV_GetNextFLACBlock: %s\n", FLAC__StreamDecoderStateString[decode_state]);
        voice->Playing = FALSE;
        return NoMoreData;
    }
*/

    if (decode_state == FLAC__STREAM_DECODER_SEEK_ERROR)
    {
        FLAC__stream_decoder_flush(fd->stream);
        decode_state = FLAC__stream_decoder_get_state(fd->stream);
    }

    if (decode_state == FLAC__STREAM_DECODER_END_OF_STREAM)
    {
        if (voice->LoopSize > 0)
        {
            if (!FLAC__stream_decoder_seek_absolute(fd->stream, (FLAC__uint64)(uintptr_t)voice->LoopStart))
                MV_Printf("MV_GetNextFLACBlock FLAC__stream_decoder_seek_absolute: LOOP_START %ul\n",
                   (FLAC__uint64)(uintptr_t)voice->LoopStart);
        }
        else
        {
            voice->Playing = FALSE;
            return NoMoreData;
        }
    }

#if 0
    // unnecessary: duplicated in write_flac_stream()
    voice->channels     = FLAC__stream_decoder_get_channels(fd->stream);
    voice->bits         = FLAC__stream_decoder_get_bits_per_sample(fd->stream);
    voice->SamplingRate = FLAC__stream_decoder_get_sample_rate(fd->stream);
    // CODEDUP multivoc.c MV_SetVoicePitch
    voice->RateScale    = ( voice->SamplingRate * voice->PitchScale ) / MV_MixRate;
    voice->FixedPointBufferSize = ( voice->RateScale * MV_MIXBUFFERSIZE ) - voice->RateScale;
    MV_SetVoiceMixMode( voice );
#endif

    return KeepPlaying;
}
예제 #9
0
int32_t MV_PlayLoopedVorbis
(
 char *ptr,
 uint32_t ptrlength,
 int32_t   loopstart,
 int32_t   loopend,
 int32_t   pitchoffset,
 int32_t   vol,
 int32_t   left,
 int32_t   right,
 int32_t   priority,
 uint32_t callbackval
 )

{
   VoiceNode   *voice;
   int32_t          status;
   vorbis_data * vd = 0;
   vorbis_info * vi = 0;
 
   UNREFERENCED_PARAMETER(loopend);

   if ( !MV_Installed )
   {
      MV_SetErrorCode( MV_NotInstalled );
      return( MV_Error );
   }
   
   vd = (vorbis_data *) malloc( sizeof(vorbis_data) );
   if (!vd) {
      MV_SetErrorCode( MV_InvalidVorbisFile );
      return MV_Error;
   }
   
   memset(vd, 0, sizeof(vorbis_data));
   vd->ptr = ptr;
   vd->pos = 0;
   vd->length = ptrlength;
   vd->lastbitstream = -1;
   
   status = ov_open_callbacks((void *) vd, &vd->vf, 0, 0, vorbis_callbacks);
   if (status < 0) {
      MV_Printf("MV_PlayLoopedVorbis: err %d\n", status);
      MV_SetErrorCode( MV_InvalidVorbisFile );
      return MV_Error;
   }
   
   vi = ov_info(&vd->vf, 0);
   if (!vi) {
      ov_clear(&vd->vf);
      free(vd);
      MV_SetErrorCode( MV_InvalidVorbisFile );
      return MV_Error;
   }
   
   if (vi->channels != 1 && vi->channels != 2) {
      ov_clear(&vd->vf);
      free(vd);
      MV_SetErrorCode( MV_InvalidVorbisFile );
      return MV_Error;
   }
   
   // Request a voice from the voice pool
   voice = MV_AllocVoice( priority );
   if ( voice == NULL )
   {
      ov_clear(&vd->vf);
      free(vd);
      MV_SetErrorCode( MV_NoVoices );
      return( MV_Error );
   }
   
   voice->wavetype    = Vorbis;
   voice->bits        = 16;
   voice->channels    = vi->channels;
   voice->extra       = (void *) vd;
   voice->GetSound    = MV_GetNextVorbisBlock;
   voice->NextBlock   = vd->block;
   voice->DemandFeed  = NULL;
   voice->LoopCount   = 0;
   voice->BlockLength = 0;
   voice->PitchScale  = PITCH_GetScale( pitchoffset );
   voice->length      = 0;
   voice->next        = NULL;
   voice->prev        = NULL;
   voice->priority    = priority;
   voice->callbackval = callbackval;
   voice->LoopStart   = (char *) (loopstart >= 0 ? TRUE : FALSE);
   voice->LoopEnd     = 0;
   voice->LoopSize    = 0;
   voice->Playing     = TRUE;
   voice->Paused      = FALSE;
   
   voice->SamplingRate = vi->rate;
   voice->RateScale    = ( voice->SamplingRate * voice->PitchScale ) / MV_MixRate;
   voice->FixedPointBufferSize = ( voice->RateScale * MixBufferSize ) -
      voice->RateScale;
   MV_SetVoiceMixMode( voice );

   MV_SetVoiceVolume( voice, vol, left, right );
   MV_PlayVoice( voice );
   
   return( voice->handle );
}
예제 #10
0
static playbackstatus MV_GetNextVorbisBlock
(
 VoiceNode *voice
 )

{
   vorbis_data * vd = (vorbis_data *) voice->extra;
   int32_t bytes, bytesread;
   int32_t bitstream, err;

   voice->Playing = TRUE;
   
   bytesread = 0;
   do {
       bytes = ov_read(&vd->vf, vd->block + bytesread, BLOCKSIZE - bytesread, 0, 2, 1, &bitstream);
       //fprintf(stderr, "ov_read = %d\n", bytes);
       if (bytes > 0) { bytesread += bytes; continue; }
       else if (bytes == OV_HOLE) continue;
       else if (bytes == 0) {
           if (voice->LoopStart) {
               err = ov_pcm_seek_page(&vd->vf, 0);
               if (err != 0) {
                   MV_Printf("MV_GetNextVorbisBlock ov_pcm_seek_page_lap: err %d\n", err);
               } else {
                   continue;
               }
           } else {
               break;
           }
       } else if (bytes < 0) {
           MV_Printf("MV_GetNextVorbisBlock ov_read: err %d\n", bytes);
           voice->Playing = FALSE;
           return NoMoreData;
       }
   } while (bytesread < BLOCKSIZE);

   if (bytesread == 0) {
      voice->Playing = FALSE;
      return NoMoreData;
   }
      
   if (bitstream != vd->lastbitstream) {
      vorbis_info * vi = 0;
      
      vi = ov_info(&vd->vf, -1);
      if (!vi || (vi->channels != 1 && vi->channels != 2)) {
         voice->Playing = FALSE;
         return NoMoreData;
      }
      
      voice->channels = vi->channels;
      voice->SamplingRate = vi->rate;
      voice->RateScale    = ( voice->SamplingRate * voice->PitchScale ) / MV_MixRate;
      voice->FixedPointBufferSize = ( voice->RateScale * MixBufferSize ) - voice->RateScale;
      MV_SetVoiceMixMode( voice );
      vd->lastbitstream = bitstream;
   }

   bytesread /= 2 * voice->channels;
   
   voice->position    = 0;
   voice->sound       = vd->block;
   voice->BlockLength = 0;
   voice->length      = bytesread << 16;
   
   return( KeepPlaying );
}
예제 #11
0
파일: multivoc.c 프로젝트: dahlor/Duke3DS
/*---------------------------------------------------------------------
   JBF: no synchronisation happens inside MV_ServiceVoc nor the
        supporting functions it calls. This would cause a deadlock
        between the mixer thread in the driver vs the nested
        locking in the user-space functions of MultiVoc. The call
        to MV_ServiceVoc is synchronised in the driver.
---------------------------------------------------------------------*/
static void MV_ServiceVoc(void)
{
    // Toggle which buffer we'll mix next
    if (++MV_MixPage >= MV_NumberOfBuffers)
        MV_MixPage -= MV_NumberOfBuffers;

    if (MV_ReverbLevel == 0)
    {
        // Initialize buffer
        //Commented out so that the buffer is always cleared.
        //This is so the guys at Echo Speech can mix into the
        //buffer even when no sounds are playing.
        if (!MV_BufferEmpty[MV_MixPage])
        {
            Bmemset(MV_MixBuffer[MV_MixPage], 0, MV_BufferSize);
            MV_BufferEmpty[ MV_MixPage ] = TRUE;
        }
    }
    else
    {
        char const *const end = MV_MixBuffer[0] + MV_BufferLength;
        char *dest = MV_MixBuffer[MV_MixPage];
        char const *source = MV_MixBuffer[MV_MixPage] - MV_ReverbDelay;

        if (source < MV_MixBuffer[ 0 ])
            source += MV_BufferLength;

        int32_t length = MV_BufferSize;

        while (length > 0)
        {
            int const count = (source + length > end) ? (end - source) : length;

            MV_16BitReverb(source, dest, MV_ReverbTable, count / 2);

            // if we go through the loop again, it means that we've wrapped around the buffer
            source  = MV_MixBuffer[ 0 ];
            dest   += count;
            length -= count;
        }
    }

    // Play any waiting voices
    //DisableInterrupts();

    VoiceNode *voice;

    if (!VoiceList.next || (voice = VoiceList.next) == &VoiceList)
        return;

    int iter = 0;

    VoiceNode *next;

    do
    {
        next = voice->next;

        if (++iter > MV_MaxVoices && MV_Printf)
            MV_Printf("more iterations than voices! iter: %d\n",iter);

        if (voice->Paused)
            continue;

        MV_BufferEmpty[ MV_MixPage ] = FALSE;

        MV_Mix(voice, MV_MixPage);

        // Is this voice done?
        if (!voice->Playing)
        {
            //JBF: prevent a deadlock caused by MV_StopVoice grabbing the mutex again
            //MV_StopVoice( voice );
            LL_Remove(voice, next, prev);
            LL_Add((VoiceNode*) &VoicePool, voice, next, prev);

            switch (voice->wavetype)
            {
#ifdef HAVE_VORBIS
                case FMT_VORBIS: MV_ReleaseVorbisVoice(voice); break;
#endif
#ifdef HAVE_FLAC
                case FMT_FLAC: MV_ReleaseFLACVoice(voice); break;
#endif
                case FMT_XA: MV_ReleaseXAVoice(voice); break;
                default: break;
            }

            voice->handle = 0;

            if (MV_CallBackFunc)
                MV_CallBackFunc(voice->callbackval);
        }
    }
    while ((voice = next) != &VoiceList);

    //RestoreInterrupts();
}