/*---------------------------------------------------------------------------* Project: Mixer application for AX File: mix.c Copyright (C)1998-2006 Nintendo All Rights Reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Log: mix.c,v $ Revision 1.12.4.1 2007/09/13 04:05:14 aka For SDK3.1 patch1. Revision 1.14 2007/08/08 02:45:02 aka Modified MIXInitSpecifyMem() to check __init flag. Revision 1.13 2007/08/08 00:22:02 aka Modified MIXInit() to check __init flag. Revision 1.12 2006/12/22 05:23:36 aka Removed __MIXAIVolumeTable[]. Revision 1.11 2006/11/13 00:35:11 aka Added initialization of axvpb. Revision 1.10 2006/10/23 01:51:45 aka Rolled-back MIXInit(). Added MIXInitSpecifyMem(). Revision 1.9 2006/10/10 05:19:39 aka Removed MIXSetMemory(). Revised MIXInit(). Revision 1.8 2006/10/10 00:56:07 aka Added checking initialization. Revision 1.7 2006/10/06 08:07:08 aka Added MIXSetMemory(). Revision 1.6 2006/07/24 09:11:22 aka Added initialization of remote speaker params. Revision 1.5 2006/07/19 07:51:45 aka Modified to support controller speakers. Revision 1.4 2006/06/20 00:33:03 aka Revised aux settings when DPL2 mode. Revision 1.3 2006/02/01 02:07:17 aka Modified some if statements to remove warning when building. Revision 1.2 2005/11/08 01:39:32 aka Changed suiting to Revolution's audio spec. Revision 1.1.1.1 2005/05/12 02:15:49 yasuh-to Imported from dolphin tree. 10 2003/02/10 1:46p Akagi Removed some blank lines at the file end. 9 2003/02/02 5:53p Akagi Revised attenuation of S buffer from -6dB to -3dB. Added -3dB attenuation of S buffer to MIXInitChannel(). 8 2002/04/11 1:01p Billyjack - changes for DPL2 4 buss AUX send - removed (static) statements, no change in function 7 2002/01/08 6:42p Billyjack - Added DPL2 support 6 2001/08/28 4:44p Billyjack added : c->mode &= ~MIX_MODE_UPDATE_INPUT; was missing 5 2001/06/04 3:23p Billyjack Changed to init mixer in stereo mode by default. 4 2001/05/30 3:08p Billyjack - added MIXSetSoundMode() to set mixer in mono or stereo mode - then mixer will initialize into proper mode by calling OSGetSoundMode() 3 2001/05/21 3:15p Billyjack 2 2001/05/09 5:05p Billyjack Fixed bug with setting mixerctrl flag for AUX surround... also fixed -6dB for S buffer for MIXInitChannel() 1 2001/05/09 1:12p Billyjack Created $NoKeywords: $ *---------------------------------------------------------------------------*/ #include #include #include #include "mixprivate.h" /*---------------------------------------------------------------------------* Multipliers for DSP audio application in .1 dBs from -90.4 dB to +6 dB, volume expressed in 1.15 fixed point, 0x8000 = 1.0 *---------------------------------------------------------------------------*/ static u16 __MIXVolumeTable[965] = { 0x0000, // -90.4 = inf 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000f, 0x000f, 0x000f, 0x000f, 0x000f, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0011, 0x0011, 0x0011, 0x0011, 0x0011, 0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0014, 0x0014, 0x0014, 0x0014, 0x0015, 0x0015, 0x0015, 0x0015, 0x0016, 0x0016, 0x0016, 0x0016, 0x0017, 0x0017, 0x0017, 0x0018, 0x0018, 0x0018, 0x0018, 0x0019, 0x0019, 0x0019, 0x001a, 0x001a, 0x001a, 0x001a, 0x001b, 0x001b, 0x001b, 0x001c, 0x001c, 0x001c, 0x001d, 0x001d, 0x001d, 0x001e, 0x001e, 0x001e, 0x001f, 0x001f, 0x0020, 0x0020, 0x0020, 0x0021, 0x0021, 0x0021, 0x0022, 0x0022, 0x0023, 0x0023, 0x0023, 0x0024, 0x0024, 0x0025, 0x0025, 0x0026, 0x0026, 0x0026, 0x0027, 0x0027, 0x0028, 0x0028, 0x0029, 0x0029, 0x002a, 0x002a, 0x002b, 0x002b, 0x002c, 0x002c, 0x002d, 0x002d, 0x002e, 0x002e, 0x002f, 0x002f, 0x0030, 0x0031, 0x0031, 0x0032, 0x0032, 0x0033, 0x0033, 0x0034, 0x0035, 0x0035, 0x0036, 0x0037, 0x0037, 0x0038, 0x0038, 0x0039, 0x003a, 0x003a, 0x003b, 0x003c, 0x003d, 0x003d, 0x003e, 0x003f, 0x003f, 0x0040, 0x0041, 0x0042, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x006a, 0x006b, 0x006c, 0x006d, 0x006f, 0x0070, 0x0071, 0x0072, 0x0074, 0x0075, 0x0076, 0x0078, 0x0079, 0x007b, 0x007c, 0x007e, 0x007f, 0x0080, 0x0082, 0x0083, 0x0085, 0x0087, 0x0088, 0x008a, 0x008b, 0x008d, 0x008f, 0x0090, 0x0092, 0x0094, 0x0095, 0x0097, 0x0099, 0x009b, 0x009c, 0x009e, 0x00a0, 0x00a2, 0x00a4, 0x00a6, 0x00a8, 0x00aa, 0x00ab, 0x00ad, 0x00af, 0x00b2, 0x00b4, 0x00b6, 0x00b8, 0x00ba, 0x00bc, 0x00be, 0x00c0, 0x00c3, 0x00c5, 0x00c7, 0x00ca, 0x00cc, 0x00ce, 0x00d1, 0x00d3, 0x00d6, 0x00d8, 0x00db, 0x00dd, 0x00e0, 0x00e2, 0x00e5, 0x00e7, 0x00ea, 0x00ed, 0x00f0, 0x00f2, 0x00f5, 0x00f8, 0x00fb, 0x00fe, 0x0101, 0x0104, 0x0107, 0x010a, 0x010d, 0x0110, 0x0113, 0x0116, 0x011a, 0x011d, 0x0120, 0x0124, 0x0127, 0x012a, 0x012e, 0x0131, 0x0135, 0x0138, 0x013c, 0x0140, 0x0143, 0x0147, 0x014b, 0x014f, 0x0153, 0x0157, 0x015b, 0x015f, 0x0163, 0x0167, 0x016b, 0x016f, 0x0173, 0x0178, 0x017c, 0x0180, 0x0185, 0x0189, 0x018e, 0x0193, 0x0197, 0x019c, 0x01a1, 0x01a6, 0x01ab, 0x01af, 0x01b4, 0x01ba, 0x01bf, 0x01c4, 0x01c9, 0x01ce, 0x01d4, 0x01d9, 0x01df, 0x01e4, 0x01ea, 0x01ef, 0x01f5, 0x01fb, 0x0201, 0x0207, 0x020d, 0x0213, 0x0219, 0x021f, 0x0226, 0x022c, 0x0232, 0x0239, 0x0240, 0x0246, 0x024d, 0x0254, 0x025b, 0x0262, 0x0269, 0x0270, 0x0277, 0x027e, 0x0286, 0x028d, 0x0295, 0x029d, 0x02a4, 0x02ac, 0x02b4, 0x02bc, 0x02c4, 0x02cc, 0x02d5, 0x02dd, 0x02e6, 0x02ee, 0x02f7, 0x0300, 0x0309, 0x0312, 0x031b, 0x0324, 0x032d, 0x0337, 0x0340, 0x034a, 0x0354, 0x035d, 0x0367, 0x0371, 0x037c, 0x0386, 0x0390, 0x039b, 0x03a6, 0x03b1, 0x03bb, 0x03c7, 0x03d2, 0x03dd, 0x03e9, 0x03f4, 0x0400, 0x040c, 0x0418, 0x0424, 0x0430, 0x043d, 0x0449, 0x0456, 0x0463, 0x0470, 0x047d, 0x048a, 0x0498, 0x04a5, 0x04b3, 0x04c1, 0x04cf, 0x04dd, 0x04ec, 0x04fa, 0x0509, 0x0518, 0x0527, 0x0536, 0x0546, 0x0555, 0x0565, 0x0575, 0x0586, 0x0596, 0x05a6, 0x05b7, 0x05c8, 0x05d9, 0x05eb, 0x05fc, 0x060e, 0x0620, 0x0632, 0x0644, 0x0657, 0x066a, 0x067d, 0x0690, 0x06a4, 0x06b7, 0x06cb, 0x06df, 0x06f4, 0x0708, 0x071d, 0x0732, 0x0748, 0x075d, 0x0773, 0x0789, 0x079f, 0x07b6, 0x07cd, 0x07e4, 0x07fb, 0x0813, 0x082b, 0x0843, 0x085c, 0x0874, 0x088e, 0x08a7, 0x08c1, 0x08da, 0x08f5, 0x090f, 0x092a, 0x0945, 0x0961, 0x097d, 0x0999, 0x09b5, 0x09d2, 0x09ef, 0x0a0d, 0x0a2a, 0x0a48, 0x0a67, 0x0a86, 0x0aa5, 0x0ac5, 0x0ae5, 0x0b05, 0x0b25, 0x0b47, 0x0b68, 0x0b8a, 0x0bac, 0x0bcf, 0x0bf2, 0x0c15, 0x0c39, 0x0c5d, 0x0c82, 0x0ca7, 0x0ccc, 0x0cf2, 0x0d19, 0x0d3f, 0x0d67, 0x0d8e, 0x0db7, 0x0ddf, 0x0e08, 0x0e32, 0x0e5c, 0x0e87, 0x0eb2, 0x0edd, 0x0f09, 0x0f36, 0x0f63, 0x0f91, 0x0fbf, 0x0fee, 0x101d, 0x104d, 0x107d, 0x10ae, 0x10df, 0x1111, 0x1144, 0x1177, 0x11ab, 0x11df, 0x1214, 0x124a, 0x1280, 0x12b7, 0x12ee, 0x1326, 0x135f, 0x1399, 0x13d3, 0x140d, 0x1449, 0x1485, 0x14c2, 0x14ff, 0x153e, 0x157d, 0x15bc, 0x15fd, 0x163e, 0x1680, 0x16c3, 0x1706, 0x174a, 0x178f, 0x17d5, 0x181c, 0x1863, 0x18ac, 0x18f5, 0x193f, 0x198a, 0x19d5, 0x1a22, 0x1a6f, 0x1abe, 0x1b0d, 0x1b5d, 0x1bae, 0x1c00, 0x1c53, 0x1ca7, 0x1cfc, 0x1d52, 0x1da9, 0x1e01, 0x1e5a, 0x1eb4, 0x1f0f, 0x1f6b, 0x1fc8, 0x2026, 0x2086, 0x20e6, 0x2148, 0x21aa, 0x220e, 0x2273, 0x22d9, 0x2341, 0x23a9, 0x2413, 0x247e, 0x24ea, 0x2557, 0x25c6, 0x2636, 0x26a7, 0x271a, 0x278e, 0x2803, 0x287a, 0x28f2, 0x296b, 0x29e6, 0x2a62, 0x2ae0, 0x2b5f, 0x2bdf, 0x2c61, 0x2ce5, 0x2d6a, 0x2df1, 0x2e79, 0x2f03, 0x2f8e, 0x301b, 0x30aa, 0x313a, 0x31cc, 0x325f, 0x32f5, 0x338c, 0x3425, 0x34bf, 0x355b, 0x35fa, 0x369a, 0x373c, 0x37df, 0x3885, 0x392c, 0x39d6, 0x3a81, 0x3b2f, 0x3bde, 0x3c90, 0x3d43, 0x3df9, 0x3eb1, 0x3f6a, 0x4026, 0x40e5, 0x41a5, 0x4268, 0x432c, 0x43f4, 0x44bd, 0x4589, 0x4657, 0x4727, 0x47fa, 0x48d0, 0x49a8, 0x4a82, 0x4b5f, 0x4c3e, 0x4d20, 0x4e05, 0x4eec, 0x4fd6, 0x50c3, 0x51b2, 0x52a4, 0x5399, 0x5491, 0x558c, 0x5689, 0x578a, 0x588d, 0x5994, 0x5a9d, 0x5baa, 0x5cba, 0x5dcd, 0x5ee3, 0x5ffc, 0x6119, 0x6238, 0x635c, 0x6482, 0x65ac, 0x66d9, 0x680a, 0x693f, 0x6a77, 0x6bb2, 0x6cf2, 0x6e35, 0x6f7b, 0x70c6, 0x7214, 0x7366, 0x74bc, 0x7616, 0x7774, 0x78d6, 0x7a3d, 0x7ba7, 0x7d16, 0x7e88, 0x7fff, 0x817b, 0x82fb, 0x847f, 0x8608, 0x8795, 0x8927, 0x8abe, 0x8c59, 0x8df9, 0x8f9e, 0x9148, 0x92f6, 0x94aa, 0x9663, 0x9820, 0x99e3, 0x9bab, 0x9d79, 0x9f4c, 0xa124, 0xa302, 0xa4e5, 0xa6ce, 0xa8bc, 0xaab0, 0xacaa, 0xaeaa, 0xb0b0, 0xb2bc, 0xb4ce, 0xb6e5, 0xb904, 0xbb28, 0xbd53, 0xbf84, 0xc1bc, 0xc3fa, 0xc63f, 0xc88b, 0xcadd, 0xcd37, 0xcf97, 0xd1fe, 0xd46d, 0xd6e3, 0xd960, 0xdbe4, 0xde70, 0xe103, 0xe39e, 0xe641, 0xe8eb, 0xeb9e, 0xee58, 0xf11b, 0xf3e6, 0xf6b9, 0xf994, 0xfc78, 0xff64 }; // Attenuation table for left panning in .1 dB. static int __MIXPanTable[128] = { 0, 0, -1, -1, -1, -2, -2, -2, -3, -3, -4, -4, -4, -5, -5, -5, -6, -6, -7, -7, -7, -8, -8, -9, -9, -10, -10, -10, -11, -11, -12, -12, -13, -13, -14, -14, -14, -15, -15, -16, -16, -17, -17, -18, -18, -19, -20, -20, -21, -21, -22, -22, -23, -23, -24, -25, -25, -26, -26, -27, -28, -28, -29, -30, -30, -31, -32, -33, -33, -34, -35, -36, -36, -37, -38, -39, -40, -40, -41, -42, -43, -44, -45, -46, -47, -48, -49, -50, -51, -52, -54, -55, -56, -57, -59, -60, -61, -63, -64, -66, -67, -69, -71, -72, -74, -76, -78, -80, -83, -85, -87, -90, -93, -96, -99, -102, -106, -110, -115, -120, -126, -133, -140, -150, -163, -180, -210, -904 }; // Panning tables for Pro Logic 2. // cos(pi/2 * n) static s16 __MIX_DPL2_front[128] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -3, -3, -3, -4, -4, -4, -5, -5, -6, -6, -6, -7, -7, -8, -8, -9, -9, -10, -11, -11, -12, -12, -13, -14, -14, -15, -16, -17, -17, -18, -19, -20, -21, -21, -22, -23, -24, -25, -26, -27, -28, -29, -30, -31, -32, -34, -35, -36, -37, -38, -40, -41, -42, -44, -45, -47, -48, -50, -52, -53, -55, -57, -58, -60, -62, -64, -66, -68, -70, -73, -75, -77, -80, -82, -85, -88, -90, -93, -96, -100, -103, -106, -110, -114, -118, -122, -126, -131, -136, -141, -146, -152, -159, -166, -173, -181, -190, -201, -212, -225, -241, -261, -286, -321, -381, -960 }; // cos(pi/2 * (k1 + k2n)) static s16 __MIX_DPL2_rear[128] = { -61, -61, -60, -59, -59, -58, -58, -57, -56, -56, -55, -55, -54, -53, -53, -52, -52, -51, -50, -50, -49, -49, -48, -48, -47, -47, -46, -46, -45, -45, -44, -44, -43, -43, -42, -42, -41, -41, -40, -40, -39, -39, -38, -38, -38, -37, -37, -36, -36, -35, -35, -35, -34, -34, -33, -33, -32, -32, -32, -31, -31, -31, -30, -30, -29, -29, -29, -28, -28, -28, -27, -27, -27, -26, -26, -26, -25, -25, -25, -24, -24, -24, -23, -23, -23, -22, -22, -22, -21, -21, -21, -20, -20, -20, -20, -19, -19, -19, -18, -18, -18, -18, -17, -17, -17, -17, -16, -16, -16, -16, -15, -15, -15, -15, -14, -14, -14, -14, -13, -13, -13, -13, -13, -12, -12, -12, -12, -11 }; /*---------------------------------------------------------------------------* Internal variables for the mixer *---------------------------------------------------------------------------*/ static u32 __MIXSoundMode; static u32 __MIXMaxVoices; static MIXChannel* __MIXChannel = NULL; static MIXChannel __s_MIXChannel[AX_MAX_VOICES]; static BOOL __init = FALSE; /*---------------------------------------------------------------------------* Private functions *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* Name: __MIXSetPan Description: Set panning dB attenuation for the specified channel. Arguments: Channel, pointer to MIXChannel to reset. Returns: None *---------------------------------------------------------------------------*/ static void __MIXSetPan(MIXChannel *channel) { int pan, span, ipan, ispan; ASSERT((channel->pan <= 127) && (channel->pan >= 0)); ASSERT((channel->span <= 127) && (channel->span >= 0)); pan = channel->pan; ipan = 127 - pan; span = channel->span; ispan = 127 - span; if (__MIXSoundMode == MIX_SOUND_MODE_DPL2) { channel->l = __MIX_DPL2_front[pan]; channel->r = __MIX_DPL2_front[ipan]; channel->f = __MIX_DPL2_front[ispan]; channel->b = __MIX_DPL2_front[span]; channel->l1= __MIX_DPL2_rear[ipan]; channel->r1= __MIX_DPL2_rear[pan]; } else { channel->l = __MIXPanTable[pan]; channel->r = __MIXPanTable[ipan]; channel->f = __MIXPanTable[ispan]; channel->b = __MIXPanTable[span]; channel->l1= 0; channel->r1= 0; } } /*---------------------------------------------------------------------------* Name: __MIXResetChannel Description: Reset specified channel on the mixer to initial values. Arguments: Channel, pointer to MIXChannel to reset. Returns: None *---------------------------------------------------------------------------*/ static void __MIXResetChannel(MIXChannel *channel) { channel->mode = MIX_MODE_UPDATE_MIX | MIX_MODE_UPDATE_INPUT; channel->input = 0; // 0 dB atten channel->auxA = -960; // -96.0 dB on AUX A channel->auxB = -960; // -96.0 dB on AUX B channel->auxC = -960; // -96.0 dB on AUX C channel->fader = 0; // Fader at 0. channel->pan = 64; // Pan to center. channel->span = 127; // Pan to front. channel->v = channel->vL = channel->vR = channel->vS = channel->vAL = channel->vAR = channel->vAS = channel->vBL = channel->vBR = channel->vBS = channel->vCL = channel->vCR = channel->vCS = 0; __MIXSetPan(channel); } /*---------------------------------------------------------------------------* Name: __MIXClampPan Description: Clamp user specified pan value to 0 and 127. Arguments: Pan value. Returns: Clamped pan value. *---------------------------------------------------------------------------*/ static int __MIXClampPan(int pan) { if (pan < 0) return 0; if (pan > 127) return 127; return pan; } /*---------------------------------------------------------------------------* Exposed functions *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* Name: __MIXGetVolume Description: Returns DSP volume in 1.15 for specified dB attenuation from table. It will clamp for -90.4dB and +6.0dB. Arguments: db value in 0.1 dB attenuation (1 = 0.1dB, -1 = -0.1dB). Returns: 1.15 volume for DSP volume. *---------------------------------------------------------------------------*/ u16 __MIXGetVolume(int db_) { int db = db_; // Clamp for -90.4 dB - +6.0dB. if (db <= -904) return 0; if (db >= 60) return 0xff64; return __MIXVolumeTable[db + 904]; } /*---------------------------------------------------------------------------* Name: MIXInit Description: Initialize the mixer, this function must be called prior to any other calls to the mixer APIs. Arguments: None Returns: None *---------------------------------------------------------------------------*/ void MIXInit(void) { int i; ASSERT(AXIsInit()); if (!AXIsInit()) { return; } if (__init) { return; } // Set num of max voices. __MIXMaxVoices = AXGetMaxVoices(); // Set memory. __MIXChannel = __s_MIXChannel; __MIXRmtChannel = __s_MIXRmtChannel; // Reset all channels to default setting. for (i = 0; i < __MIXMaxVoices; i++) { __MIXChannel[i].axvpb = NULL; __MIXResetChannel(&__MIXChannel[i]); __MIXRmtResetChannel(i); } // Initialize the mixing mode. __MIXSoundMode = MIX_SOUND_MODE_STEREO; __init = TRUE; } void MIXInitSpecifyMem(void* mem) { int i; u8* ptr; ASSERT(AXIsInit()); ASSERT(mem); if (!AXIsInit() || !mem) { return; } if (__init) { return; } // Set num of max voices. __MIXMaxVoices = AXGetMaxVoices(); // Set memory. ptr = (u8*)mem; __MIXChannel = (MIXChannel*)ptr; ptr += sizeof(MIXChannel) * __MIXMaxVoices; __MIXRmtChannel = (MIXRmtChannel*)ptr; ptr += sizeof(MIXRmtChannel) * __MIXMaxVoices; // Reset all channels to default setting. for (i = 0; i < __MIXMaxVoices; i++) { __MIXChannel[i].axvpb = NULL; __MIXResetChannel(&__MIXChannel[i]); __MIXRmtResetChannel(i); } // Initialize the mixing mode. __MIXSoundMode = MIX_SOUND_MODE_STEREO; __init = TRUE; } /*---------------------------------------------------------------------------* Name: MIXQuit Description: Quit the mixer in a graceful manner. Arguments: None Returns: None *---------------------------------------------------------------------------*/ void MIXQuit(void) { __MIXChannel = NULL; __MIXRmtChannel = NULL; __init = FALSE; } /*---------------------------------------------------------------------------* Name: MIXSetSoundMode Description: Runtime interface for changing sound mode. Arguments: u32 mode, new mode Returns: None *---------------------------------------------------------------------------*/ void MIXSetSoundMode(u32 mode) { ASSERT( (mode == MIX_SOUND_MODE_MONO) || (mode == MIX_SOUND_MODE_STEREO) || (mode == MIX_SOUND_MODE_SURROUND) || (mode == MIX_SOUND_MODE_DPL2) ); __MIXSoundMode = mode; } /*---------------------------------------------------------------------------* Name: MIXGetSoundMode Description: Runtime interface to query sound mode. Arguments: None Returns: MIX mode *---------------------------------------------------------------------------*/ u32 MIXGetSoundMode(void) { return __MIXSoundMode; } /*---------------------------------------------------------------------------* Name: MIXInitChannel Description: Initialize a channel on the mixer to user specified values. Users should call this after a successful call to AXAcquireVoice() to setup initial values on the channel belonging to that voice if the user wishes to use this mixer for that voice. Arguments: p Pointer to acquired voice mode Aux A, Aux B, Aux C and mute modes, see mix.h input Attenuation for input control auxA Attenuation for Aux A control auxB Attenuation for Aux B control auxC Attenuation for Aux C control pan Left - right pan control span Front - surround pan control fader Attenuation for fader control Returns: None *---------------------------------------------------------------------------*/ void MIXInitChannel( AXVPB *axvpb, // Pointer to voice. u32 mode, // auxA, B, mute modes int input, // initial input atten / gain int auxA, // initial aux A atten / gain int auxB, // initial aux B atten / gain int auxC, // initial aux C atten / gain int pan, // initial pan int span, // initial span int fader // initial fader atten / gain ) { int old; MIXChannel *c; u32 mixerCtrl; u16 *p; ASSERT(axvpb); c = &__MIXChannel[axvpb->index]; c->axvpb = axvpb; c->mode = mode & (MIX_MODE_AUXA_PREFADER | MIX_MODE_AUXB_PREFADER | MIX_MODE_AUXC_PREFADER | MIX_MODE_MUTE); c->input = input; c->auxA = auxA; c->auxB = auxB; c->auxC = auxC; c->pan = pan; c->span = span; c->fader = fader; __MIXSetPan(c); // If this channel is muted print 0 into the input. if (c->mode & MIX_MODE_MUTE) c->v = 0; else c->v = __MIXGetVolume(input); mixerCtrl = 0; switch(__MIXSoundMode) { case MIX_SOUND_MODE_MONO: // main buss volume = fader + pan + span c->vL = __MIXGetVolume(c->fader + c->f); c->vR = __MIXGetVolume(c->fader + c->f); c->vS = __MIXGetVolume(c->fader + c->b - 30); // -3dB for S if (c->mode & MIX_MODE_AUXA_PREFADER) { // Pre fader does not need fader atten. c->vAL = __MIXGetVolume(c->auxA + c->f); c->vAR = __MIXGetVolume(c->auxA + c->f); c->vAS = __MIXGetVolume(c->auxA + c->b - 30); } else { // Post fader need fader atten. c->vAL = __MIXGetVolume(c->fader + c->auxA + c->f); c->vAR = __MIXGetVolume(c->fader + c->auxA + c->f); c->vAS = __MIXGetVolume(c->fader + c->auxA + c->b - 30); } if (c->mode & MIX_MODE_AUXB_PREFADER) { // Pre fader does not need fader atten. c->vBL = __MIXGetVolume(c->auxB + c->f); c->vBR = __MIXGetVolume(c->auxB + c->f); c->vBS = __MIXGetVolume(c->auxB + c->b - 30); } else { // Post fader need fader atten. c->vBL = __MIXGetVolume(c->fader + c->auxB + c->f); c->vBR = __MIXGetVolume(c->fader + c->auxB + c->f); c->vBS = __MIXGetVolume(c->fader + c->auxB + c->b - 30); } if (c->mode & MIX_MODE_AUXC_PREFADER) { // Pre fader does not need fader atten. c->vCL = __MIXGetVolume(c->auxC + c->f); c->vCR = __MIXGetVolume(c->auxC + c->f); c->vCS = __MIXGetVolume(c->auxC + c->b - 30); } else { // Post fader need fader atten. c->vCL = __MIXGetVolume(c->fader + c->auxC + c->f); c->vCR = __MIXGetVolume(c->fader + c->auxC + c->f); c->vCS = __MIXGetVolume(c->fader + c->auxC + c->b - 30); } break; case MIX_SOUND_MODE_STEREO: case MIX_SOUND_MODE_SURROUND: // main buss volume = fader + pan + span c->vL = __MIXGetVolume(c->fader + c->l + c->f); c->vR = __MIXGetVolume(c->fader + c->r + c->f); c->vS = __MIXGetVolume(c->fader + c->b - 30); // -3dB for S if (c->mode & MIX_MODE_AUXA_PREFADER) { // Pre fader does not need fader atten. c->vAL = __MIXGetVolume(c->auxA + c->l + c->f); c->vAR = __MIXGetVolume(c->auxA + c->r + c->f); c->vAS = __MIXGetVolume(c->auxA + c->b - 30); } else { // Post fader need fader atten. c->vAL = __MIXGetVolume(c->fader + c->auxA + c->l + c->f); c->vAR = __MIXGetVolume(c->fader + c->auxA + c->r + c->f); c->vAS = __MIXGetVolume(c->fader + c->auxA + c->b - 30); } if (c->mode & MIX_MODE_AUXB_PREFADER) { // Pre fader does not need fader atten. c->vBL = __MIXGetVolume(c->auxB + c->l + c->f); c->vBR = __MIXGetVolume(c->auxB + c->r + c->f); c->vBS = __MIXGetVolume(c->auxB + c->b - 30); } else { // Post fader need fader atten. c->vBL = __MIXGetVolume(c->fader + c->auxB + c->l + c->f); c->vBR = __MIXGetVolume(c->fader + c->auxB + c->r + c->f); c->vBS = __MIXGetVolume(c->fader + c->auxB + c->b - 30); } if (c->mode & MIX_MODE_AUXC_PREFADER) { // Pre fader does not need fader atten. c->vCL = __MIXGetVolume(c->auxC + c->l + c->f); c->vCR = __MIXGetVolume(c->auxC + c->r + c->f); c->vCS = __MIXGetVolume(c->auxC + c->b - 30); } else { // Post fader need fader atten. c->vCL = __MIXGetVolume(c->fader + c->auxC + c->l + c->f); c->vCR = __MIXGetVolume(c->fader + c->auxC + c->r + c->f); c->vCS = __MIXGetVolume(c->fader + c->auxC + c->b - 30); } break; case MIX_SOUND_MODE_DPL2: // main buss volume = fader + pan + span c->vL = __MIXGetVolume(c->fader + c->l + c->f); c->vR = __MIXGetVolume(c->fader + c->r + c->f); c->vS = __MIXGetVolume(c->fader + c->l1 + c->b); c->vCL = __MIXGetVolume(c->fader + c->r1 + c->b); if (c->mode & MIX_MODE_AUXA_PREFADER) { // Pre fader does not need fader atten. c->vAL = __MIXGetVolume(c->auxA + c->l + c->f); c->vAR = __MIXGetVolume(c->auxA + c->r + c->f); c->vAS = __MIXGetVolume(c->auxA + c->l1 + c->b); c->vCR = __MIXGetVolume(c->auxA + c->r1 + c->b); } else { // Post fader need fader atten. c->vAL = __MIXGetVolume(c->fader + c->auxA + c->l + c->f); c->vAR = __MIXGetVolume(c->fader + c->auxA + c->r + c->f); c->vAS = __MIXGetVolume(c->fader + c->auxA + c->l1 + c->b); c->vCR = __MIXGetVolume(c->fader + c->auxA + c->r1 + c->b); } if (c->mode & MIX_MODE_AUXB_PREFADER) { // Pre fader does not need fader atten. c->vBL = __MIXGetVolume(c->auxB + c->l + c->f); c->vBR = __MIXGetVolume(c->auxB + c->r + c->f); c->vBS = __MIXGetVolume(c->auxB + c->l1 + c->b); c->vCS = __MIXGetVolume(c->auxB + c->r1 + c->b); } else { // Post fader need fader atten. c->vBL = __MIXGetVolume(c->fader + c->auxB + c->l + c->f); c->vBR = __MIXGetVolume(c->fader + c->auxB + c->r + c->f); c->vBS = __MIXGetVolume(c->fader + c->auxB + c->l1 + c->b); c->vCS = __MIXGetVolume(c->fader + c->auxB + c->r1 + c->b); } mixerCtrl |= AX_PB_MIXCTRL_C_DPL2; break; } // Reset remote channel. __MIXRmtResetChannel((s32)axvpb->index); old = OSDisableInterrupts(); // Set the input level. axvpb->pb.ve.currentVolume = c->v; axvpb->pb.ve.currentDelta = 0; p = (u16*)&axvpb->pb.mix; if((*p++ = c->vL) != 0) mixerCtrl |= AX_PB_MIXCTRL_L; *p++ = 0; if((*p++ = c->vR) != 0) mixerCtrl |= AX_PB_MIXCTRL_R; *p++ = 0; if((*p++ = c->vAL) != 0) mixerCtrl |= AX_PB_MIXCTRL_A_L; *p++ = 0; if((*p++ = c->vAR) != 0) mixerCtrl |= AX_PB_MIXCTRL_A_R; *p++ = 0; if((*p++ = c->vBL) != 0) mixerCtrl |= AX_PB_MIXCTRL_B_L; *p++ = 0; if((*p++ = c->vBR) != 0) mixerCtrl |= AX_PB_MIXCTRL_B_R; *p++ = 0; if((*p++ = c->vCL) != 0) mixerCtrl |= AX_PB_MIXCTRL_C_L; *p++ = 0; if((*p++ = c->vCR) != 0) mixerCtrl |= AX_PB_MIXCTRL_C_R; *p++ = 0; if((*p++ = c->vS) != 0) mixerCtrl |= AX_PB_MIXCTRL_S; *p++ = 0; if((*p++ = c->vAS) != 0) mixerCtrl |= AX_PB_MIXCTRL_A_S; *p++ = 0; if((*p++ = c->vBS) != 0) mixerCtrl |= AX_PB_MIXCTRL_B_S; *p++ = 0; if((*p++ = c->vCS) != 0) mixerCtrl |= AX_PB_MIXCTRL_C_S; *p++ = 0; axvpb->pb.mixerCtrl = mixerCtrl; axvpb->sync |= AX_SYNC_USER_MIX | AX_SYNC_USER_VE | AX_SYNC_USER_MIXCTRL; p = (u16*)&axvpb->pb.rmtMix; memset(p, 0, sizeof(AXPBRMTMIX)); axvpb->pb.rmtMixerCtrl = 0; axvpb->sync |= AX_SYNC_USER_RMTMIX | AX_SYNC_USER_RMTMIXCTRL; OSRestoreInterrupts(old); } /*---------------------------------------------------------------------------* Name: MIXReleaseChannel Description: Release the mixer channel, it will no longer be serviced. Arguments: axvpb Pointer to voice Returns: None *---------------------------------------------------------------------------*/ void MIXReleaseChannel(AXVPB *axvpb) { ASSERT(axvpb); __MIXChannel[axvpb->index].axvpb = NULL; } /*---------------------------------------------------------------------------* Name: MIXResetControls Description: Reset mixer controls for mixer channel belonging to user specified voice. Arguments: p Pointer to voice Returns: None *---------------------------------------------------------------------------*/ void MIXResetControls(AXVPB *p) { __MIXResetChannel(&__MIXChannel[p->index]); __MIXRmtResetChannel((s32)p->index); } /*---------------------------------------------------------------------------* Name: MIXSetInput Description: Set input control to specified attenuation for specified voice. Arguments: p Pointer to voice dB Attenuation for input control Returns: None *---------------------------------------------------------------------------*/ void MIXSetInput(AXVPB *p, int dB) { MIXChannel *channel = &__MIXChannel[p->index]; channel->input = dB; channel->mode |= MIX_MODE_UPDATE_INPUT; } /*---------------------------------------------------------------------------* Name: MIXAdjustInput Description: Adjust the input control by specified attenuation for specified voice. Arguments: p Pointer to voice dB Amount of attenuation to add Returns: None *---------------------------------------------------------------------------*/ void MIXAdjustInput(AXVPB *p, int dB) { MIXChannel *channel = &__MIXChannel[p->index]; channel->input += dB; channel->mode |= MIX_MODE_UPDATE_INPUT; } /*---------------------------------------------------------------------------* Name: MIXGetInput Description: Returns current attenuation for input control. Arguments: p Pointer to voice Returns: Attenuation for input. *---------------------------------------------------------------------------*/ int MIXGetInput(AXVPB *p) { MIXChannel *channel = &__MIXChannel[p->index]; return channel->input; } /*---------------------------------------------------------------------------* Name: MIXAuxAPostFader Description: Set Aux A control to post fader mode for the specified voice. Arguments: p Pointer to voice Returns: None *---------------------------------------------------------------------------*/ void MIXAuxAPostFader(AXVPB *p) { MIXChannel *channel = &__MIXChannel[p->index]; channel->mode &= ~MIX_MODE_AUXA_PREFADER; channel->mode |= MIX_MODE_UPDATE_MIX; } /*---------------------------------------------------------------------------* Name: MIXAuxAPreFader Description: Set Aux A control to pre fader mode for the specified voice. Arguments: p Pointer to voice Returns: None *---------------------------------------------------------------------------*/ void MIXAuxAPreFader(AXVPB *p) { MIXChannel *channel = &__MIXChannel[p->index]; channel->mode |= MIX_MODE_UPDATE_MIX | MIX_MODE_AUXA_PREFADER; } /*---------------------------------------------------------------------------* Name: MIXAuxAIsPostFader Description: Check to see if Aux A is in post fader mode for the specified voice. Arguments: p Pointer to voice Returns: TRUE if Aux A is in post fader mode, else FALSE. *---------------------------------------------------------------------------*/ BOOL MIXAuxAIsPostFader(AXVPB *p) { MIXChannel *channel = &__MIXChannel[p->index]; if (channel->mode & MIX_MODE_AUXA_PREFADER) return FALSE; return TRUE; } /*---------------------------------------------------------------------------* Name: MIXSetAuxA Description: Set the attenuation for the Aux A control for the specified voice. Arguments: p Pointer to voice dB Attenuation to set Returns: None *---------------------------------------------------------------------------*/ void MIXSetAuxA(AXVPB *p, int dB) { MIXChannel *channel = &__MIXChannel[p->index]; channel->auxA = dB; channel->mode |= MIX_MODE_UPDATE_MIX; } /*---------------------------------------------------------------------------* Name: MIXAdjustAuxA Description: Add the specified amount of attenuation to the Aux A control for the specified voice. Arguments: p Pointer to voice dB Attenuation to add Returns: None *---------------------------------------------------------------------------*/ void MIXAdjustAuxA(AXVPB *p, int dB) { MIXChannel *channel = &__MIXChannel[p->index]; channel->auxA += dB; channel->mode |= MIX_MODE_UPDATE_MIX; } /*---------------------------------------------------------------------------* Name: MIXGetAuxA Description: Returns attenuation for the Aux A control for the specified voice. Arguments: p Pointer to voice Returns: Attenuation for Aux A. *---------------------------------------------------------------------------*/ int MIXGetAuxA(AXVPB *p) { MIXChannel *channel = &__MIXChannel[p->index]; return channel->auxA; } /*---------------------------------------------------------------------------* Name: MIXAuxBPostFader Description: Set Aux B control to post fader mode for the specified voice. Arguments: p Pointer to voice Returns: None *---------------------------------------------------------------------------*/ void MIXAuxBPostFader(AXVPB *p) { MIXChannel *channel = &__MIXChannel[p->index]; channel->mode &= ~MIX_MODE_AUXB_PREFADER; channel->mode |= MIX_MODE_UPDATE_MIX; } /*---------------------------------------------------------------------------* Name: MIXAuxBPreFader Description: Set Aux B control to pre fader mode for the specified voice. Arguments: p Pointer to voice Returns: None *---------------------------------------------------------------------------*/ void MIXAuxBPreFader(AXVPB *p) { MIXChannel *channel = &__MIXChannel[p->index]; channel->mode |= MIX_MODE_UPDATE_MIX | MIX_MODE_AUXB_PREFADER; } /*---------------------------------------------------------------------------* Name: MIXAuxBIsPostFader Description: Check to see if Aux B is in post fader mode for the specified voice. Arguments: p Pointer to voice Returns: TRUE if Aux A is in post fader mode, else FALSE. *---------------------------------------------------------------------------*/ BOOL MIXAuxBIsPostFader(AXVPB *p) { MIXChannel *channel = &__MIXChannel[p->index]; if (channel->mode & MIX_MODE_AUXB_PREFADER) return FALSE; return TRUE; } /*---------------------------------------------------------------------------* Name: MIXSetAuxB Description: Set the attenuation for the Aux B control for the specified voice. Arguments: p Pointer to voice dB Attenuation to set Returns: None *---------------------------------------------------------------------------*/ void MIXSetAuxB(AXVPB *p, int dB) { MIXChannel *channel = &__MIXChannel[p->index]; channel->auxB = dB; channel->mode |= MIX_MODE_UPDATE_MIX; } /*---------------------------------------------------------------------------* Name: MIXAdjustAuxB Description: Add the specified amount of attenuation to the Aux B control for the specified voice. Arguments: p Pointer to voice dB Attenuation to add Returns: None *---------------------------------------------------------------------------*/ void MIXAdjustAuxB(AXVPB *p, int dB) { MIXChannel *channel = &__MIXChannel[p->index]; channel->auxB += dB; channel->mode |= MIX_MODE_UPDATE_MIX; } /*---------------------------------------------------------------------------* Name: MIXGetAuxB Description: Returns attenuation for the Aux B control for the specified voice. Arguments: p Pointer to voice Returns: Attenuation for Aux B. *---------------------------------------------------------------------------*/ int MIXGetAuxB(AXVPB *p) { MIXChannel *channel = &__MIXChannel[p->index]; return channel->auxB; } /*---------------------------------------------------------------------------* Name: MIXAuxCPostFader Description: Set Aux C control to post fader mode for the specified voice. Arguments: p Pointer to voice Returns: None *---------------------------------------------------------------------------*/ void MIXAuxCPostFader(AXVPB *p) { MIXChannel *channel = &__MIXChannel[p->index]; channel->mode &= ~MIX_MODE_AUXC_PREFADER; channel->mode |= MIX_MODE_UPDATE_MIX; } /*---------------------------------------------------------------------------* Name: MIXAuxCPreFader Description: Set Aux C control to pre fader mode for the specified voice. Arguments: p Pointer to voice Returns: None *---------------------------------------------------------------------------*/ void MIXAuxCPreFader(AXVPB *p) { MIXChannel *channel = &__MIXChannel[p->index]; channel->mode |= MIX_MODE_UPDATE_MIX | MIX_MODE_AUXC_PREFADER; } /*---------------------------------------------------------------------------* Name: MIXAuxCIsPostFader Description: Check to see if Aux C is in post fader mode for the specified voice. Arguments: p Pointer to voice Returns: TRUE if Aux C is in post fader mode, else FALSE. *---------------------------------------------------------------------------*/ BOOL MIXAuxCIsPostFader(AXVPB *p) { MIXChannel *channel = &__MIXChannel[p->index]; if (channel->mode & MIX_MODE_AUXC_PREFADER) return FALSE; return TRUE; } /*---------------------------------------------------------------------------* Name: MIXSetAuxC Description: Set the attenuation for the Aux C control for the specified voice. Arguments: p Pointer to voice dB Attenuation to set Returns: None *---------------------------------------------------------------------------*/ void MIXSetAuxC(AXVPB *p, int dB) { MIXChannel *channel; if (__MIXSoundMode == MIX_SOUND_MODE_DPL2) return; channel = &__MIXChannel[p->index]; channel->auxC = dB; channel->mode |= MIX_MODE_UPDATE_MIX; } /*---------------------------------------------------------------------------* Name: MIXAdjustAuxC Description: Add the specified amount of attenuation to the Aux C control for the specified voice. Arguments: p Pointer to voice dB Attenuation to add Returns: None *---------------------------------------------------------------------------*/ void MIXAdjustAuxC(AXVPB *p, int dB) { MIXChannel *channel; if (__MIXSoundMode == MIX_SOUND_MODE_DPL2) return; channel = &__MIXChannel[p->index]; channel->auxC += dB; channel->mode |= MIX_MODE_UPDATE_MIX; } /*---------------------------------------------------------------------------* Name: MIXGetAuxC Description: Returns attenuation for the Aux C control for the specified voice. Arguments: p Pointer to voice Returns: Attenuation for Aux C. *---------------------------------------------------------------------------*/ int MIXGetAuxC(AXVPB *p) { MIXChannel *channel; if (__MIXSoundMode == MIX_SOUND_MODE_DPL2) return -960; channel = &__MIXChannel[p->index]; return channel->auxC; } /*---------------------------------------------------------------------------* Name: MIXSetPan Description: Set pan value for specified voice. Arguments: p Pointer to voice pan Pan value to set Returns: None *---------------------------------------------------------------------------*/ void MIXSetPan(AXVPB *p, int pan) { MIXChannel *channel = &__MIXChannel[p->index]; channel->pan = __MIXClampPan(pan); __MIXSetPan(channel); channel->mode |= MIX_MODE_UPDATE_MIX; } /*---------------------------------------------------------------------------* Name: MIXAdjustPan Description: Adjust pan value for specified voice. Arguments: p Pointer to voice pan Pan value to add Returns: None *---------------------------------------------------------------------------*/ void MIXAdjustPan(AXVPB *p, int pan) { MIXChannel *channel = &__MIXChannel[p->index]; channel->pan = __MIXClampPan(channel->pan + pan); __MIXSetPan(channel); channel->mode |= MIX_MODE_UPDATE_MIX; } /*---------------------------------------------------------------------------* Name: MIXGetPan Description: Return pan value for the specified voice. Arguments: p Pointer to voice Returns: Pan value for voice. *---------------------------------------------------------------------------*/ int MIXGetPan(AXVPB *p) { MIXChannel *channel = &__MIXChannel[p->index]; return channel->pan; } /*---------------------------------------------------------------------------* Name: MIXSetSPan Description: Set surround pan value for specified voice. Arguments: p Pointer to voice span Surround pan value to set Returns: None *---------------------------------------------------------------------------*/ void MIXSetSPan(AXVPB *p, int span) { MIXChannel *channel = &__MIXChannel[p->index]; channel->span = __MIXClampPan(span); __MIXSetPan(channel); channel->mode |= MIX_MODE_UPDATE_MIX; } /*---------------------------------------------------------------------------* Name: MIXAdjustSPan Description: Adjust surround pan value for specified voice. Arguments: p Pointer to voice span Surround pan value to add Returns: None *---------------------------------------------------------------------------*/ void MIXAdjustSPan(AXVPB *p, int span) { MIXChannel *channel = &__MIXChannel[p->index]; channel->span = __MIXClampPan(channel->span + span); __MIXSetPan(channel); channel->mode |= MIX_MODE_UPDATE_MIX; } /*---------------------------------------------------------------------------* Name: MIXGetSPan Description: Return surround pan value for the specified voice. Arguments: p Pointer to voice Returns: Surround pan value for voice. *---------------------------------------------------------------------------*/ int MIXGetSPan(AXVPB *p) { MIXChannel *channel = &__MIXChannel[p->index]; return channel->span; } /*---------------------------------------------------------------------------* Name: MIXMute Description: Mute specified voice. Arguments: p Pointer to voice Returns: None *---------------------------------------------------------------------------*/ void MIXMute(AXVPB *p) { MIXChannel *channel = &__MIXChannel[p->index]; channel->mode |= MIX_MODE_MUTE | MIX_MODE_UPDATE_INPUT; } /*---------------------------------------------------------------------------* Name: MIXUnMute Description: Un mute specified voice. Arguments: p Pointer to voice Returns: None *---------------------------------------------------------------------------*/ void MIXUnMute(AXVPB *p) { MIXChannel *channel = &__MIXChannel[p->index]; channel->mode &= ~MIX_MODE_MUTE; channel->mode |= MIX_MODE_UPDATE_INPUT; } /*---------------------------------------------------------------------------* Name: MIXIsMute Description: Return mute setting for specified voice. Arguments: p Pointer to voice. Returns: TRUE if voice is mute, else FALSE. *---------------------------------------------------------------------------*/ BOOL MIXIsMute(AXVPB *p) { MIXChannel *channel = &__MIXChannel[p->index]; if (channel->mode & MIX_MODE_MUTE) return TRUE; return FALSE; } /*---------------------------------------------------------------------------* Name: MIXSetFader Description: Set fader attenuation for specified voice. Arguments: p Pointer to voice dB Attenuation to set Returns: None *---------------------------------------------------------------------------*/ void MIXSetFader(AXVPB *p, int dB) { MIXChannel *channel = &__MIXChannel[p->index]; channel->fader = dB; channel->mode |= MIX_MODE_UPDATE_MIX; } /*---------------------------------------------------------------------------* Name: MIXAdjustFader Description: Adjust fader for specified voice Arguments: p Pointer to voice dB Attenuation to add Returns: None *---------------------------------------------------------------------------*/ void MIXAdjustFader(AXVPB *p, int dB) { MIXChannel *channel = &__MIXChannel[p->index]; channel->fader += dB; channel->mode |= MIX_MODE_UPDATE_MIX; } /*---------------------------------------------------------------------------* Name: MIXGetFader Description: Returns fader attenuation for the specified voice. Arguments: p Pointer to voice Returns: Attenuation for fader. *---------------------------------------------------------------------------*/ int MIXGetFader(AXVPB *p) { MIXChannel *channel = &__MIXChannel[p->index]; return channel->fader; } /*---------------------------------------------------------------------------* Name: MIXUpdateSettings Description: Updates user settings to AX, this function should be called from the audio frame callback for AX to update the mixer settings every audio frame. Arguments: None Returns: None *---------------------------------------------------------------------------*/ void MIXUpdateSettings(void) { int i; if (!__init) { return; } for (i = 0; i < __MIXMaxVoices; i++) { BOOL setNewMixLevel; BOOL setNewInputLevel; MIXChannel *c; AXVPB *axvpb; setNewInputLevel = FALSE; setNewMixLevel = FALSE; // Get pointer to mixer channel. c = &__MIXChannel[i]; axvpb = c->axvpb; if (axvpb) { u32 mixerCtrl = 0; // Take care of input volume ramp that might have been set for last frame. if (c->mode & MIX_MODE_UPDATE_INPUT1) { c->v = c->v1; // Clear the update flag for next frame. c->mode &= ~MIX_MODE_UPDATE_INPUT1; // Flag to set new level. setNewInputLevel = TRUE; } if (c->mode & MIX_MODE_UPDATE_INPUT) { // If this channel is muted set the input to 0. if (c->mode & MIX_MODE_MUTE) c->v1 = 0; else c->v1 = __MIXGetVolume(c->input); // Clear the update flag for next frame. c->mode &= ~MIX_MODE_UPDATE_INPUT; // Assert the update for next frame. c->mode |= MIX_MODE_UPDATE_INPUT1; // Flag to set new level. setNewInputLevel = TRUE; } // Take care of mix ramp that might have been set for last frame. if (c->mode & MIX_MODE_UPDATE_MIX1) { // Set the vX1 values to vX. c->vL = c->vL1; c->vR = c->vR1; c->vS = c->vS1; c->vAL = c->vAL1; c->vAR = c->vAR1; c->vAS = c->vAS1; c->vBL = c->vBL1; c->vBR = c->vBR1; c->vBS = c->vBS1; c->vCL = c->vCL1; c->vCR = c->vCR1; c->vCS = c->vCS1; // Clear the mix1 update flag for next frame. c->mode &= ~MIX_MODE_UPDATE_MIX1; // Flag to set new level. setNewMixLevel = TRUE; } // See if any mixer settings need to be updated. if (c->mode & MIX_MODE_UPDATE_MIX) { // Volume updates in the DSP will always happen over 1 audio frame. // This is so we can ramp differences larger than AX_IN_SAMPLES_PER_FRAME ... // To do this we place the new target value in vX1 and assert // the bit for that buss in the ramp, on the following frame the // vX1 value will be places into vX. switch(__MIXSoundMode) { case MIX_SOUND_MODE_MONO: // main buss volume = fader + pan + span c->vL1 = __MIXGetVolume(c->fader + c->f); c->vR1 = __MIXGetVolume(c->fader + c->f); c->vS1 = __MIXGetVolume(c->fader + c->b - 30); // -3dB for S if (c->mode & MIX_MODE_AUXA_PREFADER) { // Pre fader does not need fader atten. c->vAL1 = __MIXGetVolume(c->auxA + c->f); c->vAR1 = __MIXGetVolume(c->auxA + c->f); c->vAS1 = __MIXGetVolume(c->auxA + c->b - 30); } else { // Post fader need fader atten. c->vAL1 = __MIXGetVolume(c->fader + c->auxA + c->f); c->vAR1 = __MIXGetVolume(c->fader + c->auxA + c->f); c->vAS1 = __MIXGetVolume(c->fader + c->auxA + c->b - 30); } if (c->mode & MIX_MODE_AUXB_PREFADER) { // Pre fader does not need fader atten. c->vBL1 = __MIXGetVolume(c->auxB + c->f); c->vBR1 = __MIXGetVolume(c->auxB + c->f); c->vBS1 = __MIXGetVolume(c->auxB + c->b - 30); } else { // Post fader need fader atten. c->vBL1 = __MIXGetVolume(c->fader + c->auxB + c->f); c->vBR1 = __MIXGetVolume(c->fader + c->auxB + c->f); c->vBS1 = __MIXGetVolume(c->fader + c->auxB + c->b - 30); } if (c->mode & MIX_MODE_AUXC_PREFADER) { // Pre fader does not need fader atten. c->vCL1 = __MIXGetVolume(c->auxC + c->f); c->vCR1 = __MIXGetVolume(c->auxC + c->f); c->vCS1 = __MIXGetVolume(c->auxC + c->b - 30); } else { // Post fader need fader atten. c->vCL1 = __MIXGetVolume(c->fader + c->auxC + c->f); c->vCR1 = __MIXGetVolume(c->fader + c->auxC + c->f); c->vCS1 = __MIXGetVolume(c->fader + c->auxC + c->b - 30); } break; case MIX_SOUND_MODE_STEREO: case MIX_SOUND_MODE_SURROUND: // main buss volume = fader + pan + span c->vL1 = __MIXGetVolume(c->fader + c->l + c->f); c->vR1 = __MIXGetVolume(c->fader + c->r + c->f); c->vS1 = __MIXGetVolume(c->fader + c->b - 30); // -3dB for S if (c->mode & MIX_MODE_AUXA_PREFADER) { // Pre fader does not need fader atten. c->vAL1 = __MIXGetVolume(c->auxA + c->l + c->f); c->vAR1 = __MIXGetVolume(c->auxA + c->r + c->f); c->vAS1 = __MIXGetVolume(c->auxA + c->b - 30); } else { // Post fader need fader atten. c->vAL1 = __MIXGetVolume(c->fader + c->auxA + c->l + c->f); c->vAR1 = __MIXGetVolume(c->fader + c->auxA + c->r + c->f); c->vAS1 = __MIXGetVolume(c->fader + c->auxA + c->b - 30); } if (c->mode & MIX_MODE_AUXB_PREFADER) { // Pre fader does not need fader atten. c->vBL1 = __MIXGetVolume(c->auxB + c->l + c->f); c->vBR1 = __MIXGetVolume(c->auxB + c->r + c->f); c->vBS1 = __MIXGetVolume(c->auxB + c->b - 30); } else { // Post fader need fader atten. c->vBL1 = __MIXGetVolume(c->fader + c->auxB + c->l + c->f); c->vBR1 = __MIXGetVolume(c->fader + c->auxB + c->r + c->f); c->vBS1 = __MIXGetVolume(c->fader + c->auxB + c->b - 30); } if (c->mode & MIX_MODE_AUXC_PREFADER) { // Pre fader does not need fader atten. c->vCL1 = __MIXGetVolume(c->auxC + c->l + c->f); c->vCR1 = __MIXGetVolume(c->auxC + c->r + c->f); c->vCS1 = __MIXGetVolume(c->auxC + c->b - 30); } else { // Post fader need fader atten. c->vCL1 = __MIXGetVolume(c->fader + c->auxC + c->l + c->f); c->vCR1 = __MIXGetVolume(c->fader + c->auxC + c->r + c->f); c->vCS1 = __MIXGetVolume(c->fader + c->auxC + c->b - 30); } break; case MIX_SOUND_MODE_DPL2: // main buss volume = fader + pan + span c->vL1 = __MIXGetVolume(c->fader + c->l + c->f); c->vR1 = __MIXGetVolume(c->fader + c->r + c->f); c->vS1 = __MIXGetVolume(c->fader + c->l1 + c->b); c->vCL1 = __MIXGetVolume(c->fader + c->r1 + c->b); if (c->mode & MIX_MODE_AUXA_PREFADER) { // Pre fader does not need fader atten. c->vAL1 = __MIXGetVolume(c->auxA + c->l + c->f); c->vAR1 = __MIXGetVolume(c->auxA + c->r + c->f); c->vAS1 = __MIXGetVolume(c->auxA + c->l1 + c->b); c->vCR1 = __MIXGetVolume(c->auxA + c->r1 + c->b); } else { // Post fader need fader atten. c->vAL1 = __MIXGetVolume(c->fader + c->auxA + c->l + c->f); c->vAR1 = __MIXGetVolume(c->fader + c->auxA + c->r + c->f); c->vAS1 = __MIXGetVolume(c->fader + c->auxA + c->l1 + c->b); c->vCR1 = __MIXGetVolume(c->fader + c->auxA + c->r1 + c->b); } if (c->mode & MIX_MODE_AUXB_PREFADER) { // Pre fader does not need fader atten. c->vBL1 = __MIXGetVolume(c->auxB + c->l + c->f); c->vBR1 = __MIXGetVolume(c->auxB + c->r + c->f); c->vBS1 = __MIXGetVolume(c->auxB + c->l1 + c->b); c->vCS1 = __MIXGetVolume(c->auxB + c->r1 + c->b); } else { // Post fader need fader atten. c->vBL1 = __MIXGetVolume(c->fader + c->auxB + c->l + c->f); c->vBR1 = __MIXGetVolume(c->fader + c->auxB + c->r + c->f); c->vBS1 = __MIXGetVolume(c->fader + c->auxB + c->l1 + c->b); c->vCS1 = __MIXGetVolume(c->fader + c->auxB + c->r1 + c->b); } mixerCtrl |= AX_PB_MIXCTRL_C_DPL2; break; } // Clear the update mix bit and set the update mix1 for the next frame. c->mode &= ~MIX_MODE_UPDATE_MIX; c->mode |= MIX_MODE_UPDATE_MIX1; // Must update new mix to AX. setNewMixLevel = TRUE; } // Update the input level. if (setNewInputLevel) { axvpb->pb.ve.currentVolume = c->v; axvpb->pb.ve.currentDelta = (s16)((c->v1 - c->v) / AX_IN_SAMPLES_PER_FRAME); axvpb->sync |= AX_SYNC_USER_VE; } // Update the new levels to the AX. if (setNewMixLevel) { u16 *p = (u16*)&axvpb->pb.mix; if((*p++ = c->vL) != 0) mixerCtrl |= AX_PB_MIXCTRL_L; if((*p++ = (u16)((c->vL1 - c->vL) / AX_IN_SAMPLES_PER_FRAME)) != 0) mixerCtrl |= AX_PB_MIXCTRL_LR_RAMP; if((*p++ = c->vR) != 0) mixerCtrl |= AX_PB_MIXCTRL_R; if((*p++ = (u16)((c->vR1 - c->vR) / AX_IN_SAMPLES_PER_FRAME)) != 0) mixerCtrl |= AX_PB_MIXCTRL_LR_RAMP; if((*p++ = c->vAL) != 0) mixerCtrl |= AX_PB_MIXCTRL_A_L; if((*p++ = (u16)((c->vAL1 - c->vAL) / AX_IN_SAMPLES_PER_FRAME)) != 0) mixerCtrl |= AX_PB_MIXCTRL_A_LR_RAMP; if((*p++ = c->vAR) != 0) mixerCtrl |= AX_PB_MIXCTRL_A_R; if((*p++ = (u16)((c->vAR1 - c->vAR) / AX_IN_SAMPLES_PER_FRAME)) != 0) mixerCtrl |= AX_PB_MIXCTRL_A_LR_RAMP; if((*p++ = c->vBL) != 0) mixerCtrl |= AX_PB_MIXCTRL_B_L; if((*p++ = (u16)((c->vBL1 - c->vBL) / AX_IN_SAMPLES_PER_FRAME)) != 0) mixerCtrl |= AX_PB_MIXCTRL_B_LR_RAMP; if((*p++ = c->vBR) != 0) mixerCtrl |= AX_PB_MIXCTRL_B_R; if((*p++ = (u16)((c->vBR1 - c->vBR) / AX_IN_SAMPLES_PER_FRAME)) != 0) mixerCtrl |= AX_PB_MIXCTRL_B_LR_RAMP; if((*p++ = c->vCL) != 0) mixerCtrl |= AX_PB_MIXCTRL_C_L; if((*p++ = (u16)((c->vCL1 - c->vCL) / AX_IN_SAMPLES_PER_FRAME)) != 0) mixerCtrl |= AX_PB_MIXCTRL_C_LR_RAMP; if((*p++ = c->vCR) != 0) mixerCtrl |= AX_PB_MIXCTRL_C_R; if((*p++ = (u16)((c->vCR1 - c->vCR) / AX_IN_SAMPLES_PER_FRAME)) != 0) mixerCtrl |= AX_PB_MIXCTRL_C_LR_RAMP; if((*p++ = c->vS) != 0) mixerCtrl |= AX_PB_MIXCTRL_S; if((*p++ = (u16)((c->vS1 - c->vS) / AX_IN_SAMPLES_PER_FRAME)) != 0) mixerCtrl |= AX_PB_MIXCTRL_S_RAMP; if((*p++ = c->vAS) != 0) mixerCtrl |= AX_PB_MIXCTRL_A_S; if((*p++ = (u16)((c->vAS1 - c->vAS) / AX_IN_SAMPLES_PER_FRAME)) != 0) mixerCtrl |= AX_PB_MIXCTRL_A_S_RAMP; if((*p++ = c->vBS) != 0) mixerCtrl |= AX_PB_MIXCTRL_B_S; if((*p++ = (u16)((c->vBS1 - c->vBS) / AX_IN_SAMPLES_PER_FRAME)) != 0) mixerCtrl |= AX_PB_MIXCTRL_B_S_RAMP; if((*p++ = c->vCS) != 0) mixerCtrl |= AX_PB_MIXCTRL_C_S; if((*p++ = (u16)((c->vCS1 - c->vCS) / AX_IN_SAMPLES_PER_FRAME)) != 0) mixerCtrl |= AX_PB_MIXCTRL_C_S_RAMP; axvpb->pb.mixerCtrl = mixerCtrl; axvpb->sync |= AX_SYNC_USER_MIX | AX_SYNC_USER_MIXCTRL; } __MIXRmtUpdateSettings(i, axvpb); } } }