1 /****************************************************************************
3 * ____ ___ ____ __ ______ ___ ____ ____/ / *
4 * / __ `__ \/ __ `/ |/ / __ `__ \/ __ \/ __ / *
5 * / / / / / / /_/ /> </ / / / / / /_/ / /_/ / *
6 * /_/ /_/ /_/\__,_/_/|_/_/ /_/ /_/\____/\__,_/ *
8 * Sound Effect System *
10 * Copyright (c) 2008, Mukunda Johnson (mukunda@maxmod.org) *
12 * Permission to use, copy, modify, and/or distribute this software for any *
13 * purpose with or without fee is hereby granted, provided that the above *
14 * copyright notice and this permission notice appear in all copies. *
16 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
17 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
18 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
19 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
21 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
22 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
23 ****************************************************************************/
25 #include "mp_defs.inc"
27 #include "mp_mas_structs.inc"
28 #include "mp_format_mas.inc"
29 #include "mp_macros.inc"
32 #include "mp_mixer_gba.inc"
36 #include "mp_mixer_ds.inc"
39 /***********************************************************************
43 ***********************************************************************/
45 .struct 0 // mm_sound_effect
46 MM_SFX_SOURCE: .space 4 // word: source
47 MM_SFX_RATE: .space 2 // hword: rate
48 MM_SFX_HANDLE: .space 2 // byte: handle
49 MM_SFX_VOLUME: .space 1 // byte: volume
50 MM_SFX_PANNING: .space 1 // byte: panning
51 MM_SFX_SIZE: // 8 bytes total
54 .equ releaseLevel, 200
56 /***********************************************************************
60 ***********************************************************************/
64 .GLOBAL mm_sfx_bitmask, mm_sfx_clearmask
66 mm_sfx_mastervolume: .space 4
67 mm_sfx_channels: .space 2*channelCount
68 mm_sfx_bitmask: .space 4
69 mm_sfx_clearmask: .space 4
71 mm_sfx_counter: .space 1
73 /***********************************************************************
77 ***********************************************************************/
83 /***********************************************************************
85 ***********************************************************************/
86 .global mmResetEffects
92 ldr r2,=mm_sfx_channels
99 ldr r2,=mm_sfx_bitmask
104 /***********************************************************************
105 * mmGetFreeEffectChannel()
107 * Return index to free effect channel
108 ***********************************************************************/
110 mmGetFreeEffectChannel:
112 ldr r0,=mm_sfx_bitmask // r0 = bitmask
114 mov r1, #1 // r1 = channel counter
116 .channel_search: // shift out bits until we find a cleared one
118 bcc .found_channel //
119 add r1, #1 // r1 = index value
124 cmp r1, #channelCount+1 // if r1 == cc+1 then r1 = 0 (no handles avail.)
125 bne .found_valid_channel //
127 .found_valid_channel: //
129 mov r0, r1 // return value
132 /***********************************************************************
135 * Play sound effect with default parameters
136 ***********************************************************************/
142 mov r1, #1 // r1 = hhhhrrrr
144 ldr r2,=0x000080FF // r2 = ----ppvv
146 push {r0-r2} // mmEffectEx( sound )
153 /***********************************************************************
154 * mmEffectEx( sound )
156 * Play sound effect with specified parameters
157 ***********************************************************************/
165 ldrh r5, [r4, #MM_SFX_HANDLE] // test if handle was given
173 beq .generate_new_handle //
175 lsl r1, r5, #24 // check if channel is in use
178 ldr r0,=mm_sfx_channels //
181 beq .got_handle // [valid handle otherwise]
184 bl mmEffectCancel // attempt to stop active channel
187 // failure: generate new handle
188 .generate_new_handle:
190 bl mmGetFreeEffectChannel // generate handle
192 beq .got_handle //-(no available channels)
194 ldr r0,=mm_sfx_counter // (counter = ((counter+1) & 255))
205 ldr r1,=mmAllocChannel // allocate new channel
208 bge .no_available_channels //
215 ldr r1,=mm_sfx_channels // register data
216 sub r2, r5, #1 // r3 = bit
228 ldr r1,=mm_sfx_bitmask // set bit
235 ldr r1,=mm_achannels // setup channel
241 mov r2, #releaseLevel //
242 strb r2, [r1, #MCA_FVOL] //
246 mov r2, #ACHN_BACKGROUND //
248 1: mov r2, #ACHN_CUSTOM //
250 strb r2, [r1, #MCA_TYPE] //
251 mov r2, #MCAF_EFFECT //
252 strb r2, [r1, #MCA_FLAGS] //
254 GET_MIXCH r1 // setup voice
255 mov r2, #MIXER_CHN_SIZE //
261 ldr r0,=mp_solution // set sample data address
263 ldrh r1, [r4, #MM_SFX_SOURCE] //
268 ldrh r2, [r1, #8+C_SAMPLEC_DFREQ] //
269 add r1, #8+C_SAMPLE_DATA //
270 str r1, [r3, #MIXER_CHN_SRC] //
272 ldrh r0, [r4, #MM_SFX_RATE] // set pitch to original * pitch
275 str r2, [r3, #MIXER_CHN_FREQ] //
277 mov r1, #0 // reset read position
278 str r1, [r3, #MIXER_CHN_READ] //
280 ldrb r0, [r4, #MM_SFX_VOLUME] // set volume
282 ldr r1,=mm_sfx_mastervolume
287 strb r0, [r3, #MIXER_CHN_VOL] //
289 ldrb r0, [r4, #MM_SFX_PANNING] // set panning
290 strb r0, [r3, #MIXER_CHN_PAN] //
293 ldr r1, [r4, #MM_SFX_SOURCE] // set sample address
294 lsr r0, r1, #16 // > 0x10000 = external sample
296 ldr r0,=mmSampleBank // ID# otherwise
307 str r1, [r3, #MIXER_CHN_SAMP] //
310 ldrh r0, [r4, #MM_SFX_RATE] // set pitch to original * pitch
311 ldrh r1, [r1, #C_SAMPLEC_DFREQ] //
314 strh r1, [r3, #MIXER_CHN_FREQ] //
316 mov r1, #0 // clear sample offset
317 str r1, [r3, #MIXER_CHN_READ] //
319 ldrb r1, [r4, #MM_SFX_PANNING] // set panning + startbit
322 strb r1, [r3, #MIXER_CHN_CNT] //
324 ldrb r1, [r4, #MM_SFX_VOLUME] // set volume
325 ldr r0,=mm_sfx_mastervolume
332 strh r2, [r3, #MIXER_CHN_VOL] //
337 str r0, [r3, #MIXER_CHN_SAMP]
343 mov r0, r5 // return handle
347 .no_available_channels:
348 mov r0, #0 // return bad
354 /***********************************************************************
355 * mme_get_channel_index
357 * Test handle and return mixing channel index
358 ***********************************************************************/
360 mme_get_channel_index:
362 lsl r1, r0, #24 // mask and test channel#
365 beq .invalid_handle //
366 cmp r1, #channelCount*2 //
367 bgt .invalid_handle //
369 ldr r2,=mm_sfx_channels-2 // check if instances match
374 bne .invalid_handle //
376 lsl r3, #24 // mask channel#
381 .invalid_handle: // return invalid handle
386 /***********************************************************************
387 * mmEffectActive( handle )
389 * Indicates if a sound effect is active or not
390 ***********************************************************************/
391 .global mmEffectActive
395 bl mme_get_channel_index //
396 cmp r3, #0 // if r3 >= 0, it is active
398 mov r0, #0 // return false
403 mov r0, #1 // return true
407 /***********************************************************************
408 * mme_clear_channel(ch)
410 * Clear channel entry and bitmask
412 ***********************************************************************/
416 ldr r2,=mm_sfx_channels // clear effect channel
420 mov r1, #1 // clear effect bitmask
423 ldr r2,=mm_sfx_bitmask //
432 /***********************************************************************
433 * mmEffectVolume( handle, volume )
438 ***********************************************************************/
439 .global mmEffectVolume
445 bl mme_get_channel_index
449 ldr r0,=mm_sfx_mastervolume
471 /***********************************************************************
472 * mmEffectPanning( handle, panning )
477 ***********************************************************************/
478 .global mmEffectPanning
483 bl mme_get_channel_index
492 /***********************************************************************
493 * mmEffectRate( handle, rate )
495 * Set effect playback rate
496 ***********************************************************************/
502 bl mme_get_channel_index
511 /***********************************************************************
512 * mmEffectCancel( handle )
515 ***********************************************************************/
516 .global mmEffectCancel
522 bl mme_get_channel_index
528 mov r1, #MCA_SIZE // free achannel
530 ldr r2,=mm_achannels //
533 mov r1, #ACHN_BACKGROUND //
534 strb r1, [r2, #MCA_TYPE] //
536 strb r1, [r2, #MCA_FVOL] // clear volume for channel allocator
543 mov r1, #0 // zero voice volume
545 bl mmMixerSetVolume //
553 /***********************************************************************
554 * mmEffectRelease( channel )
556 * Release sound effect (allow interruption)
557 ***********************************************************************/
558 .global mmEffectRelease
564 bl mme_get_channel_index
569 mov r1, #MCA_SIZE // release achannel
571 ldr r2,=mm_achannels //
574 mov r1, #ACHN_BACKGROUND //
575 strb r1, [r2, #MCA_TYPE] //
584 /***********************************************************************
585 * mmEffectScaleRate( channel, factor )
587 * Scale sampling rate by 6.10 factor
588 ***********************************************************************/
589 .global mmEffectScaleRate
595 bl mme_get_channel_index
605 /***********************************************************************
606 * mmSetEffectsVolume( volume )
608 * set master volume scale, 0->1024
609 ***********************************************************************/
610 .global mmSetEffectsVolume
619 1: ldr r1,=mm_sfx_mastervolume
623 /***********************************************************************
624 * mmEffectCancelAll()
626 * Stop all sound effects
627 ***********************************************************************/
628 .global mmEffectCancelAll
634 ldr r4,=mm_sfx_bitmask
636 ldr r6,=mm_sfx_channels
652 ldr r0,=mm_achannels // free achannel
657 mov r1, #ACHN_BACKGROUND //
658 strb r1, [r0, #MCA_TYPE] //
660 strb r1, [r0, #MCA_FVOL] //
674 /***********************************************************************
677 * Update sound effects
678 ***********************************************************************/
679 .global mmUpdateEffects
685 ldr r4,=mm_sfx_bitmask
687 ldr r6,=mm_sfx_channels
694 ldrb r0, [r6, r5] // get channel index
700 mov r2, #MIXER_CHN_SIZE // get mixing channel pointer
704 #ifdef SYS_NDS // test if channel is still active
706 ldr r2, [r1, #MIXER_CHN_SAMP] //
712 ldr r2, [r1, #MIXER_CHN_SRC] //
718 ldr r1,=mm_achannels // free achannel
724 strb r0, [r1, #MCA_TYPE] //
725 strb r0, [r1, #MCA_FLAGS] //
729 add r5, #2 // look for another set bit
731 bcs .process_channel //
734 bcs .process_channel //
739 lsl r5, #32-channelCount
740 ldr r6,=mm_sfx_channels
749 bne .build_new_bitmask
751 lsr r4, #32-channelCount
752 ldr r0,=mm_sfx_bitmask
753 ldr r1, [r0] // r1 = bits that change from 1->0
761 str r4, [r0, #4] // write 1->0 mask