Exemplo n.º 1
0
int32_t MV_Shutdown(void)
{
    if (!MV_Installed)
        return MV_Ok;

    MV_KillAllVoices();

    MV_Installed = FALSE;

    // Stop the sound playback engine
    MV_StopPlayback();

    // Shutdown the sound card
    SoundDriver_Shutdown();

    // Free any voices we allocated
    #ifdef _3DS
    linearFree(MV_Voices);
    #else
    ALIGNED_FREE_AND_NULL(MV_Voices);
    #endif

    LL_Reset((VoiceNode*) &VoiceList, next, prev);
    LL_Reset((VoiceNode*) &VoicePool, next, prev);

    MV_MaxVoices = 1;

    // Release the descriptor from our mix buffer
    for (int buffer = 0; buffer < MV_NUMBEROFBUFFERS; buffer++)
        MV_MixBuffer[ buffer ] = NULL;

    MV_SetErrorCode(MV_NotInstalled);

    return MV_Ok;
}
Exemplo n.º 2
0
static int32_t MV_StartPlayback(void)
{
    // Initialize the buffers
    Bmemset(MV_MixBuffer[0], 0, MV_TOTALBUFFERSIZE);

    for (int buffer = 0; buffer < MV_NumberOfBuffers; buffer++)
        MV_BufferEmpty[buffer] = TRUE;

    MV_MixPage = 1;

    if (SoundDriver_BeginPlayback(MV_MixBuffer[0], MV_BufferSize, MV_NumberOfBuffers, MV_ServiceVoc) != MV_Ok)
    {
        MV_SetErrorCode(MV_DriverError);
        return MV_Error;
    }

    return MV_Ok;
}
Exemplo n.º 3
0
VoiceNode *MV_BeginService(int32_t handle)
{
    if (!MV_Installed)
        return NULL;

    DisableInterrupts();

    VoiceNode *voice;

    if ((voice = MV_GetVoice(handle)) == NULL)
    {
        RestoreInterrupts();
        MV_SetErrorCode(MV_VoiceNotFound);
        return NULL;
    }

    return voice;
}
Exemplo n.º 4
0
int MV_PlayVorbis3D
(
 char *ptr,
 unsigned int ptrlength,
 int  pitchoffset,
 int  angle,
 int  distance,
 int  priority,
 unsigned int callbackval
 )

{
   int left;
   int right;
   int mid;
   int volume;
   int status;
   
   if ( !MV_Installed )
   {
      MV_SetErrorCode( MV_NotInstalled );
      return( MV_Error );
   }
   
   if ( distance < 0 )
   {
      distance  = -distance;
      angle    += MV_NumPanPositions / 2;
   }
   
   volume = MIX_VOLUME( distance );
   
   // Ensure angle is within 0 - 31
   angle &= MV_MaxPanPosition;
   
   left  = MV_PanTable[ angle ][ volume ].left;
   right = MV_PanTable[ angle ][ volume ].right;
   mid   = max( 0, 255 - distance );
   
   status = MV_PlayVorbis( ptr, ptrlength, pitchoffset, mid, left, right, priority,
                           callbackval );
   
   return( status );
}
Exemplo n.º 5
0
int32_t MV_PlayFLAC3D
(
 char *ptr,
 uint32_t ptrlength,
 int32_t loophow,
 int32_t  pitchoffset,
 int32_t  angle,
 int32_t  distance,
 int32_t  priority,
 uint32_t callbackval
 )

{
   int32_t left;
   int32_t right;
   int32_t mid;
   int32_t volume;
   int32_t status;

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

   if ( distance < 0 )
   {
      distance  = -distance;
      angle    += MV_NUMPANPOSITIONS / 2;
   }

   volume = MIX_VOLUME( distance );

   // Ensure angle is within 0 - 127
   angle &= MV_MAXPANPOSITION;

   left  = MV_PanTable[ angle ][ volume ].left;
   right = MV_PanTable[ angle ][ volume ].right;
   mid   = max( 0, 255 - distance );

   status = MV_PlayFLAC(ptr, ptrlength, pitchoffset, loophow, -1, mid, left, right, priority, callbackval);

   return status;
}
Exemplo n.º 6
0
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;
}
Exemplo n.º 7
0
int MV_PlayLoopedVorbis
(
 char *ptr,
 unsigned int ptrlength,
 int   loopstart,
 int   loopend,
 int   pitchoffset,
 int   vol,
 int   left,
 int   right,
 int   priority,
 unsigned int callbackval
 )

{
   VoiceNode   *voice;
   int          status;
   vorbis_data * vd = 0;
   vorbis_info * vi = 0;
   
   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) {
      fprintf(stderr, "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 );
}
Exemplo n.º 8
0
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;
}
Exemplo n.º 9
0
int32_t MV_Init(int32_t soundcard, int32_t MixRate, int32_t Voices, int32_t numchannels, void *initdata)
{
    if (MV_Installed)
        MV_Shutdown();

    MV_SetErrorCode(MV_Ok);

    // MV_TotalMemory + 2: FIXME, see valgrind_errors.log
    int const totalmem = Voices * sizeof(VoiceNode) + MV_TOTALBUFFERSIZE + 2;
    #ifdef _3DS
    char *ptr = (char *) linearAlloc( totalmem);
    #else
    char *ptr = (char *) Xaligned_alloc(16, totalmem);
    #endif

    if (!ptr)
    {
        MV_SetErrorCode(MV_NoMem);
        return MV_Error;
    }

    Bmemset(ptr, 0, totalmem);

    MV_Voices = (VoiceNode *)ptr;
    ptr += Voices * sizeof(VoiceNode);

    // Set number of voices before calculating volume table
    MV_MaxVoices = Voices;

    LL_Reset((VoiceNode*) &VoiceList, next, prev);
    LL_Reset((VoiceNode*) &VoicePool, next, prev);

    for (int index = 0; index < Voices; index++)
    {
        LL_Add((VoiceNode*) &VoicePool, &MV_Voices[ index ], next, prev);
    }

    MV_SetReverseStereo(FALSE);

    ASS_SoundDriver = soundcard;

    // Initialize the sound card

    if (SoundDriver_Init(&MixRate, &numchannels, initdata) != MV_Ok)
        MV_SetErrorCode(MV_DriverError);

    if (MV_ErrorCode != MV_Ok)
    {
        ALIGNED_FREE_AND_NULL(MV_Voices);

        return MV_Error;
    }

    MV_Installed    = TRUE;
    MV_CallBackFunc = NULL;
    MV_ReverbLevel  = 0;
    MV_ReverbTable  = NULL;

    // Set the sampling rate
    MV_MixRate = MixRate;

    // Set Mixer to play stereo digitized sound
    MV_SetMixMode(numchannels);
    MV_ReverbDelay = MV_BufferSize * 3;

    // Make sure we don't cross a physical page
    MV_MixBuffer[ MV_NumberOfBuffers ] = ptr;
    for (int buffer = 0; buffer < MV_NumberOfBuffers; buffer++)
    {
        MV_MixBuffer[ buffer ] = ptr;
        ptr += MV_BufferSize;
    }

    // Calculate pan table
    MV_CalcPanTable();

    MV_SetVolume(MV_MAXTOTALVOLUME);

    // Start the playback engine
    if (MV_StartPlayback() != MV_Ok)
    {
        // Preserve error code while we shutdown.
        int status = MV_ErrorCode;
        MV_Shutdown();
        MV_SetErrorCode(status);
        return MV_Error;
    }

    return MV_Ok;
}