xref: /openbmc/linux/sound/drivers/opl4/opl4_synth.c (revision 8dd06ef34b6e2f41b29fbf5fc1663780f2524285)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * OPL4 MIDI synthesizer functions
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Copyright (c) 2003 by Clemens Ladisch <clemens@ladisch.de>
51da177e4SLinus Torvalds  * All rights reserved.
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * Redistribution and use in source and binary forms, with or without
81da177e4SLinus Torvalds  * modification, are permitted provided that the following conditions
91da177e4SLinus Torvalds  * are met:
101da177e4SLinus Torvalds  * 1. Redistributions of source code must retain the above copyright
111da177e4SLinus Torvalds  *    notice, this list of conditions, and the following disclaimer,
121da177e4SLinus Torvalds  *    without modification.
131da177e4SLinus Torvalds  * 2. The name of the author may not be used to endorse or promote products
141da177e4SLinus Torvalds  *    derived from this software without specific prior written permission.
151da177e4SLinus Torvalds  *
161da177e4SLinus Torvalds  * Alternatively, this software may be distributed and/or modified under the
171da177e4SLinus Torvalds  * terms of the GNU General Public License as published by the Free Software
181da177e4SLinus Torvalds  * Foundation; either version 2 of the License, or (at your option) any later
191da177e4SLinus Torvalds  * version.
201da177e4SLinus Torvalds  *
211da177e4SLinus Torvalds  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
221da177e4SLinus Torvalds  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231da177e4SLinus Torvalds  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241da177e4SLinus Torvalds  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
251da177e4SLinus Torvalds  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261da177e4SLinus Torvalds  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271da177e4SLinus Torvalds  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281da177e4SLinus Torvalds  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291da177e4SLinus Torvalds  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301da177e4SLinus Torvalds  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311da177e4SLinus Torvalds  * SUCH DAMAGE.
321da177e4SLinus Torvalds  */
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds #include "opl4_local.h"
351da177e4SLinus Torvalds #include <linux/delay.h>
366cbbfe1cSTakashi Iwai #include <linux/io.h>
371da177e4SLinus Torvalds #include <sound/asoundef.h>
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds /* GM2 controllers */
401da177e4SLinus Torvalds #ifndef MIDI_CTL_RELEASE_TIME
411da177e4SLinus Torvalds #define MIDI_CTL_RELEASE_TIME	0x48
421da177e4SLinus Torvalds #define MIDI_CTL_ATTACK_TIME	0x49
431da177e4SLinus Torvalds #define MIDI_CTL_DECAY_TIME	0x4b
441da177e4SLinus Torvalds #define MIDI_CTL_VIBRATO_RATE	0x4c
451da177e4SLinus Torvalds #define MIDI_CTL_VIBRATO_DEPTH	0x4d
461da177e4SLinus Torvalds #define MIDI_CTL_VIBRATO_DELAY	0x4e
471da177e4SLinus Torvalds #endif
481da177e4SLinus Torvalds 
491da177e4SLinus Torvalds /*
501da177e4SLinus Torvalds  * This table maps 100/128 cents to F_NUMBER.
511da177e4SLinus Torvalds  */
521da177e4SLinus Torvalds static const s16 snd_opl4_pitch_map[0x600] = {
531da177e4SLinus Torvalds 	0x000,0x000,0x001,0x001,0x002,0x002,0x003,0x003,
541da177e4SLinus Torvalds 	0x004,0x004,0x005,0x005,0x006,0x006,0x006,0x007,
551da177e4SLinus Torvalds 	0x007,0x008,0x008,0x009,0x009,0x00a,0x00a,0x00b,
561da177e4SLinus Torvalds 	0x00b,0x00c,0x00c,0x00d,0x00d,0x00d,0x00e,0x00e,
571da177e4SLinus Torvalds 	0x00f,0x00f,0x010,0x010,0x011,0x011,0x012,0x012,
581da177e4SLinus Torvalds 	0x013,0x013,0x014,0x014,0x015,0x015,0x015,0x016,
591da177e4SLinus Torvalds 	0x016,0x017,0x017,0x018,0x018,0x019,0x019,0x01a,
601da177e4SLinus Torvalds 	0x01a,0x01b,0x01b,0x01c,0x01c,0x01d,0x01d,0x01e,
611da177e4SLinus Torvalds 	0x01e,0x01e,0x01f,0x01f,0x020,0x020,0x021,0x021,
621da177e4SLinus Torvalds 	0x022,0x022,0x023,0x023,0x024,0x024,0x025,0x025,
631da177e4SLinus Torvalds 	0x026,0x026,0x027,0x027,0x028,0x028,0x029,0x029,
641da177e4SLinus Torvalds 	0x029,0x02a,0x02a,0x02b,0x02b,0x02c,0x02c,0x02d,
651da177e4SLinus Torvalds 	0x02d,0x02e,0x02e,0x02f,0x02f,0x030,0x030,0x031,
661da177e4SLinus Torvalds 	0x031,0x032,0x032,0x033,0x033,0x034,0x034,0x035,
671da177e4SLinus Torvalds 	0x035,0x036,0x036,0x037,0x037,0x038,0x038,0x038,
681da177e4SLinus Torvalds 	0x039,0x039,0x03a,0x03a,0x03b,0x03b,0x03c,0x03c,
691da177e4SLinus Torvalds 	0x03d,0x03d,0x03e,0x03e,0x03f,0x03f,0x040,0x040,
701da177e4SLinus Torvalds 	0x041,0x041,0x042,0x042,0x043,0x043,0x044,0x044,
711da177e4SLinus Torvalds 	0x045,0x045,0x046,0x046,0x047,0x047,0x048,0x048,
721da177e4SLinus Torvalds 	0x049,0x049,0x04a,0x04a,0x04b,0x04b,0x04c,0x04c,
731da177e4SLinus Torvalds 	0x04d,0x04d,0x04e,0x04e,0x04f,0x04f,0x050,0x050,
741da177e4SLinus Torvalds 	0x051,0x051,0x052,0x052,0x053,0x053,0x054,0x054,
751da177e4SLinus Torvalds 	0x055,0x055,0x056,0x056,0x057,0x057,0x058,0x058,
761da177e4SLinus Torvalds 	0x059,0x059,0x05a,0x05a,0x05b,0x05b,0x05c,0x05c,
771da177e4SLinus Torvalds 	0x05d,0x05d,0x05e,0x05e,0x05f,0x05f,0x060,0x060,
781da177e4SLinus Torvalds 	0x061,0x061,0x062,0x062,0x063,0x063,0x064,0x064,
791da177e4SLinus Torvalds 	0x065,0x065,0x066,0x066,0x067,0x067,0x068,0x068,
801da177e4SLinus Torvalds 	0x069,0x069,0x06a,0x06a,0x06b,0x06b,0x06c,0x06c,
811da177e4SLinus Torvalds 	0x06d,0x06d,0x06e,0x06e,0x06f,0x06f,0x070,0x071,
821da177e4SLinus Torvalds 	0x071,0x072,0x072,0x073,0x073,0x074,0x074,0x075,
831da177e4SLinus Torvalds 	0x075,0x076,0x076,0x077,0x077,0x078,0x078,0x079,
841da177e4SLinus Torvalds 	0x079,0x07a,0x07a,0x07b,0x07b,0x07c,0x07c,0x07d,
851da177e4SLinus Torvalds 	0x07d,0x07e,0x07e,0x07f,0x07f,0x080,0x081,0x081,
861da177e4SLinus Torvalds 	0x082,0x082,0x083,0x083,0x084,0x084,0x085,0x085,
871da177e4SLinus Torvalds 	0x086,0x086,0x087,0x087,0x088,0x088,0x089,0x089,
881da177e4SLinus Torvalds 	0x08a,0x08a,0x08b,0x08b,0x08c,0x08d,0x08d,0x08e,
891da177e4SLinus Torvalds 	0x08e,0x08f,0x08f,0x090,0x090,0x091,0x091,0x092,
901da177e4SLinus Torvalds 	0x092,0x093,0x093,0x094,0x094,0x095,0x096,0x096,
911da177e4SLinus Torvalds 	0x097,0x097,0x098,0x098,0x099,0x099,0x09a,0x09a,
921da177e4SLinus Torvalds 	0x09b,0x09b,0x09c,0x09c,0x09d,0x09d,0x09e,0x09f,
931da177e4SLinus Torvalds 	0x09f,0x0a0,0x0a0,0x0a1,0x0a1,0x0a2,0x0a2,0x0a3,
941da177e4SLinus Torvalds 	0x0a3,0x0a4,0x0a4,0x0a5,0x0a6,0x0a6,0x0a7,0x0a7,
951da177e4SLinus Torvalds 	0x0a8,0x0a8,0x0a9,0x0a9,0x0aa,0x0aa,0x0ab,0x0ab,
961da177e4SLinus Torvalds 	0x0ac,0x0ad,0x0ad,0x0ae,0x0ae,0x0af,0x0af,0x0b0,
971da177e4SLinus Torvalds 	0x0b0,0x0b1,0x0b1,0x0b2,0x0b2,0x0b3,0x0b4,0x0b4,
981da177e4SLinus Torvalds 	0x0b5,0x0b5,0x0b6,0x0b6,0x0b7,0x0b7,0x0b8,0x0b8,
991da177e4SLinus Torvalds 	0x0b9,0x0ba,0x0ba,0x0bb,0x0bb,0x0bc,0x0bc,0x0bd,
1001da177e4SLinus Torvalds 	0x0bd,0x0be,0x0be,0x0bf,0x0c0,0x0c0,0x0c1,0x0c1,
1011da177e4SLinus Torvalds 	0x0c2,0x0c2,0x0c3,0x0c3,0x0c4,0x0c4,0x0c5,0x0c6,
1021da177e4SLinus Torvalds 	0x0c6,0x0c7,0x0c7,0x0c8,0x0c8,0x0c9,0x0c9,0x0ca,
1031da177e4SLinus Torvalds 	0x0cb,0x0cb,0x0cc,0x0cc,0x0cd,0x0cd,0x0ce,0x0ce,
1041da177e4SLinus Torvalds 	0x0cf,0x0d0,0x0d0,0x0d1,0x0d1,0x0d2,0x0d2,0x0d3,
1051da177e4SLinus Torvalds 	0x0d3,0x0d4,0x0d5,0x0d5,0x0d6,0x0d6,0x0d7,0x0d7,
1061da177e4SLinus Torvalds 	0x0d8,0x0d8,0x0d9,0x0da,0x0da,0x0db,0x0db,0x0dc,
1071da177e4SLinus Torvalds 	0x0dc,0x0dd,0x0de,0x0de,0x0df,0x0df,0x0e0,0x0e0,
1081da177e4SLinus Torvalds 	0x0e1,0x0e1,0x0e2,0x0e3,0x0e3,0x0e4,0x0e4,0x0e5,
1091da177e4SLinus Torvalds 	0x0e5,0x0e6,0x0e7,0x0e7,0x0e8,0x0e8,0x0e9,0x0e9,
1101da177e4SLinus Torvalds 	0x0ea,0x0eb,0x0eb,0x0ec,0x0ec,0x0ed,0x0ed,0x0ee,
1111da177e4SLinus Torvalds 	0x0ef,0x0ef,0x0f0,0x0f0,0x0f1,0x0f1,0x0f2,0x0f3,
1121da177e4SLinus Torvalds 	0x0f3,0x0f4,0x0f4,0x0f5,0x0f5,0x0f6,0x0f7,0x0f7,
1131da177e4SLinus Torvalds 	0x0f8,0x0f8,0x0f9,0x0f9,0x0fa,0x0fb,0x0fb,0x0fc,
1141da177e4SLinus Torvalds 	0x0fc,0x0fd,0x0fd,0x0fe,0x0ff,0x0ff,0x100,0x100,
1151da177e4SLinus Torvalds 	0x101,0x101,0x102,0x103,0x103,0x104,0x104,0x105,
1161da177e4SLinus Torvalds 	0x106,0x106,0x107,0x107,0x108,0x108,0x109,0x10a,
1171da177e4SLinus Torvalds 	0x10a,0x10b,0x10b,0x10c,0x10c,0x10d,0x10e,0x10e,
1181da177e4SLinus Torvalds 	0x10f,0x10f,0x110,0x111,0x111,0x112,0x112,0x113,
1191da177e4SLinus Torvalds 	0x114,0x114,0x115,0x115,0x116,0x116,0x117,0x118,
1201da177e4SLinus Torvalds 	0x118,0x119,0x119,0x11a,0x11b,0x11b,0x11c,0x11c,
1211da177e4SLinus Torvalds 	0x11d,0x11e,0x11e,0x11f,0x11f,0x120,0x120,0x121,
1221da177e4SLinus Torvalds 	0x122,0x122,0x123,0x123,0x124,0x125,0x125,0x126,
1231da177e4SLinus Torvalds 	0x126,0x127,0x128,0x128,0x129,0x129,0x12a,0x12b,
1241da177e4SLinus Torvalds 	0x12b,0x12c,0x12c,0x12d,0x12e,0x12e,0x12f,0x12f,
1251da177e4SLinus Torvalds 	0x130,0x131,0x131,0x132,0x132,0x133,0x134,0x134,
1261da177e4SLinus Torvalds 	0x135,0x135,0x136,0x137,0x137,0x138,0x138,0x139,
1271da177e4SLinus Torvalds 	0x13a,0x13a,0x13b,0x13b,0x13c,0x13d,0x13d,0x13e,
1281da177e4SLinus Torvalds 	0x13e,0x13f,0x140,0x140,0x141,0x141,0x142,0x143,
1291da177e4SLinus Torvalds 	0x143,0x144,0x144,0x145,0x146,0x146,0x147,0x148,
1301da177e4SLinus Torvalds 	0x148,0x149,0x149,0x14a,0x14b,0x14b,0x14c,0x14c,
1311da177e4SLinus Torvalds 	0x14d,0x14e,0x14e,0x14f,0x14f,0x150,0x151,0x151,
1321da177e4SLinus Torvalds 	0x152,0x153,0x153,0x154,0x154,0x155,0x156,0x156,
1331da177e4SLinus Torvalds 	0x157,0x157,0x158,0x159,0x159,0x15a,0x15b,0x15b,
1341da177e4SLinus Torvalds 	0x15c,0x15c,0x15d,0x15e,0x15e,0x15f,0x160,0x160,
1351da177e4SLinus Torvalds 	0x161,0x161,0x162,0x163,0x163,0x164,0x165,0x165,
1361da177e4SLinus Torvalds 	0x166,0x166,0x167,0x168,0x168,0x169,0x16a,0x16a,
1371da177e4SLinus Torvalds 	0x16b,0x16b,0x16c,0x16d,0x16d,0x16e,0x16f,0x16f,
1381da177e4SLinus Torvalds 	0x170,0x170,0x171,0x172,0x172,0x173,0x174,0x174,
1391da177e4SLinus Torvalds 	0x175,0x175,0x176,0x177,0x177,0x178,0x179,0x179,
1401da177e4SLinus Torvalds 	0x17a,0x17a,0x17b,0x17c,0x17c,0x17d,0x17e,0x17e,
1411da177e4SLinus Torvalds 	0x17f,0x180,0x180,0x181,0x181,0x182,0x183,0x183,
1421da177e4SLinus Torvalds 	0x184,0x185,0x185,0x186,0x187,0x187,0x188,0x188,
1431da177e4SLinus Torvalds 	0x189,0x18a,0x18a,0x18b,0x18c,0x18c,0x18d,0x18e,
1441da177e4SLinus Torvalds 	0x18e,0x18f,0x190,0x190,0x191,0x191,0x192,0x193,
1451da177e4SLinus Torvalds 	0x193,0x194,0x195,0x195,0x196,0x197,0x197,0x198,
1461da177e4SLinus Torvalds 	0x199,0x199,0x19a,0x19a,0x19b,0x19c,0x19c,0x19d,
1471da177e4SLinus Torvalds 	0x19e,0x19e,0x19f,0x1a0,0x1a0,0x1a1,0x1a2,0x1a2,
1481da177e4SLinus Torvalds 	0x1a3,0x1a4,0x1a4,0x1a5,0x1a6,0x1a6,0x1a7,0x1a8,
1491da177e4SLinus Torvalds 	0x1a8,0x1a9,0x1a9,0x1aa,0x1ab,0x1ab,0x1ac,0x1ad,
1501da177e4SLinus Torvalds 	0x1ad,0x1ae,0x1af,0x1af,0x1b0,0x1b1,0x1b1,0x1b2,
1511da177e4SLinus Torvalds 	0x1b3,0x1b3,0x1b4,0x1b5,0x1b5,0x1b6,0x1b7,0x1b7,
1521da177e4SLinus Torvalds 	0x1b8,0x1b9,0x1b9,0x1ba,0x1bb,0x1bb,0x1bc,0x1bd,
1531da177e4SLinus Torvalds 	0x1bd,0x1be,0x1bf,0x1bf,0x1c0,0x1c1,0x1c1,0x1c2,
1541da177e4SLinus Torvalds 	0x1c3,0x1c3,0x1c4,0x1c5,0x1c5,0x1c6,0x1c7,0x1c7,
1551da177e4SLinus Torvalds 	0x1c8,0x1c9,0x1c9,0x1ca,0x1cb,0x1cb,0x1cc,0x1cd,
1561da177e4SLinus Torvalds 	0x1cd,0x1ce,0x1cf,0x1cf,0x1d0,0x1d1,0x1d1,0x1d2,
1571da177e4SLinus Torvalds 	0x1d3,0x1d3,0x1d4,0x1d5,0x1d5,0x1d6,0x1d7,0x1d7,
1581da177e4SLinus Torvalds 	0x1d8,0x1d9,0x1d9,0x1da,0x1db,0x1db,0x1dc,0x1dd,
1591da177e4SLinus Torvalds 	0x1dd,0x1de,0x1df,0x1df,0x1e0,0x1e1,0x1e1,0x1e2,
1601da177e4SLinus Torvalds 	0x1e3,0x1e4,0x1e4,0x1e5,0x1e6,0x1e6,0x1e7,0x1e8,
1611da177e4SLinus Torvalds 	0x1e8,0x1e9,0x1ea,0x1ea,0x1eb,0x1ec,0x1ec,0x1ed,
1621da177e4SLinus Torvalds 	0x1ee,0x1ee,0x1ef,0x1f0,0x1f0,0x1f1,0x1f2,0x1f3,
1631da177e4SLinus Torvalds 	0x1f3,0x1f4,0x1f5,0x1f5,0x1f6,0x1f7,0x1f7,0x1f8,
1641da177e4SLinus Torvalds 	0x1f9,0x1f9,0x1fa,0x1fb,0x1fb,0x1fc,0x1fd,0x1fe,
1651da177e4SLinus Torvalds 	0x1fe,0x1ff,0x200,0x200,0x201,0x202,0x202,0x203,
1661da177e4SLinus Torvalds 	0x204,0x205,0x205,0x206,0x207,0x207,0x208,0x209,
1671da177e4SLinus Torvalds 	0x209,0x20a,0x20b,0x20b,0x20c,0x20d,0x20e,0x20e,
1681da177e4SLinus Torvalds 	0x20f,0x210,0x210,0x211,0x212,0x212,0x213,0x214,
1691da177e4SLinus Torvalds 	0x215,0x215,0x216,0x217,0x217,0x218,0x219,0x21a,
1701da177e4SLinus Torvalds 	0x21a,0x21b,0x21c,0x21c,0x21d,0x21e,0x21e,0x21f,
1711da177e4SLinus Torvalds 	0x220,0x221,0x221,0x222,0x223,0x223,0x224,0x225,
1721da177e4SLinus Torvalds 	0x226,0x226,0x227,0x228,0x228,0x229,0x22a,0x22b,
1731da177e4SLinus Torvalds 	0x22b,0x22c,0x22d,0x22d,0x22e,0x22f,0x230,0x230,
1741da177e4SLinus Torvalds 	0x231,0x232,0x232,0x233,0x234,0x235,0x235,0x236,
1751da177e4SLinus Torvalds 	0x237,0x237,0x238,0x239,0x23a,0x23a,0x23b,0x23c,
1761da177e4SLinus Torvalds 	0x23c,0x23d,0x23e,0x23f,0x23f,0x240,0x241,0x241,
1771da177e4SLinus Torvalds 	0x242,0x243,0x244,0x244,0x245,0x246,0x247,0x247,
1781da177e4SLinus Torvalds 	0x248,0x249,0x249,0x24a,0x24b,0x24c,0x24c,0x24d,
1791da177e4SLinus Torvalds 	0x24e,0x24f,0x24f,0x250,0x251,0x251,0x252,0x253,
1801da177e4SLinus Torvalds 	0x254,0x254,0x255,0x256,0x257,0x257,0x258,0x259,
1811da177e4SLinus Torvalds 	0x259,0x25a,0x25b,0x25c,0x25c,0x25d,0x25e,0x25f,
1821da177e4SLinus Torvalds 	0x25f,0x260,0x261,0x262,0x262,0x263,0x264,0x265,
1831da177e4SLinus Torvalds 	0x265,0x266,0x267,0x267,0x268,0x269,0x26a,0x26a,
1841da177e4SLinus Torvalds 	0x26b,0x26c,0x26d,0x26d,0x26e,0x26f,0x270,0x270,
1851da177e4SLinus Torvalds 	0x271,0x272,0x273,0x273,0x274,0x275,0x276,0x276,
1861da177e4SLinus Torvalds 	0x277,0x278,0x279,0x279,0x27a,0x27b,0x27c,0x27c,
1871da177e4SLinus Torvalds 	0x27d,0x27e,0x27f,0x27f,0x280,0x281,0x282,0x282,
1881da177e4SLinus Torvalds 	0x283,0x284,0x285,0x285,0x286,0x287,0x288,0x288,
1891da177e4SLinus Torvalds 	0x289,0x28a,0x28b,0x28b,0x28c,0x28d,0x28e,0x28e,
1901da177e4SLinus Torvalds 	0x28f,0x290,0x291,0x291,0x292,0x293,0x294,0x294,
1911da177e4SLinus Torvalds 	0x295,0x296,0x297,0x298,0x298,0x299,0x29a,0x29b,
1921da177e4SLinus Torvalds 	0x29b,0x29c,0x29d,0x29e,0x29e,0x29f,0x2a0,0x2a1,
1931da177e4SLinus Torvalds 	0x2a1,0x2a2,0x2a3,0x2a4,0x2a5,0x2a5,0x2a6,0x2a7,
1941da177e4SLinus Torvalds 	0x2a8,0x2a8,0x2a9,0x2aa,0x2ab,0x2ab,0x2ac,0x2ad,
1951da177e4SLinus Torvalds 	0x2ae,0x2af,0x2af,0x2b0,0x2b1,0x2b2,0x2b2,0x2b3,
1961da177e4SLinus Torvalds 	0x2b4,0x2b5,0x2b5,0x2b6,0x2b7,0x2b8,0x2b9,0x2b9,
1971da177e4SLinus Torvalds 	0x2ba,0x2bb,0x2bc,0x2bc,0x2bd,0x2be,0x2bf,0x2c0,
1981da177e4SLinus Torvalds 	0x2c0,0x2c1,0x2c2,0x2c3,0x2c4,0x2c4,0x2c5,0x2c6,
1991da177e4SLinus Torvalds 	0x2c7,0x2c7,0x2c8,0x2c9,0x2ca,0x2cb,0x2cb,0x2cc,
2001da177e4SLinus Torvalds 	0x2cd,0x2ce,0x2ce,0x2cf,0x2d0,0x2d1,0x2d2,0x2d2,
2011da177e4SLinus Torvalds 	0x2d3,0x2d4,0x2d5,0x2d6,0x2d6,0x2d7,0x2d8,0x2d9,
2021da177e4SLinus Torvalds 	0x2da,0x2da,0x2db,0x2dc,0x2dd,0x2dd,0x2de,0x2df,
2031da177e4SLinus Torvalds 	0x2e0,0x2e1,0x2e1,0x2e2,0x2e3,0x2e4,0x2e5,0x2e5,
2041da177e4SLinus Torvalds 	0x2e6,0x2e7,0x2e8,0x2e9,0x2e9,0x2ea,0x2eb,0x2ec,
2051da177e4SLinus Torvalds 	0x2ed,0x2ed,0x2ee,0x2ef,0x2f0,0x2f1,0x2f1,0x2f2,
2061da177e4SLinus Torvalds 	0x2f3,0x2f4,0x2f5,0x2f5,0x2f6,0x2f7,0x2f8,0x2f9,
2071da177e4SLinus Torvalds 	0x2f9,0x2fa,0x2fb,0x2fc,0x2fd,0x2fd,0x2fe,0x2ff,
2081da177e4SLinus Torvalds 	0x300,0x301,0x302,0x302,0x303,0x304,0x305,0x306,
2091da177e4SLinus Torvalds 	0x306,0x307,0x308,0x309,0x30a,0x30a,0x30b,0x30c,
2101da177e4SLinus Torvalds 	0x30d,0x30e,0x30f,0x30f,0x310,0x311,0x312,0x313,
2111da177e4SLinus Torvalds 	0x313,0x314,0x315,0x316,0x317,0x318,0x318,0x319,
2121da177e4SLinus Torvalds 	0x31a,0x31b,0x31c,0x31c,0x31d,0x31e,0x31f,0x320,
2131da177e4SLinus Torvalds 	0x321,0x321,0x322,0x323,0x324,0x325,0x326,0x326,
2141da177e4SLinus Torvalds 	0x327,0x328,0x329,0x32a,0x32a,0x32b,0x32c,0x32d,
2151da177e4SLinus Torvalds 	0x32e,0x32f,0x32f,0x330,0x331,0x332,0x333,0x334,
2161da177e4SLinus Torvalds 	0x334,0x335,0x336,0x337,0x338,0x339,0x339,0x33a,
2171da177e4SLinus Torvalds 	0x33b,0x33c,0x33d,0x33e,0x33e,0x33f,0x340,0x341,
2181da177e4SLinus Torvalds 	0x342,0x343,0x343,0x344,0x345,0x346,0x347,0x348,
2191da177e4SLinus Torvalds 	0x349,0x349,0x34a,0x34b,0x34c,0x34d,0x34e,0x34e,
2201da177e4SLinus Torvalds 	0x34f,0x350,0x351,0x352,0x353,0x353,0x354,0x355,
2211da177e4SLinus Torvalds 	0x356,0x357,0x358,0x359,0x359,0x35a,0x35b,0x35c,
2221da177e4SLinus Torvalds 	0x35d,0x35e,0x35f,0x35f,0x360,0x361,0x362,0x363,
2231da177e4SLinus Torvalds 	0x364,0x364,0x365,0x366,0x367,0x368,0x369,0x36a,
2241da177e4SLinus Torvalds 	0x36a,0x36b,0x36c,0x36d,0x36e,0x36f,0x370,0x370,
2251da177e4SLinus Torvalds 	0x371,0x372,0x373,0x374,0x375,0x376,0x377,0x377,
2261da177e4SLinus Torvalds 	0x378,0x379,0x37a,0x37b,0x37c,0x37d,0x37d,0x37e,
2271da177e4SLinus Torvalds 	0x37f,0x380,0x381,0x382,0x383,0x383,0x384,0x385,
2281da177e4SLinus Torvalds 	0x386,0x387,0x388,0x389,0x38a,0x38a,0x38b,0x38c,
2291da177e4SLinus Torvalds 	0x38d,0x38e,0x38f,0x390,0x391,0x391,0x392,0x393,
2301da177e4SLinus Torvalds 	0x394,0x395,0x396,0x397,0x398,0x398,0x399,0x39a,
2311da177e4SLinus Torvalds 	0x39b,0x39c,0x39d,0x39e,0x39f,0x39f,0x3a0,0x3a1,
2321da177e4SLinus Torvalds 	0x3a2,0x3a3,0x3a4,0x3a5,0x3a6,0x3a7,0x3a7,0x3a8,
2331da177e4SLinus Torvalds 	0x3a9,0x3aa,0x3ab,0x3ac,0x3ad,0x3ae,0x3ae,0x3af,
2341da177e4SLinus Torvalds 	0x3b0,0x3b1,0x3b2,0x3b3,0x3b4,0x3b5,0x3b6,0x3b6,
2351da177e4SLinus Torvalds 	0x3b7,0x3b8,0x3b9,0x3ba,0x3bb,0x3bc,0x3bd,0x3be,
2361da177e4SLinus Torvalds 	0x3bf,0x3bf,0x3c0,0x3c1,0x3c2,0x3c3,0x3c4,0x3c5,
2371da177e4SLinus Torvalds 	0x3c6,0x3c7,0x3c7,0x3c8,0x3c9,0x3ca,0x3cb,0x3cc,
2381da177e4SLinus Torvalds 	0x3cd,0x3ce,0x3cf,0x3d0,0x3d1,0x3d1,0x3d2,0x3d3,
2391da177e4SLinus Torvalds 	0x3d4,0x3d5,0x3d6,0x3d7,0x3d8,0x3d9,0x3da,0x3da,
2401da177e4SLinus Torvalds 	0x3db,0x3dc,0x3dd,0x3de,0x3df,0x3e0,0x3e1,0x3e2,
2411da177e4SLinus Torvalds 	0x3e3,0x3e4,0x3e4,0x3e5,0x3e6,0x3e7,0x3e8,0x3e9,
2421da177e4SLinus Torvalds 	0x3ea,0x3eb,0x3ec,0x3ed,0x3ee,0x3ef,0x3ef,0x3f0,
2431da177e4SLinus Torvalds 	0x3f1,0x3f2,0x3f3,0x3f4,0x3f5,0x3f6,0x3f7,0x3f8,
2441da177e4SLinus Torvalds 	0x3f9,0x3fa,0x3fa,0x3fb,0x3fc,0x3fd,0x3fe,0x3ff
2451da177e4SLinus Torvalds };
2461da177e4SLinus Torvalds 
2471da177e4SLinus Torvalds /*
2481da177e4SLinus Torvalds  * Attenuation according to GM recommendations, in -0.375 dB units.
2491da177e4SLinus Torvalds  * table[v] = 40 * log(v / 127) / -0.375
2501da177e4SLinus Torvalds  */
251*1d99500aSTakashi Iwai static const unsigned char snd_opl4_volume_table[128] = {
2521da177e4SLinus Torvalds 	255,224,192,173,160,150,141,134,
2531da177e4SLinus Torvalds 	128,122,117,113,109,105,102, 99,
2541da177e4SLinus Torvalds 	 96, 93, 90, 88, 85, 83, 81, 79,
2551da177e4SLinus Torvalds 	 77, 75, 73, 71, 70, 68, 67, 65,
2561da177e4SLinus Torvalds 	 64, 62, 61, 59, 58, 57, 56, 54,
2571da177e4SLinus Torvalds 	 53, 52, 51, 50, 49, 48, 47, 46,
2581da177e4SLinus Torvalds 	 45, 44, 43, 42, 41, 40, 39, 39,
2591da177e4SLinus Torvalds 	 38, 37, 36, 35, 34, 34, 33, 32,
2601da177e4SLinus Torvalds 	 31, 31, 30, 29, 29, 28, 27, 27,
2611da177e4SLinus Torvalds 	 26, 25, 25, 24, 24, 23, 22, 22,
2621da177e4SLinus Torvalds 	 21, 21, 20, 19, 19, 18, 18, 17,
2631da177e4SLinus Torvalds 	 17, 16, 16, 15, 15, 14, 14, 13,
2641da177e4SLinus Torvalds 	 13, 12, 12, 11, 11, 10, 10,  9,
2651da177e4SLinus Torvalds 	  9,  9,  8,  8,  7,  7,  6,  6,
2661da177e4SLinus Torvalds 	  6,  5,  5,  4,  4,  4,  3,  3,
2671da177e4SLinus Torvalds 	  2,  2,  2,  1,  1,  0,  0,  0
2681da177e4SLinus Torvalds };
2691da177e4SLinus Torvalds 
2701da177e4SLinus Torvalds /*
2711da177e4SLinus Torvalds  * Initializes all voices.
2721da177e4SLinus Torvalds  */
snd_opl4_synth_reset(struct snd_opl4 * opl4)273a42dd420STakashi Iwai void snd_opl4_synth_reset(struct snd_opl4 *opl4)
2741da177e4SLinus Torvalds {
2751da177e4SLinus Torvalds 	unsigned long flags;
2761da177e4SLinus Torvalds 	int i;
2771da177e4SLinus Torvalds 
2781da177e4SLinus Torvalds 	spin_lock_irqsave(&opl4->reg_lock, flags);
2791da177e4SLinus Torvalds 	for (i = 0; i < OPL4_MAX_VOICES; i++)
2801da177e4SLinus Torvalds 		snd_opl4_write(opl4, OPL4_REG_MISC + i, OPL4_DAMP_BIT);
2811da177e4SLinus Torvalds 	spin_unlock_irqrestore(&opl4->reg_lock, flags);
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds 	INIT_LIST_HEAD(&opl4->off_voices);
2841da177e4SLinus Torvalds 	INIT_LIST_HEAD(&opl4->on_voices);
2851da177e4SLinus Torvalds 	memset(opl4->voices, 0, sizeof(opl4->voices));
2861da177e4SLinus Torvalds 	for (i = 0; i < OPL4_MAX_VOICES; i++) {
2871da177e4SLinus Torvalds 		opl4->voices[i].number = i;
2881da177e4SLinus Torvalds 		list_add_tail(&opl4->voices[i].list, &opl4->off_voices);
2891da177e4SLinus Torvalds 	}
2901da177e4SLinus Torvalds 
2911da177e4SLinus Torvalds 	snd_midi_channel_set_clear(opl4->chset);
2921da177e4SLinus Torvalds }
2931da177e4SLinus Torvalds 
2941da177e4SLinus Torvalds /*
2951da177e4SLinus Torvalds  * Shuts down all voices.
2961da177e4SLinus Torvalds  */
snd_opl4_synth_shutdown(struct snd_opl4 * opl4)297a42dd420STakashi Iwai void snd_opl4_synth_shutdown(struct snd_opl4 *opl4)
2981da177e4SLinus Torvalds {
2991da177e4SLinus Torvalds 	unsigned long flags;
3001da177e4SLinus Torvalds 	int i;
3011da177e4SLinus Torvalds 
3021da177e4SLinus Torvalds 	spin_lock_irqsave(&opl4->reg_lock, flags);
3031da177e4SLinus Torvalds 	for (i = 0; i < OPL4_MAX_VOICES; i++)
3041da177e4SLinus Torvalds 		snd_opl4_write(opl4, OPL4_REG_MISC + i,
3051da177e4SLinus Torvalds 			       opl4->voices[i].reg_misc & ~OPL4_KEY_ON_BIT);
3061da177e4SLinus Torvalds 	spin_unlock_irqrestore(&opl4->reg_lock, flags);
3071da177e4SLinus Torvalds }
3081da177e4SLinus Torvalds 
3091da177e4SLinus Torvalds /*
3101da177e4SLinus Torvalds  * Executes the callback for all voices playing the specified note.
3111da177e4SLinus Torvalds  */
snd_opl4_do_for_note(struct snd_opl4 * opl4,int note,struct snd_midi_channel * chan,void (* func)(struct snd_opl4 * opl4,struct opl4_voice * voice))312a42dd420STakashi Iwai static void snd_opl4_do_for_note(struct snd_opl4 *opl4, int note, struct snd_midi_channel *chan,
313a42dd420STakashi Iwai 				 void (*func)(struct snd_opl4 *opl4, struct opl4_voice *voice))
3141da177e4SLinus Torvalds {
3151da177e4SLinus Torvalds 	int i;
3161da177e4SLinus Torvalds 	unsigned long flags;
317a42dd420STakashi Iwai 	struct opl4_voice *voice;
3181da177e4SLinus Torvalds 
3191da177e4SLinus Torvalds 	spin_lock_irqsave(&opl4->reg_lock, flags);
3201da177e4SLinus Torvalds 	for (i = 0; i < OPL4_MAX_VOICES; i++) {
3211da177e4SLinus Torvalds 		voice = &opl4->voices[i];
3221da177e4SLinus Torvalds 		if (voice->chan == chan && voice->note == note) {
3231da177e4SLinus Torvalds 			func(opl4, voice);
3241da177e4SLinus Torvalds 		}
3251da177e4SLinus Torvalds 	}
3261da177e4SLinus Torvalds 	spin_unlock_irqrestore(&opl4->reg_lock, flags);
3271da177e4SLinus Torvalds }
3281da177e4SLinus Torvalds 
3291da177e4SLinus Torvalds /*
3301da177e4SLinus Torvalds  * Executes the callback for all voices of to the specified channel.
3311da177e4SLinus Torvalds  */
snd_opl4_do_for_channel(struct snd_opl4 * opl4,struct snd_midi_channel * chan,void (* func)(struct snd_opl4 * opl4,struct opl4_voice * voice))332a42dd420STakashi Iwai static void snd_opl4_do_for_channel(struct snd_opl4 *opl4,
333a42dd420STakashi Iwai 				    struct snd_midi_channel *chan,
334a42dd420STakashi Iwai 				    void (*func)(struct snd_opl4 *opl4, struct opl4_voice *voice))
3351da177e4SLinus Torvalds {
3361da177e4SLinus Torvalds 	int i;
3371da177e4SLinus Torvalds 	unsigned long flags;
338a42dd420STakashi Iwai 	struct opl4_voice *voice;
3391da177e4SLinus Torvalds 
3401da177e4SLinus Torvalds 	spin_lock_irqsave(&opl4->reg_lock, flags);
3411da177e4SLinus Torvalds 	for (i = 0; i < OPL4_MAX_VOICES; i++) {
3421da177e4SLinus Torvalds 		voice = &opl4->voices[i];
3431da177e4SLinus Torvalds 		if (voice->chan == chan) {
3441da177e4SLinus Torvalds 			func(opl4, voice);
3451da177e4SLinus Torvalds 		}
3461da177e4SLinus Torvalds 	}
3471da177e4SLinus Torvalds 	spin_unlock_irqrestore(&opl4->reg_lock, flags);
3481da177e4SLinus Torvalds }
3491da177e4SLinus Torvalds 
3501da177e4SLinus Torvalds /*
3511da177e4SLinus Torvalds  * Executes the callback for all active voices.
3521da177e4SLinus Torvalds  */
snd_opl4_do_for_all(struct snd_opl4 * opl4,void (* func)(struct snd_opl4 * opl4,struct opl4_voice * voice))353a42dd420STakashi Iwai static void snd_opl4_do_for_all(struct snd_opl4 *opl4,
354a42dd420STakashi Iwai 				void (*func)(struct snd_opl4 *opl4, struct opl4_voice *voice))
3551da177e4SLinus Torvalds {
3561da177e4SLinus Torvalds 	int i;
3571da177e4SLinus Torvalds 	unsigned long flags;
358a42dd420STakashi Iwai 	struct opl4_voice *voice;
3591da177e4SLinus Torvalds 
3601da177e4SLinus Torvalds 	spin_lock_irqsave(&opl4->reg_lock, flags);
3611da177e4SLinus Torvalds 	for (i = 0; i < OPL4_MAX_VOICES; i++) {
3621da177e4SLinus Torvalds 		voice = &opl4->voices[i];
3631da177e4SLinus Torvalds 		if (voice->chan)
3641da177e4SLinus Torvalds 			func(opl4, voice);
3651da177e4SLinus Torvalds 	}
3661da177e4SLinus Torvalds 	spin_unlock_irqrestore(&opl4->reg_lock, flags);
3671da177e4SLinus Torvalds }
3681da177e4SLinus Torvalds 
snd_opl4_update_volume(struct snd_opl4 * opl4,struct opl4_voice * voice)369a42dd420STakashi Iwai static void snd_opl4_update_volume(struct snd_opl4 *opl4, struct opl4_voice *voice)
3701da177e4SLinus Torvalds {
3711da177e4SLinus Torvalds 	int att;
3721da177e4SLinus Torvalds 
3731da177e4SLinus Torvalds 	att = voice->sound->tone_attenuate;
3741da177e4SLinus Torvalds 	att += snd_opl4_volume_table[opl4->chset->gs_master_volume & 0x7f];
3751da177e4SLinus Torvalds 	att += snd_opl4_volume_table[voice->chan->gm_volume & 0x7f];
3761da177e4SLinus Torvalds 	att += snd_opl4_volume_table[voice->chan->gm_expression & 0x7f];
3771da177e4SLinus Torvalds 	att += snd_opl4_volume_table[voice->velocity];
3781da177e4SLinus Torvalds 	att = 0x7f - (0x7f - att) * (voice->sound->volume_factor) / 0xfe - volume_boost;
3791da177e4SLinus Torvalds 	if (att < 0)
3801da177e4SLinus Torvalds 		att = 0;
3811da177e4SLinus Torvalds 	else if (att > 0x7e)
3821da177e4SLinus Torvalds 		att = 0x7e;
3831da177e4SLinus Torvalds 	snd_opl4_write(opl4, OPL4_REG_LEVEL + voice->number,
3841da177e4SLinus Torvalds 		       (att << 1) | voice->level_direct);
3851da177e4SLinus Torvalds 	voice->level_direct = 0;
3861da177e4SLinus Torvalds }
3871da177e4SLinus Torvalds 
snd_opl4_update_pan(struct snd_opl4 * opl4,struct opl4_voice * voice)388a42dd420STakashi Iwai static void snd_opl4_update_pan(struct snd_opl4 *opl4, struct opl4_voice *voice)
3891da177e4SLinus Torvalds {
3901da177e4SLinus Torvalds 	int pan = voice->sound->panpot;
3911da177e4SLinus Torvalds 
3921da177e4SLinus Torvalds 	if (!voice->chan->drum_channel)
3931da177e4SLinus Torvalds 		pan += (voice->chan->control[MIDI_CTL_MSB_PAN] - 0x40) >> 3;
3941da177e4SLinus Torvalds 	if (pan < -7)
3951da177e4SLinus Torvalds 		pan = -7;
3961da177e4SLinus Torvalds 	else if (pan > 7)
3971da177e4SLinus Torvalds 		pan = 7;
3981da177e4SLinus Torvalds 	voice->reg_misc = (voice->reg_misc & ~OPL4_PAN_POT_MASK)
3991da177e4SLinus Torvalds 		| (pan & OPL4_PAN_POT_MASK);
4001da177e4SLinus Torvalds 	snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc);
4011da177e4SLinus Torvalds }
4021da177e4SLinus Torvalds 
snd_opl4_update_vibrato_depth(struct snd_opl4 * opl4,struct opl4_voice * voice)403a42dd420STakashi Iwai static void snd_opl4_update_vibrato_depth(struct snd_opl4 *opl4,
404a42dd420STakashi Iwai 					  struct opl4_voice *voice)
4051da177e4SLinus Torvalds {
4061da177e4SLinus Torvalds 	int depth;
4071da177e4SLinus Torvalds 
4081da177e4SLinus Torvalds 	if (voice->chan->drum_channel)
4091da177e4SLinus Torvalds 		return;
4101da177e4SLinus Torvalds 	depth = (7 - voice->sound->vibrato)
4111da177e4SLinus Torvalds 		* (voice->chan->control[MIDI_CTL_VIBRATO_DEPTH] & 0x7f);
4121da177e4SLinus Torvalds 	depth = (depth >> 7) + voice->sound->vibrato;
4131da177e4SLinus Torvalds 	voice->reg_lfo_vibrato &= ~OPL4_VIBRATO_DEPTH_MASK;
4141da177e4SLinus Torvalds 	voice->reg_lfo_vibrato |= depth & OPL4_VIBRATO_DEPTH_MASK;
4151da177e4SLinus Torvalds 	snd_opl4_write(opl4, OPL4_REG_LFO_VIBRATO + voice->number,
4161da177e4SLinus Torvalds 		       voice->reg_lfo_vibrato);
4171da177e4SLinus Torvalds }
4181da177e4SLinus Torvalds 
snd_opl4_update_pitch(struct snd_opl4 * opl4,struct opl4_voice * voice)419a42dd420STakashi Iwai static void snd_opl4_update_pitch(struct snd_opl4 *opl4,
420a42dd420STakashi Iwai 				  struct opl4_voice *voice)
4211da177e4SLinus Torvalds {
422a42dd420STakashi Iwai 	struct snd_midi_channel *chan = voice->chan;
4231da177e4SLinus Torvalds 	int note, pitch, octave;
4241da177e4SLinus Torvalds 
4251da177e4SLinus Torvalds 	note = chan->drum_channel ? 60 : voice->note;
4261da177e4SLinus Torvalds 	/*
4271da177e4SLinus Torvalds 	 * pitch is in 100/128 cents, so 0x80 is one semitone and
4281da177e4SLinus Torvalds 	 * 0x600 is one octave.
4291da177e4SLinus Torvalds 	 */
4301da177e4SLinus Torvalds 	pitch = ((note - 60) << 7) * voice->sound->key_scaling / 100 + (60 << 7);
4311da177e4SLinus Torvalds 	pitch += voice->sound->pitch_offset;
4321da177e4SLinus Torvalds 	if (!chan->drum_channel)
4331da177e4SLinus Torvalds 		pitch += chan->gm_rpn_coarse_tuning;
4341da177e4SLinus Torvalds 	pitch += chan->gm_rpn_fine_tuning >> 7;
4351da177e4SLinus Torvalds 	pitch += chan->midi_pitchbend * chan->gm_rpn_pitch_bend_range / 0x2000;
4361da177e4SLinus Torvalds 	if (pitch < 0)
4371da177e4SLinus Torvalds 		pitch = 0;
4381da177e4SLinus Torvalds 	else if (pitch >= 0x6000)
4391da177e4SLinus Torvalds 		pitch = 0x5fff;
4401da177e4SLinus Torvalds 	octave = pitch / 0x600 - 8;
4411da177e4SLinus Torvalds 	pitch = snd_opl4_pitch_map[pitch % 0x600];
4421da177e4SLinus Torvalds 
4431da177e4SLinus Torvalds 	snd_opl4_write(opl4, OPL4_REG_OCTAVE + voice->number,
4441da177e4SLinus Torvalds 		       (octave << 4) | ((pitch >> 7) & OPL4_F_NUMBER_HIGH_MASK));
4451da177e4SLinus Torvalds 	voice->reg_f_number = (voice->reg_f_number & OPL4_TONE_NUMBER_BIT8)
4461da177e4SLinus Torvalds 		| ((pitch << 1) & OPL4_F_NUMBER_LOW_MASK);
4471da177e4SLinus Torvalds 	snd_opl4_write(opl4, OPL4_REG_F_NUMBER + voice->number, voice->reg_f_number);
4481da177e4SLinus Torvalds }
4491da177e4SLinus Torvalds 
snd_opl4_update_tone_parameters(struct snd_opl4 * opl4,struct opl4_voice * voice)450a42dd420STakashi Iwai static void snd_opl4_update_tone_parameters(struct snd_opl4 *opl4,
451a42dd420STakashi Iwai 					    struct opl4_voice *voice)
4521da177e4SLinus Torvalds {
4531da177e4SLinus Torvalds 	snd_opl4_write(opl4, OPL4_REG_ATTACK_DECAY1 + voice->number,
4541da177e4SLinus Torvalds 		       voice->sound->reg_attack_decay1);
4551da177e4SLinus Torvalds 	snd_opl4_write(opl4, OPL4_REG_LEVEL_DECAY2 + voice->number,
4561da177e4SLinus Torvalds 		       voice->sound->reg_level_decay2);
4571da177e4SLinus Torvalds 	snd_opl4_write(opl4, OPL4_REG_RELEASE_CORRECTION + voice->number,
4581da177e4SLinus Torvalds 		       voice->sound->reg_release_correction);
4591da177e4SLinus Torvalds 	snd_opl4_write(opl4, OPL4_REG_TREMOLO + voice->number,
4601da177e4SLinus Torvalds 		       voice->sound->reg_tremolo);
4611da177e4SLinus Torvalds }
4621da177e4SLinus Torvalds 
4631da177e4SLinus Torvalds /* allocate one voice */
snd_opl4_get_voice(struct snd_opl4 * opl4)464a42dd420STakashi Iwai static struct opl4_voice *snd_opl4_get_voice(struct snd_opl4 *opl4)
4651da177e4SLinus Torvalds {
4661da177e4SLinus Torvalds 	/* first, try to get the oldest key-off voice */
4671da177e4SLinus Torvalds 	if (!list_empty(&opl4->off_voices))
468a42dd420STakashi Iwai 		return list_entry(opl4->off_voices.next, struct opl4_voice, list);
4691da177e4SLinus Torvalds 	/* then get the oldest key-on voice */
4705e246b85STakashi Iwai 	snd_BUG_ON(list_empty(&opl4->on_voices));
471a42dd420STakashi Iwai 	return list_entry(opl4->on_voices.next, struct opl4_voice, list);
4721da177e4SLinus Torvalds }
4731da177e4SLinus Torvalds 
snd_opl4_wait_for_wave_headers(struct snd_opl4 * opl4)474a42dd420STakashi Iwai static void snd_opl4_wait_for_wave_headers(struct snd_opl4 *opl4)
4751da177e4SLinus Torvalds {
4761da177e4SLinus Torvalds 	int timeout = 200;
4771da177e4SLinus Torvalds 
4781da177e4SLinus Torvalds 	while ((inb(opl4->fm_port) & OPL4_STATUS_LOAD) && --timeout > 0)
4791da177e4SLinus Torvalds 		udelay(10);
4801da177e4SLinus Torvalds }
4811da177e4SLinus Torvalds 
snd_opl4_note_on(void * private_data,int note,int vel,struct snd_midi_channel * chan)482a42dd420STakashi Iwai void snd_opl4_note_on(void *private_data, int note, int vel, struct snd_midi_channel *chan)
4831da177e4SLinus Torvalds {
484a42dd420STakashi Iwai 	struct snd_opl4 *opl4 = private_data;
485a42dd420STakashi Iwai 	const struct opl4_region_ptr *regions;
486a42dd420STakashi Iwai 	struct opl4_voice *voice[2];
487a42dd420STakashi Iwai 	const struct opl4_sound *sound[2];
4881da177e4SLinus Torvalds 	int voices = 0, i;
4891da177e4SLinus Torvalds 	unsigned long flags;
4901da177e4SLinus Torvalds 
4911da177e4SLinus Torvalds 	/* determine the number of voices and voice parameters */
4921da177e4SLinus Torvalds 	i = chan->drum_channel ? 0x80 : (chan->midi_program & 0x7f);
4931da177e4SLinus Torvalds 	regions = &snd_yrw801_regions[i];
4941da177e4SLinus Torvalds 	for (i = 0; i < regions->count; i++) {
4951da177e4SLinus Torvalds 		if (note >= regions->regions[i].key_min &&
4961da177e4SLinus Torvalds 		    note <= regions->regions[i].key_max) {
4971da177e4SLinus Torvalds 			sound[voices] = &regions->regions[i].sound;
4981da177e4SLinus Torvalds 			if (++voices >= 2)
4991da177e4SLinus Torvalds 				break;
5001da177e4SLinus Torvalds 		}
5011da177e4SLinus Torvalds 	}
5021da177e4SLinus Torvalds 
5031da177e4SLinus Torvalds 	/* allocate and initialize the needed voices */
5041da177e4SLinus Torvalds 	spin_lock_irqsave(&opl4->reg_lock, flags);
5051da177e4SLinus Torvalds 	for (i = 0; i < voices; i++) {
5061da177e4SLinus Torvalds 		voice[i] = snd_opl4_get_voice(opl4);
5073a4a7ef5SWei Yongjun 		list_move_tail(&voice[i]->list, &opl4->on_voices);
5081da177e4SLinus Torvalds 		voice[i]->chan = chan;
5091da177e4SLinus Torvalds 		voice[i]->note = note;
5101da177e4SLinus Torvalds 		voice[i]->velocity = vel & 0x7f;
5111da177e4SLinus Torvalds 		voice[i]->sound = sound[i];
5121da177e4SLinus Torvalds 	}
5131da177e4SLinus Torvalds 
5141da177e4SLinus Torvalds 	/* set tone number (triggers header loading) */
5151da177e4SLinus Torvalds 	for (i = 0; i < voices; i++) {
5161da177e4SLinus Torvalds 		voice[i]->reg_f_number =
5171da177e4SLinus Torvalds 			(sound[i]->tone >> 8) & OPL4_TONE_NUMBER_BIT8;
5181da177e4SLinus Torvalds 		snd_opl4_write(opl4, OPL4_REG_F_NUMBER + voice[i]->number,
5191da177e4SLinus Torvalds 			       voice[i]->reg_f_number);
5201da177e4SLinus Torvalds 		snd_opl4_write(opl4, OPL4_REG_TONE_NUMBER + voice[i]->number,
5211da177e4SLinus Torvalds 			       sound[i]->tone & 0xff);
5221da177e4SLinus Torvalds 	}
5231da177e4SLinus Torvalds 
5241da177e4SLinus Torvalds 	/* set parameters which can be set while loading */
5251da177e4SLinus Torvalds 	for (i = 0; i < voices; i++) {
5261da177e4SLinus Torvalds 		voice[i]->reg_misc = OPL4_LFO_RESET_BIT;
5271da177e4SLinus Torvalds 		snd_opl4_update_pan(opl4, voice[i]);
5281da177e4SLinus Torvalds 		snd_opl4_update_pitch(opl4, voice[i]);
5291da177e4SLinus Torvalds 		voice[i]->level_direct = OPL4_LEVEL_DIRECT_BIT;
5301da177e4SLinus Torvalds 		snd_opl4_update_volume(opl4, voice[i]);
5311da177e4SLinus Torvalds 	}
5321da177e4SLinus Torvalds 	spin_unlock_irqrestore(&opl4->reg_lock, flags);
5331da177e4SLinus Torvalds 
5341da177e4SLinus Torvalds 	/* wait for completion of loading */
5351da177e4SLinus Torvalds 	snd_opl4_wait_for_wave_headers(opl4);
5361da177e4SLinus Torvalds 
5371da177e4SLinus Torvalds 	/* set remaining parameters */
5381da177e4SLinus Torvalds 	spin_lock_irqsave(&opl4->reg_lock, flags);
5391da177e4SLinus Torvalds 	for (i = 0; i < voices; i++) {
5401da177e4SLinus Torvalds 		snd_opl4_update_tone_parameters(opl4, voice[i]);
5411da177e4SLinus Torvalds 		voice[i]->reg_lfo_vibrato = voice[i]->sound->reg_lfo_vibrato;
5421da177e4SLinus Torvalds 		snd_opl4_update_vibrato_depth(opl4, voice[i]);
5431da177e4SLinus Torvalds 	}
5441da177e4SLinus Torvalds 
5451da177e4SLinus Torvalds 	/* finally, switch on all voices */
5461da177e4SLinus Torvalds 	for (i = 0; i < voices; i++) {
5471da177e4SLinus Torvalds 		voice[i]->reg_misc =
5481da177e4SLinus Torvalds 			(voice[i]->reg_misc & 0x1f) | OPL4_KEY_ON_BIT;
5491da177e4SLinus Torvalds 		snd_opl4_write(opl4, OPL4_REG_MISC + voice[i]->number,
5501da177e4SLinus Torvalds 			       voice[i]->reg_misc);
5511da177e4SLinus Torvalds 	}
5521da177e4SLinus Torvalds 	spin_unlock_irqrestore(&opl4->reg_lock, flags);
5531da177e4SLinus Torvalds }
5541da177e4SLinus Torvalds 
snd_opl4_voice_off(struct snd_opl4 * opl4,struct opl4_voice * voice)555a42dd420STakashi Iwai static void snd_opl4_voice_off(struct snd_opl4 *opl4, struct opl4_voice *voice)
5561da177e4SLinus Torvalds {
5573a4a7ef5SWei Yongjun 	list_move_tail(&voice->list, &opl4->off_voices);
5581da177e4SLinus Torvalds 
5591da177e4SLinus Torvalds 	voice->reg_misc &= ~OPL4_KEY_ON_BIT;
5601da177e4SLinus Torvalds 	snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc);
5611da177e4SLinus Torvalds }
5621da177e4SLinus Torvalds 
snd_opl4_note_off(void * private_data,int note,int vel,struct snd_midi_channel * chan)563a42dd420STakashi Iwai void snd_opl4_note_off(void *private_data, int note, int vel, struct snd_midi_channel *chan)
5641da177e4SLinus Torvalds {
565a42dd420STakashi Iwai 	struct snd_opl4 *opl4 = private_data;
5661da177e4SLinus Torvalds 
5671da177e4SLinus Torvalds 	snd_opl4_do_for_note(opl4, note, chan, snd_opl4_voice_off);
5681da177e4SLinus Torvalds }
5691da177e4SLinus Torvalds 
snd_opl4_terminate_voice(struct snd_opl4 * opl4,struct opl4_voice * voice)570a42dd420STakashi Iwai static void snd_opl4_terminate_voice(struct snd_opl4 *opl4, struct opl4_voice *voice)
5711da177e4SLinus Torvalds {
5723a4a7ef5SWei Yongjun 	list_move_tail(&voice->list, &opl4->off_voices);
5731da177e4SLinus Torvalds 
5741da177e4SLinus Torvalds 	voice->reg_misc = (voice->reg_misc & ~OPL4_KEY_ON_BIT) | OPL4_DAMP_BIT;
5751da177e4SLinus Torvalds 	snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc);
5761da177e4SLinus Torvalds }
5771da177e4SLinus Torvalds 
snd_opl4_terminate_note(void * private_data,int note,struct snd_midi_channel * chan)578a42dd420STakashi Iwai void snd_opl4_terminate_note(void *private_data, int note, struct snd_midi_channel *chan)
5791da177e4SLinus Torvalds {
580a42dd420STakashi Iwai 	struct snd_opl4 *opl4 = private_data;
5811da177e4SLinus Torvalds 
5821da177e4SLinus Torvalds 	snd_opl4_do_for_note(opl4, note, chan, snd_opl4_terminate_voice);
5831da177e4SLinus Torvalds }
5841da177e4SLinus Torvalds 
snd_opl4_control(void * private_data,int type,struct snd_midi_channel * chan)585a42dd420STakashi Iwai void snd_opl4_control(void *private_data, int type, struct snd_midi_channel *chan)
5861da177e4SLinus Torvalds {
587a42dd420STakashi Iwai 	struct snd_opl4 *opl4 = private_data;
5881da177e4SLinus Torvalds 
5891da177e4SLinus Torvalds 	switch (type) {
5901da177e4SLinus Torvalds 	case MIDI_CTL_MSB_MODWHEEL:
5911da177e4SLinus Torvalds 		chan->control[MIDI_CTL_VIBRATO_DEPTH] = chan->control[MIDI_CTL_MSB_MODWHEEL];
5921da177e4SLinus Torvalds 		snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_vibrato_depth);
5931da177e4SLinus Torvalds 		break;
5941da177e4SLinus Torvalds 	case MIDI_CTL_MSB_MAIN_VOLUME:
5951da177e4SLinus Torvalds 		snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_volume);
5961da177e4SLinus Torvalds 		break;
5971da177e4SLinus Torvalds 	case MIDI_CTL_MSB_PAN:
5981da177e4SLinus Torvalds 		snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_pan);
5991da177e4SLinus Torvalds 		break;
6001da177e4SLinus Torvalds 	case MIDI_CTL_MSB_EXPRESSION:
6011da177e4SLinus Torvalds 		snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_volume);
6021da177e4SLinus Torvalds 		break;
6031da177e4SLinus Torvalds 	case MIDI_CTL_VIBRATO_RATE:
6041da177e4SLinus Torvalds 		/* not yet supported */
6051da177e4SLinus Torvalds 		break;
6061da177e4SLinus Torvalds 	case MIDI_CTL_VIBRATO_DEPTH:
6071da177e4SLinus Torvalds 		snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_vibrato_depth);
6081da177e4SLinus Torvalds 		break;
6091da177e4SLinus Torvalds 	case MIDI_CTL_VIBRATO_DELAY:
6101da177e4SLinus Torvalds 		/* not yet supported */
6111da177e4SLinus Torvalds 		break;
6121da177e4SLinus Torvalds 	case MIDI_CTL_E1_REVERB_DEPTH:
6131da177e4SLinus Torvalds 		/*
6141da177e4SLinus Torvalds 		 * Each OPL4 voice has a bit called "Pseudo-Reverb", but
6151da177e4SLinus Torvalds 		 * IMHO _not_ using it enhances the listening experience.
6161da177e4SLinus Torvalds 		 */
6171da177e4SLinus Torvalds 		break;
6181da177e4SLinus Torvalds 	case MIDI_CTL_PITCHBEND:
6191da177e4SLinus Torvalds 		snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_pitch);
6201da177e4SLinus Torvalds 		break;
6211da177e4SLinus Torvalds 	}
6221da177e4SLinus Torvalds }
6231da177e4SLinus Torvalds 
snd_opl4_sysex(void * private_data,unsigned char * buf,int len,int parsed,struct snd_midi_channel_set * chset)6241da177e4SLinus Torvalds void snd_opl4_sysex(void *private_data, unsigned char *buf, int len,
625a42dd420STakashi Iwai 		    int parsed, struct snd_midi_channel_set *chset)
6261da177e4SLinus Torvalds {
627a42dd420STakashi Iwai 	struct snd_opl4 *opl4 = private_data;
6281da177e4SLinus Torvalds 
6291da177e4SLinus Torvalds 	if (parsed == SNDRV_MIDI_SYSEX_GS_MASTER_VOLUME)
6301da177e4SLinus Torvalds 		snd_opl4_do_for_all(opl4, snd_opl4_update_volume);
6311da177e4SLinus Torvalds }
632