# # SDL_mixer: An audio mixer library based on the SDL library # Copyright (C) 1997-2013 Sam Lantinga # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages # arising from the use of this software. # # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. # {.deadCodeElim: on.} # Dynamically link to the correct library for our system: when not defined(SDL_Static): when defined(windows): const LibName* = "SDL2_mixer.dll" elif defined(macosx): const LibName* = "libSDL2_mixer.dylib" else: const LibName* = "libSDL2_mixer(|-2.0).so(|.0)" else: static: echo "SDL_Static option is deprecated and will soon be removed. Instead please use --dynlibOverride:SDL2." when not defined(SDL_Static): {.push callConv:cdecl, dynlib: LibName.} import ../sdl2, audio when system.cpuEndian == littleEndian: # SDL_BYTEORDER == SDL_LIL_ENDIAN const MIX_DEFAULT_FORMAT* = AUDIO_S16LSB else: const MIX_DEFAULT_FORMAT* = AUDIO_S16MSB # Remove prefixes in our wrapper, we have modules in Nim: # These are not recognized by c2nim, but that's easy to fix: # This function gets the version of the dynamically linked SDL_mixer library. # it should NOT be used to fill a version structure, instead you should # use the SDL_MIXER_VERSION() macro. # proc linkedVersion*(): ptr SDL_version {.importc: "Mix_Linked_Version".} const MIX_INIT_FLAC* : cint = 0x00000001 MIX_INIT_MOD* : cint = 0x00000002 MIX_INIT_MODPLUG* : cint = 0x00000004 MIX_INIT_MP3* : cint = 0x00000008 MIX_INIT_OGG* : cint = 0x00000010 MIX_INIT_FLUIDSYNTH* : cint = 0x00000020 # Loads dynamic libraries and prepares them for use. Flags should be # one or more flags from MIX_InitFlags OR'd together. # It returns the flags successfully initialized, or 0 on failure. # proc init*(flags: cint): cint {.importc: "Mix_Init".} # Unloads libraries loaded with Mix_Init proc quit*() {.importc: "Mix_Quit".} # The default mixer has 8 simultaneous mixing channels const MIX_CHANNELS* = 8 # Good default values for a PC soundcard const MIX_DEFAULT_FREQUENCY* = 22050 MIX_DEFAULT_CHANNELS* = 2 # Volume of a chunk const MIX_MAX_VOLUME* = 128 # The internal format for an audio chunk type ChunkPtr* = ptr Chunk Chunk* = object allocated*: cint abuf*: ptr uint8 alen*: uint32 volume*: uint8 # Per-sample volume, 0-128 # The different fading types supported type Fading* {.size: sizeof(cint).} = enum MIX_NO_FADING, MIX_FADING_OUT, MIX_FADING_IN MusicType* {.size: sizeof(cint).} = enum MUS_NONE, MUS_CMD, MUS_WAV, MUS_MOD, MUS_MID, MUS_OGG, MUS_MP3, MUS_MP3_MAD, MUS_FLAC, MUS_MODPLUG # The internal format for a music chunk interpreted via mikmod type MusicPtr* = ptr Music Music* = object # Open the mixer with a certain audio format proc openAudio*(frequency: cint; format: uint16; channels: cint; chunksize: cint): cint {.importc: "Mix_OpenAudio".} # Dynamically change the number of channels managed by the mixer. # If decreasing the number of channels, the upper channels are # stopped. # This function returns the new number of allocated channels. # proc allocateChannels*(numchans: cint): cint {. importc: "Mix_AllocateChannels".} # Find out what the actual audio device parameters are. # This function returns 1 if the audio has been opened, 0 otherwise. # proc querySpec*(frequency: ptr cint; format: ptr uint16; channels: ptr cint): cint {. importc: "Mix_QuerySpec".} # Load a wave file or a music (.mod .s3m .it .xm) file proc loadWAV_RW*(src: RWopsPtr; freesrc: cint): ptr Chunk {.importc: "Mix_LoadWAV_RW".} template loadWAV*(file: untyped): untyped = loadWAV_RW(rwFromFile(file, "rb"), 1) proc loadMUS*(file: cstring): ptr Music {.importc: "Mix_LoadMUS".} # Load a music file from an SDL_RWops object (Ogg and MikMod specific currently) # Matt Campbell (matt@campbellhome.dhs.org) April 2000 proc loadMUS_RW*(src: RWopsPtr; freesrc: cint): ptr Music {. importc: "Mix_LoadMUS_RW".} # Load a music file from an SDL_RWops object assuming a specific format proc loadMUSType_RW*(src: RWopsPtr; `type`: MusicType; freesrc: cint): ptr Music {. importc: "Mix_LoadMUSType_RW".} # Load a wave file of the mixer format from a memory buffer proc quickLoad_WAV*(mem: ptr uint8): ptr Chunk {.importc: "Mix_QuickLoad_WAV".} # Load raw audio data of the mixer format from a memory buffer proc quickLoad_RAW*(mem: ptr uint8; len: uint32): ptr Chunk {.importc: "Mix_QuickLoad_RAW".} # Free an audio chunk previously loaded proc freeChunk*(chunk: ptr Chunk) {.importc: "Mix_FreeChunk".} proc freeMusic*(music: ptr Music) {.importc: "Mix_FreeMusic".} # Get a list of chunk/music decoders that this build of SDL_mixer provides. # This list can change between builds AND runs of the program, if external # libraries that add functionality become available. # You must successfully call Mix_OpenAudio() before calling these functions. # This API is only available in SDL_mixer 1.2.9 and later. # # // usage... # int i; # const int total = Mix_GetNumChunkDecoders(); # for (i = 0; i < total; i++) # printf("Supported chunk decoder: [%s]\n", Mix_GetChunkDecoder(i)); # # Appearing in this list doesn't promise your specific audio file will # decode...but it's handy to know if you have, say, a functioning Timidity # install. # # These return values are static, read-only data; do not modify or free it. # The pointers remain valid until you call Mix_CloseAudio(). # proc getNumChunkDecoders*(): cint {.importc: "Mix_GetNumChunkDecoders".} proc getChunkDecoder*(index: cint): cstring {.importc: "Mix_GetChunkDecoder".} proc getNumMusicDecoders*(): cint {.importc: "Mix_GetNumMusicDecoders".} proc getMusicDecoder*(index: cint): cstring {.importc: "Mix_GetMusicDecoder".} # Find out the music format of a mixer music, or the currently playing # music, if 'music' is NULL. # proc getMusicType*(music: ptr Music): MusicType {.importc: "Mix_GetMusicType".} # Set a function that is called after all mixing is performed. # This can be used to provide real-time visual display of the audio stream # or add a custom mixer filter for the stream data. # proc setPostMix*(mix_func: proc (udata: pointer; stream: ptr uint8; len: cint) {.cdecl.}; arg: pointer) {.importc: "Mix_SetPostMix".} # Add your own music player or additional mixer function. # If 'mix_func' is NULL, the default music player is re-enabled. # proc hookMusic*(mix_func: proc (udata: pointer; stream: ptr uint8; len: cint) {. cdecl.}; arg: pointer) {.importc: "Mix_HookMusic".} # Add your own callback when the music has finished playing. # This callback is only called if the music finishes naturally. # proc hookMusicFinished*(music_finished: proc () {.cdecl.}) {.importc: "Mix_HookMusicFinished".} # Get a pointer to the user data for the current music hook proc getMusicHookData*(): pointer {.importc: "Mix_GetMusicHookData".} # # Add your own callback when a channel has finished playing. NULL # to disable callback. The callback may be called from the mixer's audio # callback or it could be called as a result of Mix_HaltChannel(), etc. # do not call SDL_LockAudio() from this callback; you will either be # inside the audio callback, or SDL_mixer will explicitly lock the audio # before calling your callback. # proc channelFinished*(channel_finished: proc (channel: cint) {.cdecl.}) {.importc: "Mix_ChannelFinished".} # Special Effects API by ryan c. gordon. (icculus@icculus.org) const MIX_CHANNEL_POST* = - 2 # This is the format of a special effect callback: # # myeffect(int chan, void *stream, int len, void *udata); # # (chan) is the channel number that your effect is affecting. (stream) is # the buffer of data to work upon. (len) is the size of (stream), and # (udata) is a user-defined bit of data, which you pass as the last arg of # Mix_RegisterEffect(), and is passed back unmolested to your callback. # Your effect changes the contents of (stream) based on whatever parameters # are significant, or just leaves it be, if you prefer. You can do whatever # you like to the buffer, though, and it will continue in its changed state # down the mixing pipeline, through any other effect functions, then finally # to be mixed with the rest of the channels and music for the final output # stream. # # DO NOT EVER call SDL_LockAudio() from your callback function! # type Mix_EffectFunc_t* = proc (chan: cint; stream: pointer; len: cint; udata: pointer) {.cdecl.} # # This is a callback that signifies that a channel has finished all its # loops and has completed playback. This gets called if the buffer # plays out normally, or if you call Mix_HaltChannel(), implicitly stop # a channel via Mix_AllocateChannels(), or unregister a callback while # it's still playing. # # DO NOT EVER call SDL_LockAudio() from your callback function! # type Mix_EffectDone_t* = proc (chan: cint; udata: pointer) {.cdecl.} # Register a special effect function. At mixing time, the channel data is # copied into a buffer and passed through each registered effect function. # After it passes through all the functions, it is mixed into the final # output stream. The copy to buffer is performed once, then each effect # function performs on the output of the previous effect. Understand that # this extra copy to a buffer is not performed if there are no effects # registered for a given chunk, which saves CPU cycles, and any given # effect will be extra cycles, too, so it is crucial that your code run # fast. Also note that the data that your function is given is in the # format of the sound device, and not the format you gave to Mix_OpenAudio(), # although they may in reality be the same. This is an unfortunate but # necessary speed concern. Use Mix_QuerySpec() to determine if you can # handle the data before you register your effect, and take appropriate # actions. # You may also specify a callback (Mix_EffectDone_t) that is called when # the channel finishes playing. This gives you a more fine-grained control # than Mix_ChannelFinished(), in case you need to free effect-specific # resources, etc. If you don't need this, you can specify NULL. # You may set the callbacks before or after calling Mix_PlayChannel(). # Things like Mix_SetPanning() are just internal special effect functions, # so if you are using that, you've already incurred the overhead of a copy # to a separate buffer, and that these effects will be in the queue with # any functions you've registered. The list of registered effects for a # channel is reset when a chunk finishes playing, so you need to explicitly # set them with each call to Mix_PlayChannel*(). # You may also register a special effect function that is to be run after # final mixing occurs. The rules for these callbacks are identical to those # in Mix_RegisterEffect, but they are run after all the channels and the # music have been mixed into a single stream, whereas channel-specific # effects run on a given channel before any other mixing occurs. These # global effect callbacks are call "posteffects". Posteffects only have # their Mix_EffectDone_t function called when they are unregistered (since # the main output stream is never "done" in the same sense as a channel). # You must unregister them manually when you've had enough. Your callback # will be told that the channel being mixed is (MIX_CHANNEL_POST) if the # processing is considered a posteffect. # # After all these effects have finished processing, the callback registered # through Mix_SetPostMix() runs, and then the stream goes to the audio # device. # # DO NOT EVER call SDL_LockAudio() from your callback function! # # returns zero if error (no such channel), nonzero if added. # Error messages can be retrieved from Mix_GetError(). # proc registerEffect*(chan: cint; f: Mix_EffectFunc_t; d: Mix_EffectDone_t; arg: pointer): cint {.importc: "Mix_RegisterEffect".} # You may not need to call this explicitly, unless you need to stop an # effect from processing in the middle of a chunk's playback. # Posteffects are never implicitly unregistered as they are for channels, # but they may be explicitly unregistered through this function by # specifying MIX_CHANNEL_POST for a channel. # returns zero if error (no such channel or effect), nonzero if removed. # Error messages can be retrieved from Mix_GetError(). # proc unregisterEffect*(channel: cint; f: Mix_EffectFunc_t): cint {.importc: "Mix_UnregisterEffect".} # You may not need to call this explicitly, unless you need to stop all # effects from processing in the middle of a chunk's playback. Note that # this will also shut off some internal effect processing, since # Mix_SetPanning() and others may use this API under the hood. This is # called internally when a channel completes playback. # Posteffects are never implicitly unregistered as they are for channels, # but they may be explicitly unregistered through this function by # specifying MIX_CHANNEL_POST for a channel. # returns zero if error (no such channel), nonzero if all effects removed. # Error messages can be retrieved from Mix_GetError(). # proc unregisterAllEffects*(channel: cint): cint {.importc: "Mix_UnregisterAllEffects".} const MIX_EFFECTSMAXSPEED* = "MIX_EFFECTSMAXSPEED" # # These are the internally-defined mixing effects. They use the same API that # effects defined in the application use, but are provided here as a # convenience. Some effects can reduce their quality or use more memory in # the name of speed; to enable this, make sure the environment variable # MIX_EFFECTSMAXSPEED (see above) is defined before you call # Mix_OpenAudio(). # # Set the panning of a channel. The left and right channels are specified # as integers between 0 and 255, quietest to loudest, respectively. # # Technically, this is just individual volume control for a sample with # two (stereo) channels, so it can be used for more than just panning. # If you want real panning, call it like this: # # Mix_SetPanning(channel, left, 255 - left); # # ...which isn't so hard. # # Setting (channel) to MIX_CHANNEL_POST registers this as a posteffect, and # the panning will be done to the final mixed stream before passing it on # to the audio device. # # This uses the Mix_RegisterEffect() API internally, and returns without # registering the effect function if the audio device is not configured # for stereo output. Setting both (left) and (right) to 255 causes this # effect to be unregistered, since that is the data's normal state. # # returns zero if error (no such channel or Mix_RegisterEffect() fails), # nonzero if panning effect enabled. Note that an audio device in mono # mode is a no-op, but this call will return successful in that case. # Error messages can be retrieved from Mix_GetError(). # proc setPanning*(channel: cint; left: uint8; right: uint8): cint {.importc: "Mix_SetPanning".} # Set the position of a channel. (angle) is an integer from 0 to 360, that # specifies the location of the sound in relation to the listener. (angle) # will be reduced as neccesary (540 becomes 180 degrees, -100 becomes 260). # Angle 0 is due north, and rotates clockwise as the value increases. # For efficiency, the precision of this effect may be limited (angles 1 # through 7 might all produce the same effect, 8 through 15 are equal, etc). # (distance) is an integer between 0 and 255 that specifies the space # between the sound and the listener. The larger the number, the further # away the sound is. Using 255 does not guarantee that the channel will be # culled from the mixing process or be completely silent. For efficiency, # the precision of this effect may be limited (distance 0 through 5 might # all produce the same effect, 6 through 10 are equal, etc). Setting (angle) # and (distance) to 0 unregisters this effect, since the data would be # unchanged. # # If you need more precise positional audio, consider using OpenAL for # spatialized effects instead of SDL_mixer. This is only meant to be a # basic effect for simple "3D" games. # # If the audio device is configured for mono output, then you won't get # any effectiveness from the angle; however, distance attenuation on the # channel will still occur. While this effect will function with stereo # voices, it makes more sense to use voices with only one channel of sound, # so when they are mixed through this effect, the positioning will sound # correct. You can convert them to mono through SDL before giving them to # the mixer in the first place if you like. # # Setting (channel) to MIX_CHANNEL_POST registers this as a posteffect, and # the positioning will be done to the final mixed stream before passing it # on to the audio device. # # This is a convenience wrapper over Mix_SetDistance() and Mix_SetPanning(). # # returns zero if error (no such channel or Mix_RegisterEffect() fails), # nonzero if position effect is enabled. # Error messages can be retrieved from Mix_GetError(). # proc setPosition*(channel: cint; angle: int16; distance: uint8): cint {.importc: "Mix_SetPosition".} # Set the "distance" of a channel. (distance) is an integer from 0 to 255 # that specifies the location of the sound in relation to the listener. # Distance 0 is overlapping the listener, and 255 is as far away as possible # A distance of 255 does not guarantee silence; in such a case, you might # want to try changing the chunk's volume, or just cull the sample from the # mixing process with Mix_HaltChannel(). # For efficiency, the precision of this effect may be limited (distances 1 # through 7 might all produce the same effect, 8 through 15 are equal, etc). # (distance) is an integer between 0 and 255 that specifies the space # between the sound and the listener. The larger the number, the further # away the sound is. # Setting (distance) to 0 unregisters this effect, since the data would be # unchanged. # If you need more precise positional audio, consider using OpenAL for # spatialized effects instead of SDL_mixer. This is only meant to be a # basic effect for simple "3D" games. # # Setting (channel) to MIX_CHANNEL_POST registers this as a posteffect, and # the distance attenuation will be done to the final mixed stream before # passing it on to the audio device. # # This uses the Mix_RegisterEffect() API internally. # # returns zero if error (no such channel or Mix_RegisterEffect() fails), # nonzero if position effect is enabled. # Error messages can be retrieved from Mix_GetError(). # proc setDistance*(channel: cint; distance: uint8): cint {.importc: "Mix_SetDistance".} # # !!! FIXME : Haven't implemented, since the effect goes past the # end of the sound buffer. Will have to think about this. # --ryan. # when false: # Causes an echo effect to be mixed into a sound. (echo) is the amount # of echo to mix. 0 is no echo, 255 is infinite (and probably not # what you want). # # Setting (channel) to MIX_CHANNEL_POST registers this as a posteffect, and # the reverbing will be done to the final mixed stream before passing it on # to the audio device. # # This uses the Mix_RegisterEffect() API internally. If you specify an echo # of zero, the effect is unregistered, as the data is already in that state. # # returns zero if error (no such channel or Mix_RegisterEffect() fails), # nonzero if reversing effect is enabled. # Error messages can be retrieved from Mix_GetError(). # proc setReverb*(channel: cint; echo: uint8): cint {.importc: "Mix_SetReverb".} # Causes a channel to reverse its stereo. This is handy if the user has his # speakers hooked up backwards, or you would like to have a minor bit of # psychedelia in your sound code. :) Calling this function with (flip) # set to non-zero reverses the chunks's usual channels. If (flip) is zero, # the effect is unregistered. # # This uses the Mix_RegisterEffect() API internally, and thus is probably # more CPU intensive than having the user just plug in his speakers # correctly. Mix_SetReverseStereo() returns without registering the effect # function if the audio device is not configured for stereo output. # # If you specify MIX_CHANNEL_POST for (channel), then this the effect is used # on the final mixed stream before sending it on to the audio device (a # posteffect). # # returns zero if error (no such channel or Mix_RegisterEffect() fails), # nonzero if reversing effect is enabled. Note that an audio device in mono # mode is a no-op, but this call will return successful in that case. # Error messages can be retrieved from Mix_GetError(). # proc setReverseStereo*(channel: cint; flip: cint): cint {.importc: "Mix_SetReverseStereo".} # end of effects API. --ryan. # Reserve the first channels (0 -> n-1) for the application, i.e. don't allocate # them dynamically to the next sample if requested with a -1 value below. # Returns the number of reserved channels. # proc reserveChannels*(num: cint): cint {.importc: "Mix_ReserveChannels".} # Channel grouping functions # Attach a tag to a channel. A tag can be assigned to several mixer # channels, to form groups of channels. # If 'tag' is -1, the tag is removed (actually -1 is the tag used to # represent the group of all the channels). # Returns true if everything was OK. # proc groupChannel*(which: cint; tag: cint): cint {.importc: "Mix_GroupChannel".} # Assign several consecutive channels to a group proc groupChannels*(`from`: cint; to: cint; tag: cint): cint {.importc: "Mix_GroupChannels".} # Finds the first available channel in a group of channels, # returning -1 if none are available. # proc groupAvailable*(tag: cint): cint {.importc: "Mix_GroupAvailable".} # Returns the number of channels in a group. This is also a subtle # way to get the total number of channels when 'tag' is -1 # proc groupCount*(tag: cint): cint {.importc: "Mix_GroupCount".} # Finds the "oldest" sample playing in a group of channels proc groupOldest*(tag: cint): cint {.importc: "Mix_GroupOldest".} # Finds the "most recent" (i.e. last) sample playing in a group of channels proc groupNewer*(tag: cint): cint {.importc: "Mix_GroupNewer".} # Play an audio chunk on a specific channel. # If the specified channel is -1, play on the first free channel. # If 'loops' is greater than zero, loop the sound that many times. # If 'loops' is -1, loop inifinitely (~65000 times). # The sound is played at most 'ticks' milliseconds. If -1, play forever. # Returns which channel was used to play the sound. # proc playChannelTimed*(channel: cint; chunk: ptr Chunk; loops: cint; ticks: cint): cint {.importc: "Mix_PlayChannelTimed".} # The same as above, but the sound is played forever template playChannel*(channel, chunk, loops: untyped): untyped = playChannelTimed(channel, chunk, loops, - 1) proc playMusic*(music: ptr Music; loops: cint): cint {.importc: "Mix_PlayMusic".} # Fade in music or a channel over "ms" milliseconds, same semantics as the "Play" functions proc fadeInMusic*(music: ptr Music; loops: cint; ms: cint): cint {.importc: "Mix_FadeInMusic".} proc fadeInMusicPos*(music: ptr Music; loops: cint; ms: cint; position: cdouble): cint {.importc: "Mix_FadeInMusicPos".} template fadeInChannel*(channel, chunk, loops, ms: untyped): untyped = fadeInChannelTimed(channel, chunk, loops, ms, - 1) proc fadeInChannelTimed*(channel: cint; chunk: ptr Chunk; loops: cint; ms: cint; ticks: cint): cint {.importc: "Mix_FadeInChannelTimed".} # Set the volume in the range of 0-128 of a specific channel or chunk. # If the specified channel is -1, set volume for all channels. # Returns the original volume. # If the specified volume is -1, just return the current volume. # proc volume*(channel: cint; volume: cint): cint {.importc: "Mix_Volume".} proc volumeChunk*(chunk: ptr Chunk; volume: cint): cint {.importc: "Mix_VolumeChunk".} proc volumeMusic*(volume: cint): cint {.importc: "Mix_VolumeMusic".} # Halt playing of a particular channel proc haltChannel*(channel: cint): cint {.importc: "Mix_HaltChannel".} proc haltGroup*(tag: cint): cint {.importc: "Mix_HaltGroup".} proc haltMusic*(): cint {.importc: "Mix_HaltMusic".} # Change the expiration delay for a particular channel. # The sample will stop playing after the 'ticks' milliseconds have elapsed, # or remove the expiration if 'ticks' is -1 # proc expireChannel*(channel: cint; ticks: cint): cint {.importc: "Mix_ExpireChannel".} # Halt a channel, fading it out progressively till it's silent # The ms parameter indicates the number of milliseconds the fading # will take. # proc fadeOutChannel*(which: cint; ms: cint): cint {.importc: "Mix_FadeOutChannel".} proc fadeOutGroup*(tag: cint; ms: cint): cint {.importc: "Mix_FadeOutGroup".} proc fadeOutMusic*(ms: cint): cint {.importc: "Mix_FadeOutMusic".} # Query the fading status of a channel proc fadingMusic*(): Fading {.importc: "Mix_FadingMusic".} proc fadingChannel*(which: cint): Fading {.importc: "Mix_FadingChannel".} # Pause/Resume a particular channel proc pause*(channel: cint) {.importc: "Mix_Pause".} proc resume*(channel: cint) {.importc: "Mix_Resume".} proc paused*(channel: cint): cint {.importc: "Mix_Paused".} # Pause/Resume the music stream proc pauseMusic*() {.importc: "Mix_PauseMusic".} proc resumeMusic*() {.importc: "Mix_ResumeMusic".} proc rewindMusic*() {.importc: "Mix_RewindMusic".} proc pausedMusic*(): cint {.importc: "Mix_PausedMusic".} # Set the current position in the music stream. # This returns 0 if successful, or -1 if it failed or isn't implemented. # This function is only implemented for MOD music formats (set pattern # order number) and for OGG, FLAC, MP3_MAD, and MODPLUG music (set # position in seconds), at the moment. # proc setMusicPosition*(position: cdouble): cint {.importc: "Mix_SetMusicPosition".} # Check the status of a specific channel. # If the specified channel is -1, check all channels. # proc playing*(channel: cint): cint {.importc: "Mix_Playing".} proc playingMusic*(): cint {.importc: "Mix_PlayingMusic".} # Stop music and set external music playback command proc setMusicCMD*(command: cstring): cint {.importc: "Mix_SetMusicCMD".} # Synchro value is set by MikMod from modules while playing proc setSynchroValue*(value: cint): cint {.importc: "Mix_SetSynchroValue".} proc getSynchroValue*(): cint {.importc: "Mix_GetSynchroValue".} # Set/Get/Iterate SoundFonts paths to use by supported MIDI backends proc setSoundFonts*(paths: cstring): cint {. importc: "Mix_SetSoundFonts".} proc getSoundFonts*(): cstring {.importc: "Mix_GetSoundFonts".} proc eachSoundFont*(function: proc (a2: cstring; a3: pointer): cint {.cdecl.}; data: pointer): cint {.importc: "Mix_EachSoundFont".} # Get the Chunk currently associated with a mixer channel # Returns NULL if it's an invalid channel, or there's no chunk associated. # proc getChunk*(channel: cint): ptr Chunk {.importc: "Mix_GetChunk".} # Close the mixer, halting all playing audio proc closeAudio*() {.importc: "Mix_CloseAudio".} when not defined(SDL_Static): {.pop.}