| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * OPL4 MIDI synthesizer functions | 
|  | 3 | * | 
|  | 4 | * Copyright (c) 2003 by Clemens Ladisch <clemens@ladisch.de> | 
|  | 5 | * All rights reserved. | 
|  | 6 | * | 
|  | 7 | * Redistribution and use in source and binary forms, with or without | 
|  | 8 | * modification, are permitted provided that the following conditions | 
|  | 9 | * are met: | 
|  | 10 | * 1. Redistributions of source code must retain the above copyright | 
|  | 11 | *    notice, this list of conditions, and the following disclaimer, | 
|  | 12 | *    without modification. | 
|  | 13 | * 2. The name of the author may not be used to endorse or promote products | 
|  | 14 | *    derived from this software without specific prior written permission. | 
|  | 15 | * | 
|  | 16 | * Alternatively, this software may be distributed and/or modified under the | 
|  | 17 | * terms of the GNU General Public License as published by the Free Software | 
|  | 18 | * Foundation; either version 2 of the License, or (at your option) any later | 
|  | 19 | * version. | 
|  | 20 | * | 
|  | 21 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | 
|  | 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
|  | 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 
|  | 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR | 
|  | 25 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
|  | 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 
|  | 27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 
|  | 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 
|  | 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 
|  | 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
|  | 31 | * SUCH DAMAGE. | 
|  | 32 | */ | 
|  | 33 |  | 
|  | 34 | #include "opl4_local.h" | 
|  | 35 | #include <linux/delay.h> | 
|  | 36 | #include <asm/io.h> | 
|  | 37 | #include <sound/asoundef.h> | 
|  | 38 |  | 
|  | 39 | /* GM2 controllers */ | 
|  | 40 | #ifndef MIDI_CTL_RELEASE_TIME | 
|  | 41 | #define MIDI_CTL_RELEASE_TIME	0x48 | 
|  | 42 | #define MIDI_CTL_ATTACK_TIME	0x49 | 
|  | 43 | #define MIDI_CTL_DECAY_TIME	0x4b | 
|  | 44 | #define MIDI_CTL_VIBRATO_RATE	0x4c | 
|  | 45 | #define MIDI_CTL_VIBRATO_DEPTH	0x4d | 
|  | 46 | #define MIDI_CTL_VIBRATO_DELAY	0x4e | 
|  | 47 | #endif | 
|  | 48 |  | 
|  | 49 | /* | 
|  | 50 | * This table maps 100/128 cents to F_NUMBER. | 
|  | 51 | */ | 
|  | 52 | static const s16 snd_opl4_pitch_map[0x600] = { | 
|  | 53 | 0x000,0x000,0x001,0x001,0x002,0x002,0x003,0x003, | 
|  | 54 | 0x004,0x004,0x005,0x005,0x006,0x006,0x006,0x007, | 
|  | 55 | 0x007,0x008,0x008,0x009,0x009,0x00a,0x00a,0x00b, | 
|  | 56 | 0x00b,0x00c,0x00c,0x00d,0x00d,0x00d,0x00e,0x00e, | 
|  | 57 | 0x00f,0x00f,0x010,0x010,0x011,0x011,0x012,0x012, | 
|  | 58 | 0x013,0x013,0x014,0x014,0x015,0x015,0x015,0x016, | 
|  | 59 | 0x016,0x017,0x017,0x018,0x018,0x019,0x019,0x01a, | 
|  | 60 | 0x01a,0x01b,0x01b,0x01c,0x01c,0x01d,0x01d,0x01e, | 
|  | 61 | 0x01e,0x01e,0x01f,0x01f,0x020,0x020,0x021,0x021, | 
|  | 62 | 0x022,0x022,0x023,0x023,0x024,0x024,0x025,0x025, | 
|  | 63 | 0x026,0x026,0x027,0x027,0x028,0x028,0x029,0x029, | 
|  | 64 | 0x029,0x02a,0x02a,0x02b,0x02b,0x02c,0x02c,0x02d, | 
|  | 65 | 0x02d,0x02e,0x02e,0x02f,0x02f,0x030,0x030,0x031, | 
|  | 66 | 0x031,0x032,0x032,0x033,0x033,0x034,0x034,0x035, | 
|  | 67 | 0x035,0x036,0x036,0x037,0x037,0x038,0x038,0x038, | 
|  | 68 | 0x039,0x039,0x03a,0x03a,0x03b,0x03b,0x03c,0x03c, | 
|  | 69 | 0x03d,0x03d,0x03e,0x03e,0x03f,0x03f,0x040,0x040, | 
|  | 70 | 0x041,0x041,0x042,0x042,0x043,0x043,0x044,0x044, | 
|  | 71 | 0x045,0x045,0x046,0x046,0x047,0x047,0x048,0x048, | 
|  | 72 | 0x049,0x049,0x04a,0x04a,0x04b,0x04b,0x04c,0x04c, | 
|  | 73 | 0x04d,0x04d,0x04e,0x04e,0x04f,0x04f,0x050,0x050, | 
|  | 74 | 0x051,0x051,0x052,0x052,0x053,0x053,0x054,0x054, | 
|  | 75 | 0x055,0x055,0x056,0x056,0x057,0x057,0x058,0x058, | 
|  | 76 | 0x059,0x059,0x05a,0x05a,0x05b,0x05b,0x05c,0x05c, | 
|  | 77 | 0x05d,0x05d,0x05e,0x05e,0x05f,0x05f,0x060,0x060, | 
|  | 78 | 0x061,0x061,0x062,0x062,0x063,0x063,0x064,0x064, | 
|  | 79 | 0x065,0x065,0x066,0x066,0x067,0x067,0x068,0x068, | 
|  | 80 | 0x069,0x069,0x06a,0x06a,0x06b,0x06b,0x06c,0x06c, | 
|  | 81 | 0x06d,0x06d,0x06e,0x06e,0x06f,0x06f,0x070,0x071, | 
|  | 82 | 0x071,0x072,0x072,0x073,0x073,0x074,0x074,0x075, | 
|  | 83 | 0x075,0x076,0x076,0x077,0x077,0x078,0x078,0x079, | 
|  | 84 | 0x079,0x07a,0x07a,0x07b,0x07b,0x07c,0x07c,0x07d, | 
|  | 85 | 0x07d,0x07e,0x07e,0x07f,0x07f,0x080,0x081,0x081, | 
|  | 86 | 0x082,0x082,0x083,0x083,0x084,0x084,0x085,0x085, | 
|  | 87 | 0x086,0x086,0x087,0x087,0x088,0x088,0x089,0x089, | 
|  | 88 | 0x08a,0x08a,0x08b,0x08b,0x08c,0x08d,0x08d,0x08e, | 
|  | 89 | 0x08e,0x08f,0x08f,0x090,0x090,0x091,0x091,0x092, | 
|  | 90 | 0x092,0x093,0x093,0x094,0x094,0x095,0x096,0x096, | 
|  | 91 | 0x097,0x097,0x098,0x098,0x099,0x099,0x09a,0x09a, | 
|  | 92 | 0x09b,0x09b,0x09c,0x09c,0x09d,0x09d,0x09e,0x09f, | 
|  | 93 | 0x09f,0x0a0,0x0a0,0x0a1,0x0a1,0x0a2,0x0a2,0x0a3, | 
|  | 94 | 0x0a3,0x0a4,0x0a4,0x0a5,0x0a6,0x0a6,0x0a7,0x0a7, | 
|  | 95 | 0x0a8,0x0a8,0x0a9,0x0a9,0x0aa,0x0aa,0x0ab,0x0ab, | 
|  | 96 | 0x0ac,0x0ad,0x0ad,0x0ae,0x0ae,0x0af,0x0af,0x0b0, | 
|  | 97 | 0x0b0,0x0b1,0x0b1,0x0b2,0x0b2,0x0b3,0x0b4,0x0b4, | 
|  | 98 | 0x0b5,0x0b5,0x0b6,0x0b6,0x0b7,0x0b7,0x0b8,0x0b8, | 
|  | 99 | 0x0b9,0x0ba,0x0ba,0x0bb,0x0bb,0x0bc,0x0bc,0x0bd, | 
|  | 100 | 0x0bd,0x0be,0x0be,0x0bf,0x0c0,0x0c0,0x0c1,0x0c1, | 
|  | 101 | 0x0c2,0x0c2,0x0c3,0x0c3,0x0c4,0x0c4,0x0c5,0x0c6, | 
|  | 102 | 0x0c6,0x0c7,0x0c7,0x0c8,0x0c8,0x0c9,0x0c9,0x0ca, | 
|  | 103 | 0x0cb,0x0cb,0x0cc,0x0cc,0x0cd,0x0cd,0x0ce,0x0ce, | 
|  | 104 | 0x0cf,0x0d0,0x0d0,0x0d1,0x0d1,0x0d2,0x0d2,0x0d3, | 
|  | 105 | 0x0d3,0x0d4,0x0d5,0x0d5,0x0d6,0x0d6,0x0d7,0x0d7, | 
|  | 106 | 0x0d8,0x0d8,0x0d9,0x0da,0x0da,0x0db,0x0db,0x0dc, | 
|  | 107 | 0x0dc,0x0dd,0x0de,0x0de,0x0df,0x0df,0x0e0,0x0e0, | 
|  | 108 | 0x0e1,0x0e1,0x0e2,0x0e3,0x0e3,0x0e4,0x0e4,0x0e5, | 
|  | 109 | 0x0e5,0x0e6,0x0e7,0x0e7,0x0e8,0x0e8,0x0e9,0x0e9, | 
|  | 110 | 0x0ea,0x0eb,0x0eb,0x0ec,0x0ec,0x0ed,0x0ed,0x0ee, | 
|  | 111 | 0x0ef,0x0ef,0x0f0,0x0f0,0x0f1,0x0f1,0x0f2,0x0f3, | 
|  | 112 | 0x0f3,0x0f4,0x0f4,0x0f5,0x0f5,0x0f6,0x0f7,0x0f7, | 
|  | 113 | 0x0f8,0x0f8,0x0f9,0x0f9,0x0fa,0x0fb,0x0fb,0x0fc, | 
|  | 114 | 0x0fc,0x0fd,0x0fd,0x0fe,0x0ff,0x0ff,0x100,0x100, | 
|  | 115 | 0x101,0x101,0x102,0x103,0x103,0x104,0x104,0x105, | 
|  | 116 | 0x106,0x106,0x107,0x107,0x108,0x108,0x109,0x10a, | 
|  | 117 | 0x10a,0x10b,0x10b,0x10c,0x10c,0x10d,0x10e,0x10e, | 
|  | 118 | 0x10f,0x10f,0x110,0x111,0x111,0x112,0x112,0x113, | 
|  | 119 | 0x114,0x114,0x115,0x115,0x116,0x116,0x117,0x118, | 
|  | 120 | 0x118,0x119,0x119,0x11a,0x11b,0x11b,0x11c,0x11c, | 
|  | 121 | 0x11d,0x11e,0x11e,0x11f,0x11f,0x120,0x120,0x121, | 
|  | 122 | 0x122,0x122,0x123,0x123,0x124,0x125,0x125,0x126, | 
|  | 123 | 0x126,0x127,0x128,0x128,0x129,0x129,0x12a,0x12b, | 
|  | 124 | 0x12b,0x12c,0x12c,0x12d,0x12e,0x12e,0x12f,0x12f, | 
|  | 125 | 0x130,0x131,0x131,0x132,0x132,0x133,0x134,0x134, | 
|  | 126 | 0x135,0x135,0x136,0x137,0x137,0x138,0x138,0x139, | 
|  | 127 | 0x13a,0x13a,0x13b,0x13b,0x13c,0x13d,0x13d,0x13e, | 
|  | 128 | 0x13e,0x13f,0x140,0x140,0x141,0x141,0x142,0x143, | 
|  | 129 | 0x143,0x144,0x144,0x145,0x146,0x146,0x147,0x148, | 
|  | 130 | 0x148,0x149,0x149,0x14a,0x14b,0x14b,0x14c,0x14c, | 
|  | 131 | 0x14d,0x14e,0x14e,0x14f,0x14f,0x150,0x151,0x151, | 
|  | 132 | 0x152,0x153,0x153,0x154,0x154,0x155,0x156,0x156, | 
|  | 133 | 0x157,0x157,0x158,0x159,0x159,0x15a,0x15b,0x15b, | 
|  | 134 | 0x15c,0x15c,0x15d,0x15e,0x15e,0x15f,0x160,0x160, | 
|  | 135 | 0x161,0x161,0x162,0x163,0x163,0x164,0x165,0x165, | 
|  | 136 | 0x166,0x166,0x167,0x168,0x168,0x169,0x16a,0x16a, | 
|  | 137 | 0x16b,0x16b,0x16c,0x16d,0x16d,0x16e,0x16f,0x16f, | 
|  | 138 | 0x170,0x170,0x171,0x172,0x172,0x173,0x174,0x174, | 
|  | 139 | 0x175,0x175,0x176,0x177,0x177,0x178,0x179,0x179, | 
|  | 140 | 0x17a,0x17a,0x17b,0x17c,0x17c,0x17d,0x17e,0x17e, | 
|  | 141 | 0x17f,0x180,0x180,0x181,0x181,0x182,0x183,0x183, | 
|  | 142 | 0x184,0x185,0x185,0x186,0x187,0x187,0x188,0x188, | 
|  | 143 | 0x189,0x18a,0x18a,0x18b,0x18c,0x18c,0x18d,0x18e, | 
|  | 144 | 0x18e,0x18f,0x190,0x190,0x191,0x191,0x192,0x193, | 
|  | 145 | 0x193,0x194,0x195,0x195,0x196,0x197,0x197,0x198, | 
|  | 146 | 0x199,0x199,0x19a,0x19a,0x19b,0x19c,0x19c,0x19d, | 
|  | 147 | 0x19e,0x19e,0x19f,0x1a0,0x1a0,0x1a1,0x1a2,0x1a2, | 
|  | 148 | 0x1a3,0x1a4,0x1a4,0x1a5,0x1a6,0x1a6,0x1a7,0x1a8, | 
|  | 149 | 0x1a8,0x1a9,0x1a9,0x1aa,0x1ab,0x1ab,0x1ac,0x1ad, | 
|  | 150 | 0x1ad,0x1ae,0x1af,0x1af,0x1b0,0x1b1,0x1b1,0x1b2, | 
|  | 151 | 0x1b3,0x1b3,0x1b4,0x1b5,0x1b5,0x1b6,0x1b7,0x1b7, | 
|  | 152 | 0x1b8,0x1b9,0x1b9,0x1ba,0x1bb,0x1bb,0x1bc,0x1bd, | 
|  | 153 | 0x1bd,0x1be,0x1bf,0x1bf,0x1c0,0x1c1,0x1c1,0x1c2, | 
|  | 154 | 0x1c3,0x1c3,0x1c4,0x1c5,0x1c5,0x1c6,0x1c7,0x1c7, | 
|  | 155 | 0x1c8,0x1c9,0x1c9,0x1ca,0x1cb,0x1cb,0x1cc,0x1cd, | 
|  | 156 | 0x1cd,0x1ce,0x1cf,0x1cf,0x1d0,0x1d1,0x1d1,0x1d2, | 
|  | 157 | 0x1d3,0x1d3,0x1d4,0x1d5,0x1d5,0x1d6,0x1d7,0x1d7, | 
|  | 158 | 0x1d8,0x1d9,0x1d9,0x1da,0x1db,0x1db,0x1dc,0x1dd, | 
|  | 159 | 0x1dd,0x1de,0x1df,0x1df,0x1e0,0x1e1,0x1e1,0x1e2, | 
|  | 160 | 0x1e3,0x1e4,0x1e4,0x1e5,0x1e6,0x1e6,0x1e7,0x1e8, | 
|  | 161 | 0x1e8,0x1e9,0x1ea,0x1ea,0x1eb,0x1ec,0x1ec,0x1ed, | 
|  | 162 | 0x1ee,0x1ee,0x1ef,0x1f0,0x1f0,0x1f1,0x1f2,0x1f3, | 
|  | 163 | 0x1f3,0x1f4,0x1f5,0x1f5,0x1f6,0x1f7,0x1f7,0x1f8, | 
|  | 164 | 0x1f9,0x1f9,0x1fa,0x1fb,0x1fb,0x1fc,0x1fd,0x1fe, | 
|  | 165 | 0x1fe,0x1ff,0x200,0x200,0x201,0x202,0x202,0x203, | 
|  | 166 | 0x204,0x205,0x205,0x206,0x207,0x207,0x208,0x209, | 
|  | 167 | 0x209,0x20a,0x20b,0x20b,0x20c,0x20d,0x20e,0x20e, | 
|  | 168 | 0x20f,0x210,0x210,0x211,0x212,0x212,0x213,0x214, | 
|  | 169 | 0x215,0x215,0x216,0x217,0x217,0x218,0x219,0x21a, | 
|  | 170 | 0x21a,0x21b,0x21c,0x21c,0x21d,0x21e,0x21e,0x21f, | 
|  | 171 | 0x220,0x221,0x221,0x222,0x223,0x223,0x224,0x225, | 
|  | 172 | 0x226,0x226,0x227,0x228,0x228,0x229,0x22a,0x22b, | 
|  | 173 | 0x22b,0x22c,0x22d,0x22d,0x22e,0x22f,0x230,0x230, | 
|  | 174 | 0x231,0x232,0x232,0x233,0x234,0x235,0x235,0x236, | 
|  | 175 | 0x237,0x237,0x238,0x239,0x23a,0x23a,0x23b,0x23c, | 
|  | 176 | 0x23c,0x23d,0x23e,0x23f,0x23f,0x240,0x241,0x241, | 
|  | 177 | 0x242,0x243,0x244,0x244,0x245,0x246,0x247,0x247, | 
|  | 178 | 0x248,0x249,0x249,0x24a,0x24b,0x24c,0x24c,0x24d, | 
|  | 179 | 0x24e,0x24f,0x24f,0x250,0x251,0x251,0x252,0x253, | 
|  | 180 | 0x254,0x254,0x255,0x256,0x257,0x257,0x258,0x259, | 
|  | 181 | 0x259,0x25a,0x25b,0x25c,0x25c,0x25d,0x25e,0x25f, | 
|  | 182 | 0x25f,0x260,0x261,0x262,0x262,0x263,0x264,0x265, | 
|  | 183 | 0x265,0x266,0x267,0x267,0x268,0x269,0x26a,0x26a, | 
|  | 184 | 0x26b,0x26c,0x26d,0x26d,0x26e,0x26f,0x270,0x270, | 
|  | 185 | 0x271,0x272,0x273,0x273,0x274,0x275,0x276,0x276, | 
|  | 186 | 0x277,0x278,0x279,0x279,0x27a,0x27b,0x27c,0x27c, | 
|  | 187 | 0x27d,0x27e,0x27f,0x27f,0x280,0x281,0x282,0x282, | 
|  | 188 | 0x283,0x284,0x285,0x285,0x286,0x287,0x288,0x288, | 
|  | 189 | 0x289,0x28a,0x28b,0x28b,0x28c,0x28d,0x28e,0x28e, | 
|  | 190 | 0x28f,0x290,0x291,0x291,0x292,0x293,0x294,0x294, | 
|  | 191 | 0x295,0x296,0x297,0x298,0x298,0x299,0x29a,0x29b, | 
|  | 192 | 0x29b,0x29c,0x29d,0x29e,0x29e,0x29f,0x2a0,0x2a1, | 
|  | 193 | 0x2a1,0x2a2,0x2a3,0x2a4,0x2a5,0x2a5,0x2a6,0x2a7, | 
|  | 194 | 0x2a8,0x2a8,0x2a9,0x2aa,0x2ab,0x2ab,0x2ac,0x2ad, | 
|  | 195 | 0x2ae,0x2af,0x2af,0x2b0,0x2b1,0x2b2,0x2b2,0x2b3, | 
|  | 196 | 0x2b4,0x2b5,0x2b5,0x2b6,0x2b7,0x2b8,0x2b9,0x2b9, | 
|  | 197 | 0x2ba,0x2bb,0x2bc,0x2bc,0x2bd,0x2be,0x2bf,0x2c0, | 
|  | 198 | 0x2c0,0x2c1,0x2c2,0x2c3,0x2c4,0x2c4,0x2c5,0x2c6, | 
|  | 199 | 0x2c7,0x2c7,0x2c8,0x2c9,0x2ca,0x2cb,0x2cb,0x2cc, | 
|  | 200 | 0x2cd,0x2ce,0x2ce,0x2cf,0x2d0,0x2d1,0x2d2,0x2d2, | 
|  | 201 | 0x2d3,0x2d4,0x2d5,0x2d6,0x2d6,0x2d7,0x2d8,0x2d9, | 
|  | 202 | 0x2da,0x2da,0x2db,0x2dc,0x2dd,0x2dd,0x2de,0x2df, | 
|  | 203 | 0x2e0,0x2e1,0x2e1,0x2e2,0x2e3,0x2e4,0x2e5,0x2e5, | 
|  | 204 | 0x2e6,0x2e7,0x2e8,0x2e9,0x2e9,0x2ea,0x2eb,0x2ec, | 
|  | 205 | 0x2ed,0x2ed,0x2ee,0x2ef,0x2f0,0x2f1,0x2f1,0x2f2, | 
|  | 206 | 0x2f3,0x2f4,0x2f5,0x2f5,0x2f6,0x2f7,0x2f8,0x2f9, | 
|  | 207 | 0x2f9,0x2fa,0x2fb,0x2fc,0x2fd,0x2fd,0x2fe,0x2ff, | 
|  | 208 | 0x300,0x301,0x302,0x302,0x303,0x304,0x305,0x306, | 
|  | 209 | 0x306,0x307,0x308,0x309,0x30a,0x30a,0x30b,0x30c, | 
|  | 210 | 0x30d,0x30e,0x30f,0x30f,0x310,0x311,0x312,0x313, | 
|  | 211 | 0x313,0x314,0x315,0x316,0x317,0x318,0x318,0x319, | 
|  | 212 | 0x31a,0x31b,0x31c,0x31c,0x31d,0x31e,0x31f,0x320, | 
|  | 213 | 0x321,0x321,0x322,0x323,0x324,0x325,0x326,0x326, | 
|  | 214 | 0x327,0x328,0x329,0x32a,0x32a,0x32b,0x32c,0x32d, | 
|  | 215 | 0x32e,0x32f,0x32f,0x330,0x331,0x332,0x333,0x334, | 
|  | 216 | 0x334,0x335,0x336,0x337,0x338,0x339,0x339,0x33a, | 
|  | 217 | 0x33b,0x33c,0x33d,0x33e,0x33e,0x33f,0x340,0x341, | 
|  | 218 | 0x342,0x343,0x343,0x344,0x345,0x346,0x347,0x348, | 
|  | 219 | 0x349,0x349,0x34a,0x34b,0x34c,0x34d,0x34e,0x34e, | 
|  | 220 | 0x34f,0x350,0x351,0x352,0x353,0x353,0x354,0x355, | 
|  | 221 | 0x356,0x357,0x358,0x359,0x359,0x35a,0x35b,0x35c, | 
|  | 222 | 0x35d,0x35e,0x35f,0x35f,0x360,0x361,0x362,0x363, | 
|  | 223 | 0x364,0x364,0x365,0x366,0x367,0x368,0x369,0x36a, | 
|  | 224 | 0x36a,0x36b,0x36c,0x36d,0x36e,0x36f,0x370,0x370, | 
|  | 225 | 0x371,0x372,0x373,0x374,0x375,0x376,0x377,0x377, | 
|  | 226 | 0x378,0x379,0x37a,0x37b,0x37c,0x37d,0x37d,0x37e, | 
|  | 227 | 0x37f,0x380,0x381,0x382,0x383,0x383,0x384,0x385, | 
|  | 228 | 0x386,0x387,0x388,0x389,0x38a,0x38a,0x38b,0x38c, | 
|  | 229 | 0x38d,0x38e,0x38f,0x390,0x391,0x391,0x392,0x393, | 
|  | 230 | 0x394,0x395,0x396,0x397,0x398,0x398,0x399,0x39a, | 
|  | 231 | 0x39b,0x39c,0x39d,0x39e,0x39f,0x39f,0x3a0,0x3a1, | 
|  | 232 | 0x3a2,0x3a3,0x3a4,0x3a5,0x3a6,0x3a7,0x3a7,0x3a8, | 
|  | 233 | 0x3a9,0x3aa,0x3ab,0x3ac,0x3ad,0x3ae,0x3ae,0x3af, | 
|  | 234 | 0x3b0,0x3b1,0x3b2,0x3b3,0x3b4,0x3b5,0x3b6,0x3b6, | 
|  | 235 | 0x3b7,0x3b8,0x3b9,0x3ba,0x3bb,0x3bc,0x3bd,0x3be, | 
|  | 236 | 0x3bf,0x3bf,0x3c0,0x3c1,0x3c2,0x3c3,0x3c4,0x3c5, | 
|  | 237 | 0x3c6,0x3c7,0x3c7,0x3c8,0x3c9,0x3ca,0x3cb,0x3cc, | 
|  | 238 | 0x3cd,0x3ce,0x3cf,0x3d0,0x3d1,0x3d1,0x3d2,0x3d3, | 
|  | 239 | 0x3d4,0x3d5,0x3d6,0x3d7,0x3d8,0x3d9,0x3da,0x3da, | 
|  | 240 | 0x3db,0x3dc,0x3dd,0x3de,0x3df,0x3e0,0x3e1,0x3e2, | 
|  | 241 | 0x3e3,0x3e4,0x3e4,0x3e5,0x3e6,0x3e7,0x3e8,0x3e9, | 
|  | 242 | 0x3ea,0x3eb,0x3ec,0x3ed,0x3ee,0x3ef,0x3ef,0x3f0, | 
|  | 243 | 0x3f1,0x3f2,0x3f3,0x3f4,0x3f5,0x3f6,0x3f7,0x3f8, | 
|  | 244 | 0x3f9,0x3fa,0x3fa,0x3fb,0x3fc,0x3fd,0x3fe,0x3ff | 
|  | 245 | }; | 
|  | 246 |  | 
|  | 247 | /* | 
|  | 248 | * Attenuation according to GM recommendations, in -0.375 dB units. | 
|  | 249 | * table[v] = 40 * log(v / 127) / -0.375 | 
|  | 250 | */ | 
|  | 251 | static unsigned char snd_opl4_volume_table[128] = { | 
|  | 252 | 255,224,192,173,160,150,141,134, | 
|  | 253 | 128,122,117,113,109,105,102, 99, | 
|  | 254 | 96, 93, 90, 88, 85, 83, 81, 79, | 
|  | 255 | 77, 75, 73, 71, 70, 68, 67, 65, | 
|  | 256 | 64, 62, 61, 59, 58, 57, 56, 54, | 
|  | 257 | 53, 52, 51, 50, 49, 48, 47, 46, | 
|  | 258 | 45, 44, 43, 42, 41, 40, 39, 39, | 
|  | 259 | 38, 37, 36, 35, 34, 34, 33, 32, | 
|  | 260 | 31, 31, 30, 29, 29, 28, 27, 27, | 
|  | 261 | 26, 25, 25, 24, 24, 23, 22, 22, | 
|  | 262 | 21, 21, 20, 19, 19, 18, 18, 17, | 
|  | 263 | 17, 16, 16, 15, 15, 14, 14, 13, | 
|  | 264 | 13, 12, 12, 11, 11, 10, 10,  9, | 
|  | 265 | 9,  9,  8,  8,  7,  7,  6,  6, | 
|  | 266 | 6,  5,  5,  4,  4,  4,  3,  3, | 
|  | 267 | 2,  2,  2,  1,  1,  0,  0,  0 | 
|  | 268 | }; | 
|  | 269 |  | 
|  | 270 | /* | 
|  | 271 | * Initializes all voices. | 
|  | 272 | */ | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 273 | void snd_opl4_synth_reset(struct snd_opl4 *opl4) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 274 | { | 
|  | 275 | unsigned long flags; | 
|  | 276 | int i; | 
|  | 277 |  | 
|  | 278 | spin_lock_irqsave(&opl4->reg_lock, flags); | 
|  | 279 | for (i = 0; i < OPL4_MAX_VOICES; i++) | 
|  | 280 | snd_opl4_write(opl4, OPL4_REG_MISC + i, OPL4_DAMP_BIT); | 
|  | 281 | spin_unlock_irqrestore(&opl4->reg_lock, flags); | 
|  | 282 |  | 
|  | 283 | INIT_LIST_HEAD(&opl4->off_voices); | 
|  | 284 | INIT_LIST_HEAD(&opl4->on_voices); | 
|  | 285 | memset(opl4->voices, 0, sizeof(opl4->voices)); | 
|  | 286 | for (i = 0; i < OPL4_MAX_VOICES; i++) { | 
|  | 287 | opl4->voices[i].number = i; | 
|  | 288 | list_add_tail(&opl4->voices[i].list, &opl4->off_voices); | 
|  | 289 | } | 
|  | 290 |  | 
|  | 291 | snd_midi_channel_set_clear(opl4->chset); | 
|  | 292 | } | 
|  | 293 |  | 
|  | 294 | /* | 
|  | 295 | * Shuts down all voices. | 
|  | 296 | */ | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 297 | void snd_opl4_synth_shutdown(struct snd_opl4 *opl4) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 298 | { | 
|  | 299 | unsigned long flags; | 
|  | 300 | int i; | 
|  | 301 |  | 
|  | 302 | spin_lock_irqsave(&opl4->reg_lock, flags); | 
|  | 303 | for (i = 0; i < OPL4_MAX_VOICES; i++) | 
|  | 304 | snd_opl4_write(opl4, OPL4_REG_MISC + i, | 
|  | 305 | opl4->voices[i].reg_misc & ~OPL4_KEY_ON_BIT); | 
|  | 306 | spin_unlock_irqrestore(&opl4->reg_lock, flags); | 
|  | 307 | } | 
|  | 308 |  | 
|  | 309 | /* | 
|  | 310 | * Executes the callback for all voices playing the specified note. | 
|  | 311 | */ | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 312 | static void snd_opl4_do_for_note(struct snd_opl4 *opl4, int note, struct snd_midi_channel *chan, | 
|  | 313 | void (*func)(struct snd_opl4 *opl4, struct opl4_voice *voice)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 314 | { | 
|  | 315 | int i; | 
|  | 316 | unsigned long flags; | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 317 | struct opl4_voice *voice; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 318 |  | 
|  | 319 | spin_lock_irqsave(&opl4->reg_lock, flags); | 
|  | 320 | for (i = 0; i < OPL4_MAX_VOICES; i++) { | 
|  | 321 | voice = &opl4->voices[i]; | 
|  | 322 | if (voice->chan == chan && voice->note == note) { | 
|  | 323 | func(opl4, voice); | 
|  | 324 | } | 
|  | 325 | } | 
|  | 326 | spin_unlock_irqrestore(&opl4->reg_lock, flags); | 
|  | 327 | } | 
|  | 328 |  | 
|  | 329 | /* | 
|  | 330 | * Executes the callback for all voices of to the specified channel. | 
|  | 331 | */ | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 332 | static void snd_opl4_do_for_channel(struct snd_opl4 *opl4, | 
|  | 333 | struct snd_midi_channel *chan, | 
|  | 334 | void (*func)(struct snd_opl4 *opl4, struct opl4_voice *voice)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 335 | { | 
|  | 336 | int i; | 
|  | 337 | unsigned long flags; | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 338 | struct opl4_voice *voice; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 339 |  | 
|  | 340 | spin_lock_irqsave(&opl4->reg_lock, flags); | 
|  | 341 | for (i = 0; i < OPL4_MAX_VOICES; i++) { | 
|  | 342 | voice = &opl4->voices[i]; | 
|  | 343 | if (voice->chan == chan) { | 
|  | 344 | func(opl4, voice); | 
|  | 345 | } | 
|  | 346 | } | 
|  | 347 | spin_unlock_irqrestore(&opl4->reg_lock, flags); | 
|  | 348 | } | 
|  | 349 |  | 
|  | 350 | /* | 
|  | 351 | * Executes the callback for all active voices. | 
|  | 352 | */ | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 353 | static void snd_opl4_do_for_all(struct snd_opl4 *opl4, | 
|  | 354 | void (*func)(struct snd_opl4 *opl4, struct opl4_voice *voice)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 355 | { | 
|  | 356 | int i; | 
|  | 357 | unsigned long flags; | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 358 | struct opl4_voice *voice; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 359 |  | 
|  | 360 | spin_lock_irqsave(&opl4->reg_lock, flags); | 
|  | 361 | for (i = 0; i < OPL4_MAX_VOICES; i++) { | 
|  | 362 | voice = &opl4->voices[i]; | 
|  | 363 | if (voice->chan) | 
|  | 364 | func(opl4, voice); | 
|  | 365 | } | 
|  | 366 | spin_unlock_irqrestore(&opl4->reg_lock, flags); | 
|  | 367 | } | 
|  | 368 |  | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 369 | static void snd_opl4_update_volume(struct snd_opl4 *opl4, struct opl4_voice *voice) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 370 | { | 
|  | 371 | int att; | 
|  | 372 |  | 
|  | 373 | att = voice->sound->tone_attenuate; | 
|  | 374 | att += snd_opl4_volume_table[opl4->chset->gs_master_volume & 0x7f]; | 
|  | 375 | att += snd_opl4_volume_table[voice->chan->gm_volume & 0x7f]; | 
|  | 376 | att += snd_opl4_volume_table[voice->chan->gm_expression & 0x7f]; | 
|  | 377 | att += snd_opl4_volume_table[voice->velocity]; | 
|  | 378 | att = 0x7f - (0x7f - att) * (voice->sound->volume_factor) / 0xfe - volume_boost; | 
|  | 379 | if (att < 0) | 
|  | 380 | att = 0; | 
|  | 381 | else if (att > 0x7e) | 
|  | 382 | att = 0x7e; | 
|  | 383 | snd_opl4_write(opl4, OPL4_REG_LEVEL + voice->number, | 
|  | 384 | (att << 1) | voice->level_direct); | 
|  | 385 | voice->level_direct = 0; | 
|  | 386 | } | 
|  | 387 |  | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 388 | static void snd_opl4_update_pan(struct snd_opl4 *opl4, struct opl4_voice *voice) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 389 | { | 
|  | 390 | int pan = voice->sound->panpot; | 
|  | 391 |  | 
|  | 392 | if (!voice->chan->drum_channel) | 
|  | 393 | pan += (voice->chan->control[MIDI_CTL_MSB_PAN] - 0x40) >> 3; | 
|  | 394 | if (pan < -7) | 
|  | 395 | pan = -7; | 
|  | 396 | else if (pan > 7) | 
|  | 397 | pan = 7; | 
|  | 398 | voice->reg_misc = (voice->reg_misc & ~OPL4_PAN_POT_MASK) | 
|  | 399 | | (pan & OPL4_PAN_POT_MASK); | 
|  | 400 | snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc); | 
|  | 401 | } | 
|  | 402 |  | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 403 | static void snd_opl4_update_vibrato_depth(struct snd_opl4 *opl4, | 
|  | 404 | struct opl4_voice *voice) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 405 | { | 
|  | 406 | int depth; | 
|  | 407 |  | 
|  | 408 | if (voice->chan->drum_channel) | 
|  | 409 | return; | 
|  | 410 | depth = (7 - voice->sound->vibrato) | 
|  | 411 | * (voice->chan->control[MIDI_CTL_VIBRATO_DEPTH] & 0x7f); | 
|  | 412 | depth = (depth >> 7) + voice->sound->vibrato; | 
|  | 413 | voice->reg_lfo_vibrato &= ~OPL4_VIBRATO_DEPTH_MASK; | 
|  | 414 | voice->reg_lfo_vibrato |= depth & OPL4_VIBRATO_DEPTH_MASK; | 
|  | 415 | snd_opl4_write(opl4, OPL4_REG_LFO_VIBRATO + voice->number, | 
|  | 416 | voice->reg_lfo_vibrato); | 
|  | 417 | } | 
|  | 418 |  | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 419 | static void snd_opl4_update_pitch(struct snd_opl4 *opl4, | 
|  | 420 | struct opl4_voice *voice) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 421 | { | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 422 | struct snd_midi_channel *chan = voice->chan; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 423 | int note, pitch, octave; | 
|  | 424 |  | 
|  | 425 | note = chan->drum_channel ? 60 : voice->note; | 
|  | 426 | /* | 
|  | 427 | * pitch is in 100/128 cents, so 0x80 is one semitone and | 
|  | 428 | * 0x600 is one octave. | 
|  | 429 | */ | 
|  | 430 | pitch = ((note - 60) << 7) * voice->sound->key_scaling / 100 + (60 << 7); | 
|  | 431 | pitch += voice->sound->pitch_offset; | 
|  | 432 | if (!chan->drum_channel) | 
|  | 433 | pitch += chan->gm_rpn_coarse_tuning; | 
|  | 434 | pitch += chan->gm_rpn_fine_tuning >> 7; | 
|  | 435 | pitch += chan->midi_pitchbend * chan->gm_rpn_pitch_bend_range / 0x2000; | 
|  | 436 | if (pitch < 0) | 
|  | 437 | pitch = 0; | 
|  | 438 | else if (pitch >= 0x6000) | 
|  | 439 | pitch = 0x5fff; | 
|  | 440 | octave = pitch / 0x600 - 8; | 
|  | 441 | pitch = snd_opl4_pitch_map[pitch % 0x600]; | 
|  | 442 |  | 
|  | 443 | snd_opl4_write(opl4, OPL4_REG_OCTAVE + voice->number, | 
|  | 444 | (octave << 4) | ((pitch >> 7) & OPL4_F_NUMBER_HIGH_MASK)); | 
|  | 445 | voice->reg_f_number = (voice->reg_f_number & OPL4_TONE_NUMBER_BIT8) | 
|  | 446 | | ((pitch << 1) & OPL4_F_NUMBER_LOW_MASK); | 
|  | 447 | snd_opl4_write(opl4, OPL4_REG_F_NUMBER + voice->number, voice->reg_f_number); | 
|  | 448 | } | 
|  | 449 |  | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 450 | static void snd_opl4_update_tone_parameters(struct snd_opl4 *opl4, | 
|  | 451 | struct opl4_voice *voice) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 452 | { | 
|  | 453 | snd_opl4_write(opl4, OPL4_REG_ATTACK_DECAY1 + voice->number, | 
|  | 454 | voice->sound->reg_attack_decay1); | 
|  | 455 | snd_opl4_write(opl4, OPL4_REG_LEVEL_DECAY2 + voice->number, | 
|  | 456 | voice->sound->reg_level_decay2); | 
|  | 457 | snd_opl4_write(opl4, OPL4_REG_RELEASE_CORRECTION + voice->number, | 
|  | 458 | voice->sound->reg_release_correction); | 
|  | 459 | snd_opl4_write(opl4, OPL4_REG_TREMOLO + voice->number, | 
|  | 460 | voice->sound->reg_tremolo); | 
|  | 461 | } | 
|  | 462 |  | 
|  | 463 | /* allocate one voice */ | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 464 | static struct opl4_voice *snd_opl4_get_voice(struct snd_opl4 *opl4) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 465 | { | 
|  | 466 | /* first, try to get the oldest key-off voice */ | 
|  | 467 | if (!list_empty(&opl4->off_voices)) | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 468 | return list_entry(opl4->off_voices.next, struct opl4_voice, list); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 469 | /* then get the oldest key-on voice */ | 
|  | 470 | snd_assert(!list_empty(&opl4->on_voices), ); | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 471 | return list_entry(opl4->on_voices.next, struct opl4_voice, list); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 472 | } | 
|  | 473 |  | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 474 | static void snd_opl4_wait_for_wave_headers(struct snd_opl4 *opl4) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 475 | { | 
|  | 476 | int timeout = 200; | 
|  | 477 |  | 
|  | 478 | while ((inb(opl4->fm_port) & OPL4_STATUS_LOAD) && --timeout > 0) | 
|  | 479 | udelay(10); | 
|  | 480 | } | 
|  | 481 |  | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 482 | void snd_opl4_note_on(void *private_data, int note, int vel, struct snd_midi_channel *chan) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 483 | { | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 484 | struct snd_opl4 *opl4 = private_data; | 
|  | 485 | const struct opl4_region_ptr *regions; | 
|  | 486 | struct opl4_voice *voice[2]; | 
|  | 487 | const struct opl4_sound *sound[2]; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 488 | int voices = 0, i; | 
|  | 489 | unsigned long flags; | 
|  | 490 |  | 
|  | 491 | /* determine the number of voices and voice parameters */ | 
|  | 492 | i = chan->drum_channel ? 0x80 : (chan->midi_program & 0x7f); | 
|  | 493 | regions = &snd_yrw801_regions[i]; | 
|  | 494 | for (i = 0; i < regions->count; i++) { | 
|  | 495 | if (note >= regions->regions[i].key_min && | 
|  | 496 | note <= regions->regions[i].key_max) { | 
|  | 497 | sound[voices] = ®ions->regions[i].sound; | 
|  | 498 | if (++voices >= 2) | 
|  | 499 | break; | 
|  | 500 | } | 
|  | 501 | } | 
|  | 502 |  | 
|  | 503 | /* allocate and initialize the needed voices */ | 
|  | 504 | spin_lock_irqsave(&opl4->reg_lock, flags); | 
|  | 505 | for (i = 0; i < voices; i++) { | 
|  | 506 | voice[i] = snd_opl4_get_voice(opl4); | 
|  | 507 | list_del(&voice[i]->list); | 
|  | 508 | list_add_tail(&voice[i]->list, &opl4->on_voices); | 
|  | 509 | voice[i]->chan = chan; | 
|  | 510 | voice[i]->note = note; | 
|  | 511 | voice[i]->velocity = vel & 0x7f; | 
|  | 512 | voice[i]->sound = sound[i]; | 
|  | 513 | } | 
|  | 514 |  | 
|  | 515 | /* set tone number (triggers header loading) */ | 
|  | 516 | for (i = 0; i < voices; i++) { | 
|  | 517 | voice[i]->reg_f_number = | 
|  | 518 | (sound[i]->tone >> 8) & OPL4_TONE_NUMBER_BIT8; | 
|  | 519 | snd_opl4_write(opl4, OPL4_REG_F_NUMBER + voice[i]->number, | 
|  | 520 | voice[i]->reg_f_number); | 
|  | 521 | snd_opl4_write(opl4, OPL4_REG_TONE_NUMBER + voice[i]->number, | 
|  | 522 | sound[i]->tone & 0xff); | 
|  | 523 | } | 
|  | 524 |  | 
|  | 525 | /* set parameters which can be set while loading */ | 
|  | 526 | for (i = 0; i < voices; i++) { | 
|  | 527 | voice[i]->reg_misc = OPL4_LFO_RESET_BIT; | 
|  | 528 | snd_opl4_update_pan(opl4, voice[i]); | 
|  | 529 | snd_opl4_update_pitch(opl4, voice[i]); | 
|  | 530 | voice[i]->level_direct = OPL4_LEVEL_DIRECT_BIT; | 
|  | 531 | snd_opl4_update_volume(opl4, voice[i]); | 
|  | 532 | } | 
|  | 533 | spin_unlock_irqrestore(&opl4->reg_lock, flags); | 
|  | 534 |  | 
|  | 535 | /* wait for completion of loading */ | 
|  | 536 | snd_opl4_wait_for_wave_headers(opl4); | 
|  | 537 |  | 
|  | 538 | /* set remaining parameters */ | 
|  | 539 | spin_lock_irqsave(&opl4->reg_lock, flags); | 
|  | 540 | for (i = 0; i < voices; i++) { | 
|  | 541 | snd_opl4_update_tone_parameters(opl4, voice[i]); | 
|  | 542 | voice[i]->reg_lfo_vibrato = voice[i]->sound->reg_lfo_vibrato; | 
|  | 543 | snd_opl4_update_vibrato_depth(opl4, voice[i]); | 
|  | 544 | } | 
|  | 545 |  | 
|  | 546 | /* finally, switch on all voices */ | 
|  | 547 | for (i = 0; i < voices; i++) { | 
|  | 548 | voice[i]->reg_misc = | 
|  | 549 | (voice[i]->reg_misc & 0x1f) | OPL4_KEY_ON_BIT; | 
|  | 550 | snd_opl4_write(opl4, OPL4_REG_MISC + voice[i]->number, | 
|  | 551 | voice[i]->reg_misc); | 
|  | 552 | } | 
|  | 553 | spin_unlock_irqrestore(&opl4->reg_lock, flags); | 
|  | 554 | } | 
|  | 555 |  | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 556 | static void snd_opl4_voice_off(struct snd_opl4 *opl4, struct opl4_voice *voice) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 557 | { | 
|  | 558 | list_del(&voice->list); | 
|  | 559 | list_add_tail(&voice->list, &opl4->off_voices); | 
|  | 560 |  | 
|  | 561 | voice->reg_misc &= ~OPL4_KEY_ON_BIT; | 
|  | 562 | snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc); | 
|  | 563 | } | 
|  | 564 |  | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 565 | void snd_opl4_note_off(void *private_data, int note, int vel, struct snd_midi_channel *chan) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 566 | { | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 567 | struct snd_opl4 *opl4 = private_data; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 568 |  | 
|  | 569 | snd_opl4_do_for_note(opl4, note, chan, snd_opl4_voice_off); | 
|  | 570 | } | 
|  | 571 |  | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 572 | static void snd_opl4_terminate_voice(struct snd_opl4 *opl4, struct opl4_voice *voice) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 573 | { | 
|  | 574 | list_del(&voice->list); | 
|  | 575 | list_add_tail(&voice->list, &opl4->off_voices); | 
|  | 576 |  | 
|  | 577 | voice->reg_misc = (voice->reg_misc & ~OPL4_KEY_ON_BIT) | OPL4_DAMP_BIT; | 
|  | 578 | snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc); | 
|  | 579 | } | 
|  | 580 |  | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 581 | void snd_opl4_terminate_note(void *private_data, int note, struct snd_midi_channel *chan) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 582 | { | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 583 | struct snd_opl4 *opl4 = private_data; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 584 |  | 
|  | 585 | snd_opl4_do_for_note(opl4, note, chan, snd_opl4_terminate_voice); | 
|  | 586 | } | 
|  | 587 |  | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 588 | void snd_opl4_control(void *private_data, int type, struct snd_midi_channel *chan) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 589 | { | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 590 | struct snd_opl4 *opl4 = private_data; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 591 |  | 
|  | 592 | switch (type) { | 
|  | 593 | case MIDI_CTL_MSB_MODWHEEL: | 
|  | 594 | chan->control[MIDI_CTL_VIBRATO_DEPTH] = chan->control[MIDI_CTL_MSB_MODWHEEL]; | 
|  | 595 | snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_vibrato_depth); | 
|  | 596 | break; | 
|  | 597 | case MIDI_CTL_MSB_MAIN_VOLUME: | 
|  | 598 | snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_volume); | 
|  | 599 | break; | 
|  | 600 | case MIDI_CTL_MSB_PAN: | 
|  | 601 | snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_pan); | 
|  | 602 | break; | 
|  | 603 | case MIDI_CTL_MSB_EXPRESSION: | 
|  | 604 | snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_volume); | 
|  | 605 | break; | 
|  | 606 | case MIDI_CTL_VIBRATO_RATE: | 
|  | 607 | /* not yet supported */ | 
|  | 608 | break; | 
|  | 609 | case MIDI_CTL_VIBRATO_DEPTH: | 
|  | 610 | snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_vibrato_depth); | 
|  | 611 | break; | 
|  | 612 | case MIDI_CTL_VIBRATO_DELAY: | 
|  | 613 | /* not yet supported */ | 
|  | 614 | break; | 
|  | 615 | case MIDI_CTL_E1_REVERB_DEPTH: | 
|  | 616 | /* | 
|  | 617 | * Each OPL4 voice has a bit called "Pseudo-Reverb", but | 
|  | 618 | * IMHO _not_ using it enhances the listening experience. | 
|  | 619 | */ | 
|  | 620 | break; | 
|  | 621 | case MIDI_CTL_PITCHBEND: | 
|  | 622 | snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_pitch); | 
|  | 623 | break; | 
|  | 624 | } | 
|  | 625 | } | 
|  | 626 |  | 
|  | 627 | void snd_opl4_sysex(void *private_data, unsigned char *buf, int len, | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 628 | int parsed, struct snd_midi_channel_set *chset) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 629 | { | 
| Takashi Iwai | a42dd42 | 2005-11-17 14:13:47 +0100 | [diff] [blame] | 630 | struct snd_opl4 *opl4 = private_data; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 631 |  | 
|  | 632 | if (parsed == SNDRV_MIDI_SYSEX_GS_MASTER_VOLUME) | 
|  | 633 | snd_opl4_do_for_all(opl4, snd_opl4_update_volume); | 
|  | 634 | } |