/*
* OPL4 MIDI synthesizer functions
*
* Copyright ( c ) 2003 by Clemens Ladisch < clemens @ ladisch . de >
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1 . Redistributions of source code must retain the above copyright
* notice , this list of conditions , and the following disclaimer ,
* without modification .
* 2 . The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* Alternatively , this software may be distributed and / or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation ; either version 2 of the License , or ( at your option ) any later
* version .
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ` ` AS IS ' ' AND
* ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT
* LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
*/
#include "opl4_local.h"
#include <linux/delay.h>
#include <linux/io.h>
#include <sound/asoundef.h>
/* GM2 controllers */
#ifndef MIDI_CTL_RELEASE_TIME
#define MIDI_CTL_RELEASE_TIME 0 x48
#define MIDI_CTL_ATTACK_TIME 0 x49
#define MIDI_CTL_DECAY_TIME 0 x4b
#define MIDI_CTL_VIBRATO_RATE 0 x4c
#define MIDI_CTL_VIBRATO_DEPTH 0 x4d
#define MIDI_CTL_VIBRATO_DELAY 0 x4e
#endif
/*
* This table maps 100 / 128 cents to F_NUMBER .
*/
static const s16 snd_opl4_pitch_map[0 x600] = {
0 x000,0 x000,0 x001,0 x001,0 x002,0 x002,0 x003,0 x003,
0 x004,0 x004,0 x005,0 x005,0 x006,0 x006,0 x006,0 x007,
0 x007,0 x008,0 x008,0 x009,0 x009,0 x00a,0 x00a,0 x00b,
0 x00b,0 x00c,0 x00c,0 x00d,0 x00d,0 x00d,0 x00e,0 x00e,
0 x00f,0 x00f,0 x010,0 x010,0 x011,0 x011,0 x012,0 x012,
0 x013,0 x013,0 x014,0 x014,0 x015,0 x015,0 x015,0 x016,
0 x016,0 x017,0 x017,0 x018,0 x018,0 x019,0 x019,0 x01a,
0 x01a,0 x01b,0 x01b,0 x01c,0 x01c,0 x01d,0 x01d,0 x01e,
0 x01e,0 x01e,0 x01f,0 x01f,0 x020,0 x020,0 x021,0 x021,
0 x022,0 x022,0 x023,0 x023,0 x024,0 x024,0 x025,0 x025,
0 x026,0 x026,0 x027,0 x027,0 x028,0 x028,0 x029,0 x029,
0 x029,0 x02a,0 x02a,0 x02b,0 x02b,0 x02c,0 x02c,0 x02d,
0 x02d,0 x02e,0 x02e,0 x02f,0 x02f,0 x030,0 x030,0 x031,
0 x031,0 x032,0 x032,0 x033,0 x033,0 x034,0 x034,0 x035,
0 x035,0 x036,0 x036,0 x037,0 x037,0 x038,0 x038,0 x038,
0 x039,0 x039,0 x03a,0 x03a,0 x03b,0 x03b,0 x03c,0 x03c,
0 x03d,0 x03d,0 x03e,0 x03e,0 x03f,0 x03f,0 x040,0 x040,
0 x041,0 x041,0 x042,0 x042,0 x043,0 x043,0 x044,0 x044,
0 x045,0 x045,0 x046,0 x046,0 x047,0 x047,0 x048,0 x048,
0 x049,0 x049,0 x04a,0 x04a,0 x04b,0 x04b,0 x04c,0 x04c,
0 x04d,0 x04d,0 x04e,0 x04e,0 x04f,0 x04f,0 x050,0 x050,
0 x051,0 x051,0 x052,0 x052,0 x053,0 x053,0 x054,0 x054,
0 x055,0 x055,0 x056,0 x056,0 x057,0 x057,0 x058,0 x058,
0 x059,0 x059,0 x05a,0 x05a,0 x05b,0 x05b,0 x05c,0 x05c,
0 x05d,0 x05d,0 x05e,0 x05e,0 x05f,0 x05f,0 x060,0 x060,
0 x061,0 x061,0 x062,0 x062,0 x063,0 x063,0 x064,0 x064,
0 x065,0 x065,0 x066,0 x066,0 x067,0 x067,0 x068,0 x068,
0 x069,0 x069,0 x06a,0 x06a,0 x06b,0 x06b,0 x06c,0 x06c,
0 x06d,0 x06d,0 x06e,0 x06e,0 x06f,0 x06f,0 x070,0 x071,
0 x071,0 x072,0 x072,0 x073,0 x073,0 x074,0 x074,0 x075,
0 x075,0 x076,0 x076,0 x077,0 x077,0 x078,0 x078,0 x079,
0 x079,0 x07a,0 x07a,0 x07b,0 x07b,0 x07c,0 x07c,0 x07d,
0 x07d,0 x07e,0 x07e,0 x07f,0 x07f,0 x080,0 x081,0 x081,
0 x082,0 x082,0 x083,0 x083,0 x084,0 x084,0 x085,0 x085,
0 x086,0 x086,0 x087,0 x087,0 x088,0 x088,0 x089,0 x089,
0 x08a,0 x08a,0 x08b,0 x08b,0 x08c,0 x08d,0 x08d,0 x08e,
0 x08e,0 x08f,0 x08f,0 x090,0 x090,0 x091,0 x091,0 x092,
0 x092,0 x093,0 x093,0 x094,0 x094,0 x095,0 x096,0 x096,
0 x097,0 x097,0 x098,0 x098,0 x099,0 x099,0 x09a,0 x09a,
0 x09b,0 x09b,0 x09c,0 x09c,0 x09d,0 x09d,0 x09e,0 x09f,
0 x09f,0 x0a0,0 x0a0,0 x0a1,0 x0a1,0 x0a2,0 x0a2,0 x0a3,
0 x0a3,0 x0a4,0 x0a4,0 x0a5,0 x0a6,0 x0a6,0 x0a7,0 x0a7,
0 x0a8,0 x0a8,0 x0a9,0 x0a9,0 x0aa,0 x0aa,0 x0ab,0 x0ab,
0 x0ac,0 x0ad,0 x0ad,0 x0ae,0 x0ae,0 x0af,0 x0af,0 x0b0,
0 x0b0,0 x0b1,0 x0b1,0 x0b2,0 x0b2,0 x0b3,0 x0b4,0 x0b4,
0 x0b5,0 x0b5,0 x0b6,0 x0b6,0 x0b7,0 x0b7,0 x0b8,0 x0b8,
0 x0b9,0 x0ba,0 x0ba,0 x0bb,0 x0bb,0 x0bc,0 x0bc,0 x0bd,
0 x0bd,0 x0be,0 x0be,0 x0bf,0 x0c0,0 x0c0,0 x0c1,0 x0c1,
0 x0c2,0 x0c2,0 x0c3,0 x0c3,0 x0c4,0 x0c4,0 x0c5,0 x0c6,
0 x0c6,0 x0c7,0 x0c7,0 x0c8,0 x0c8,0 x0c9,0 x0c9,0 x0ca,
0 x0cb,0 x0cb,0 x0cc,0 x0cc,0 x0cd,0 x0cd,0 x0ce,0 x0ce,
0 x0cf,0 x0d0,0 x0d0,0 x0d1,0 x0d1,0 x0d2,0 x0d2,0 x0d3,
0 x0d3,0 x0d4,0 x0d5,0 x0d5,0 x0d6,0 x0d6,0 x0d7,0 x0d7,
0 x0d8,0 x0d8,0 x0d9,0 x0da,0 x0da,0 x0db,0 x0db,0 x0dc,
0 x0dc,0 x0dd,0 x0de,0 x0de,0 x0df,0 x0df,0 x0e0,0 x0e0,
0 x0e1,0 x0e1,0 x0e2,0 x0e3,0 x0e3,0 x0e4,0 x0e4,0 x0e5,
0 x0e5,0 x0e6,0 x0e7,0 x0e7,0 x0e8,0 x0e8,0 x0e9,0 x0e9,
0 x0ea,0 x0eb,0 x0eb,0 x0ec,0 x0ec,0 x0ed,0 x0ed,0 x0ee,
0 x0ef,0 x0ef,0 x0f0,0 x0f0,0 x0f1,0 x0f1,0 x0f2,0 x0f3,
0 x0f3,0 x0f4,0 x0f4,0 x0f5,0 x0f5,0 x0f6,0 x0f7,0 x0f7,
0 x0f8,0 x0f8,0 x0f9,0 x0f9,0 x0fa,0 x0fb,0 x0fb,0 x0fc,
0 x0fc,0 x0fd,0 x0fd,0 x0fe,0 x0ff,0 x0ff,0 x100,0 x100,
0 x101,0 x101,0 x102,0 x103,0 x103,0 x104,0 x104,0 x105,
0 x106,0 x106,0 x107,0 x107,0 x108,0 x108,0 x109,0 x10a,
0 x10a,0 x10b,0 x10b,0 x10c,0 x10c,0 x10d,0 x10e,0 x10e,
0 x10f,0 x10f,0 x110,0 x111,0 x111,0 x112,0 x112,0 x113,
0 x114,0 x114,0 x115,0 x115,0 x116,0 x116,0 x117,0 x118,
0 x118,0 x119,0 x119,0 x11a,0 x11b,0 x11b,0 x11c,0 x11c,
0 x11d,0 x11e,0 x11e,0 x11f,0 x11f,0 x120,0 x120,0 x121,
0 x122,0 x122,0 x123,0 x123,0 x124,0 x125,0 x125,0 x126,
0 x126,0 x127,0 x128,0 x128,0 x129,0 x129,0 x12a,0 x12b,
0 x12b,0 x12c,0 x12c,0 x12d,0 x12e,0 x12e,0 x12f,0 x12f,
0 x130,0 x131,0 x131,0 x132,0 x132,0 x133,0 x134,0 x134,
0 x135,0 x135,0 x136,0 x137,0 x137,0 x138,0 x138,0 x139,
0 x13a,0 x13a,0 x13b,0 x13b,0 x13c,0 x13d,0 x13d,0 x13e,
0 x13e,0 x13f,0 x140,0 x140,0 x141,0 x141,0 x142,0 x143,
0 x143,0 x144,0 x144,0 x145,0 x146,0 x146,0 x147,0 x148,
0 x148,0 x149,0 x149,0 x14a,0 x14b,0 x14b,0 x14c,0 x14c,
0 x14d,0 x14e,0 x14e,0 x14f,0 x14f,0 x150,0 x151,0 x151,
0 x152,0 x153,0 x153,0 x154,0 x154,0 x155,0 x156,0 x156,
0 x157,0 x157,0 x158,0 x159,0 x159,0 x15a,0 x15b,0 x15b,
0 x15c,0 x15c,0 x15d,0 x15e,0 x15e,0 x15f,0 x160,0 x160,
0 x161,0 x161,0 x162,0 x163,0 x163,0 x164,0 x165,0 x165,
0 x166,0 x166,0 x167,0 x168,0 x168,0 x169,0 x16a,0 x16a,
0 x16b,0 x16b,0 x16c,0 x16d,0 x16d,0 x16e,0 x16f,0 x16f,
0 x170,0 x170,0 x171,0 x172,0 x172,0 x173,0 x174,0 x174,
0 x175,0 x175,0 x176,0 x177,0 x177,0 x178,0 x179,0 x179,
0 x17a,0 x17a,0 x17b,0 x17c,0 x17c,0 x17d,0 x17e,0 x17e,
0 x17f,0 x180,0 x180,0 x181,0 x181,0 x182,0 x183,0 x183,
0 x184,0 x185,0 x185,0 x186,0 x187,0 x187,0 x188,0 x188,
0 x189,0 x18a,0 x18a,0 x18b,0 x18c,0 x18c,0 x18d,0 x18e,
0 x18e,0 x18f,0 x190,0 x190,0 x191,0 x191,0 x192,0 x193,
0 x193,0 x194,0 x195,0 x195,0 x196,0 x197,0 x197,0 x198,
0 x199,0 x199,0 x19a,0 x19a,0 x19b,0 x19c,0 x19c,0 x19d,
0 x19e,0 x19e,0 x19f,0 x1a0,0 x1a0,0 x1a1,0 x1a2,0 x1a2,
0 x1a3,0 x1a4,0 x1a4,0 x1a5,0 x1a6,0 x1a6,0 x1a7,0 x1a8,
0 x1a8,0 x1a9,0 x1a9,0 x1aa,0 x1ab,0 x1ab,0 x1ac,0 x1ad,
0 x1ad,0 x1ae,0 x1af,0 x1af,0 x1b0,0 x1b1,0 x1b1,0 x1b2,
0 x1b3,0 x1b3,0 x1b4,0 x1b5,0 x1b5,0 x1b6,0 x1b7,0 x1b7,
0 x1b8,0 x1b9,0 x1b9,0 x1ba,0 x1bb,0 x1bb,0 x1bc,0 x1bd,
0 x1bd,0 x1be,0 x1bf,0 x1bf,0 x1c0,0 x1c1,0 x1c1,0 x1c2,
0 x1c3,0 x1c3,0 x1c4,0 x1c5,0 x1c5,0 x1c6,0 x1c7,0 x1c7,
0 x1c8,0 x1c9,0 x1c9,0 x1ca,0 x1cb,0 x1cb,0 x1cc,0 x1cd,
0 x1cd,0 x1ce,0 x1cf,0 x1cf,0 x1d0,0 x1d1,0 x1d1,0 x1d2,
0 x1d3,0 x1d3,0 x1d4,0 x1d5,0 x1d5,0 x1d6,0 x1d7,0 x1d7,
0 x1d8,0 x1d9,0 x1d9,0 x1da,0 x1db,0 x1db,0 x1dc,0 x1dd,
0 x1dd,0 x1de,0 x1df,0 x1df,0 x1e0,0 x1e1,0 x1e1,0 x1e2,
0 x1e3,0 x1e4,0 x1e4,0 x1e5,0 x1e6,0 x1e6,0 x1e7,0 x1e8,
0 x1e8,0 x1e9,0 x1ea,0 x1ea,0 x1eb,0 x1ec,0 x1ec,0 x1ed,
0 x1ee,0 x1ee,0 x1ef,0 x1f0,0 x1f0,0 x1f1,0 x1f2,0 x1f3,
0 x1f3,0 x1f4,0 x1f5,0 x1f5,0 x1f6,0 x1f7,0 x1f7,0 x1f8,
0 x1f9,0 x1f9,0 x1fa,0 x1fb,0 x1fb,0 x1fc,0 x1fd,0 x1fe,
0 x1fe,0 x1ff,0 x200,0 x200,0 x201,0 x202,0 x202,0 x203,
0 x204,0 x205,0 x205,0 x206,0 x207,0 x207,0 x208,0 x209,
0 x209,0 x20a,0 x20b,0 x20b,0 x20c,0 x20d,0 x20e,0 x20e,
0 x20f,0 x210,0 x210,0 x211,0 x212,0 x212,0 x213,0 x214,
0 x215,0 x215,0 x216,0 x217,0 x217,0 x218,0 x219,0 x21a,
0 x21a,0 x21b,0 x21c,0 x21c,0 x21d,0 x21e,0 x21e,0 x21f,
0 x220,0 x221,0 x221,0 x222,0 x223,0 x223,0 x224,0 x225,
0 x226,0 x226,0 x227,0 x228,0 x228,0 x229,0 x22a,0 x22b,
0 x22b,0 x22c,0 x22d,0 x22d,0 x22e,0 x22f,0 x230,0 x230,
0 x231,0 x232,0 x232,0 x233,0 x234,0 x235,0 x235,0 x236,
0 x237,0 x237,0 x238,0 x239,0 x23a,0 x23a,0 x23b,0 x23c,
0 x23c,0 x23d,0 x23e,0 x23f,0 x23f,0 x240,0 x241,0 x241,
0 x242,0 x243,0 x244,0 x244,0 x245,0 x246,0 x247,0 x247,
0 x248,0 x249,0 x249,0 x24a,0 x24b,0 x24c,0 x24c,0 x24d,
0 x24e,0 x24f,0 x24f,0 x250,0 x251,0 x251,0 x252,0 x253,
0 x254,0 x254,0 x255,0 x256,0 x257,0 x257,0 x258,0 x259,
0 x259,0 x25a,0 x25b,0 x25c,0 x25c,0 x25d,0 x25e,0 x25f,
0 x25f,0 x260,0 x261,0 x262,0 x262,0 x263,0 x264,0 x265,
0 x265,0 x266,0 x267,0 x267,0 x268,0 x269,0 x26a,0 x26a,
0 x26b,0 x26c,0 x26d,0 x26d,0 x26e,0 x26f,0 x270,0 x270,
0 x271,0 x272,0 x273,0 x273,0 x274,0 x275,0 x276,0 x276,
0 x277,0 x278,0 x279,0 x279,0 x27a,0 x27b,0 x27c,0 x27c,
0 x27d,0 x27e,0 x27f,0 x27f,0 x280,0 x281,0 x282,0 x282,
0 x283,0 x284,0 x285,0 x285,0 x286,0 x287,0 x288,0 x288,
0 x289,0 x28a,0 x28b,0 x28b,0 x28c,0 x28d,0 x28e,0 x28e,
0 x28f,0 x290,0 x291,0 x291,0 x292,0 x293,0 x294,0 x294,
0 x295,0 x296,0 x297,0 x298,0 x298,0 x299,0 x29a,0 x29b,
0 x29b,0 x29c,0 x29d,0 x29e,0 x29e,0 x29f,0 x2a0,0 x2a1,
0 x2a1,0 x2a2,0 x2a3,0 x2a4,0 x2a5,0 x2a5,0 x2a6,0 x2a7,
0 x2a8,0 x2a8,0 x2a9,0 x2aa,0 x2ab,0 x2ab,0 x2ac,0 x2ad,
0 x2ae,0 x2af,0 x2af,0 x2b0,0 x2b1,0 x2b2,0 x2b2,0 x2b3,
0 x2b4,0 x2b5,0 x2b5,0 x2b6,0 x2b7,0 x2b8,0 x2b9,0 x2b9,
0 x2ba,0 x2bb,0 x2bc,0 x2bc,0 x2bd,0 x2be,0 x2bf,0 x2c0,
0 x2c0,0 x2c1,0 x2c2,0 x2c3,0 x2c4,0 x2c4,0 x2c5,0 x2c6,
0 x2c7,0 x2c7,0 x2c8,0 x2c9,0 x2ca,0 x2cb,0 x2cb,0 x2cc,
0 x2cd,0 x2ce,0 x2ce,0 x2cf,0 x2d0,0 x2d1,0 x2d2,0 x2d2,
0 x2d3,0 x2d4,0 x2d5,0 x2d6,0 x2d6,0 x2d7,0 x2d8,0 x2d9,
0 x2da,0 x2da,0 x2db,0 x2dc,0 x2dd,0 x2dd,0 x2de,0 x2df,
0 x2e0,0 x2e1,0 x2e1,0 x2e2,0 x2e3,0 x2e4,0 x2e5,0 x2e5,
0 x2e6,0 x2e7,0 x2e8,0 x2e9,0 x2e9,0 x2ea,0 x2eb,0 x2ec,
0 x2ed,0 x2ed,0 x2ee,0 x2ef,0 x2f0,0 x2f1,0 x2f1,0 x2f2,
0 x2f3,0 x2f4,0 x2f5,0 x2f5,0 x2f6,0 x2f7,0 x2f8,0 x2f9,
0 x2f9,0 x2fa,0 x2fb,0 x2fc,0 x2fd,0 x2fd,0 x2fe,0 x2ff,
0 x300,0 x301,0 x302,0 x302,0 x303,0 x304,0 x305,0 x306,
0 x306,0 x307,0 x308,0 x309,0 x30a,0 x30a,0 x30b,0 x30c,
0 x30d,0 x30e,0 x30f,0 x30f,0 x310,0 x311,0 x312,0 x313,
0 x313,0 x314,0 x315,0 x316,0 x317,0 x318,0 x318,0 x319,
0 x31a,0 x31b,0 x31c,0 x31c,0 x31d,0 x31e,0 x31f,0 x320,
0 x321,0 x321,0 x322,0 x323,0 x324,0 x325,0 x326,0 x326,
0 x327,0 x328,0 x329,0 x32a,0 x32a,0 x32b,0 x32c,0 x32d,
0 x32e,0 x32f,0 x32f,0 x330,0 x331,0 x332,0 x333,0 x334,
0 x334,0 x335,0 x336,0 x337,0 x338,0 x339,0 x339,0 x33a,
0 x33b,0 x33c,0 x33d,0 x33e,0 x33e,0 x33f,0 x340,0 x341,
0 x342,0 x343,0 x343,0 x344,0 x345,0 x346,0 x347,0 x348,
0 x349,0 x349,0 x34a,0 x34b,0 x34c,0 x34d,0 x34e,0 x34e,
0 x34f,0 x350,0 x351,0 x352,0 x353,0 x353,0 x354,0 x355,
0 x356,0 x357,0 x358,0 x359,0 x359,0 x35a,0 x35b,0 x35c,
0 x35d,0 x35e,0 x35f,0 x35f,0 x360,0 x361,0 x362,0 x363,
0 x364,0 x364,0 x365,0 x366,0 x367,0 x368,0 x369,0 x36a,
0 x36a,0 x36b,0 x36c,0 x36d,0 x36e,0 x36f,0 x370,0 x370,
0 x371,0 x372,0 x373,0 x374,0 x375,0 x376,0 x377,0 x377,
0 x378,0 x379,0 x37a,0 x37b,0 x37c,0 x37d,0 x37d,0 x37e,
0 x37f,0 x380,0 x381,0 x382,0 x383,0 x383,0 x384,0 x385,
0 x386,0 x387,0 x388,0 x389,0 x38a,0 x38a,0 x38b,0 x38c,
0 x38d,0 x38e,0 x38f,0 x390,0 x391,0 x391,0 x392,0 x393,
0 x394,0 x395,0 x396,0 x397,0 x398,0 x398,0 x399,0 x39a,
0 x39b,0 x39c,0 x39d,0 x39e,0 x39f,0 x39f,0 x3a0,0 x3a1,
0 x3a2,0 x3a3,0 x3a4,0 x3a5,0 x3a6,0 x3a7,0 x3a7,0 x3a8,
0 x3a9,0 x3aa,0 x3ab,0 x3ac,0 x3ad,0 x3ae,0 x3ae,0 x3af,
0 x3b0,0 x3b1,0 x3b2,0 x3b3,0 x3b4,0 x3b5,0 x3b6,0 x3b6,
0 x3b7,0 x3b8,0 x3b9,0 x3ba,0 x3bb,0 x3bc,0 x3bd,0 x3be,
0 x3bf,0 x3bf,0 x3c0,0 x3c1,0 x3c2,0 x3c3,0 x3c4,0 x3c5,
0 x3c6,0 x3c7,0 x3c7,0 x3c8,0 x3c9,0 x3ca,0 x3cb,0 x3cc,
0 x3cd,0 x3ce,0 x3cf,0 x3d0,0 x3d1,0 x3d1,0 x3d2,0 x3d3,
0 x3d4,0 x3d5,0 x3d6,0 x3d7,0 x3d8,0 x3d9,0 x3da,0 x3da,
0 x3db,0 x3dc,0 x3dd,0 x3de,0 x3df,0 x3e0,0 x3e1,0 x3e2,
0 x3e3,0 x3e4,0 x3e4,0 x3e5,0 x3e6,0 x3e7,0 x3e8,0 x3e9,
0 x3ea,0 x3eb,0 x3ec,0 x3ed,0 x3ee,0 x3ef,0 x3ef,0 x3f0,
0 x3f1,0 x3f2,0 x3f3,0 x3f4,0 x3f5,0 x3f6,0 x3f7,0 x3f8,
0 x3f9,0 x3fa,0 x3fa,0 x3fb,0 x3fc,0 x3fd,0 x3fe,0 x3ff
};
/*
* Attenuation according to GM recommendations , in - 0 . 375 dB units .
* table [ v ] = 40 * log ( v / 127 ) / - 0 . 375
*/
static const unsigned char snd_opl4_volume_table[128 ] = {
255 ,224 ,192 ,173 ,160 ,150 ,141 ,134 ,
128 ,122 ,117 ,113 ,109 ,105 ,102 , 99 ,
96 , 93 , 90 , 88 , 85 , 83 , 81 , 79 ,
77 , 75 , 73 , 71 , 70 , 68 , 67 , 65 ,
64 , 62 , 61 , 59 , 58 , 57 , 56 , 54 ,
53 , 52 , 51 , 50 , 49 , 48 , 47 , 46 ,
45 , 44 , 43 , 42 , 41 , 40 , 39 , 39 ,
38 , 37 , 36 , 35 , 34 , 34 , 33 , 32 ,
31 , 31 , 30 , 29 , 29 , 28 , 27 , 27 ,
26 , 25 , 25 , 24 , 24 , 23 , 22 , 22 ,
21 , 21 , 20 , 19 , 19 , 18 , 18 , 17 ,
17 , 16 , 16 , 15 , 15 , 14 , 14 , 13 ,
13 , 12 , 12 , 11 , 11 , 10 , 10 , 9 ,
9 , 9 , 8 , 8 , 7 , 7 , 6 , 6 ,
6 , 5 , 5 , 4 , 4 , 4 , 3 , 3 ,
2 , 2 , 2 , 1 , 1 , 0 , 0 , 0
};
/*
* Initializes all voices .
*/
void snd_opl4_synth_reset(struct snd_opl4 *opl4)
{
unsigned long flags;
int i;
spin_lock_irqsave(&opl4->reg_lock, flags);
for (i = 0 ; i < OPL4_MAX_VOICES; i++)
snd_opl4_write(opl4, OPL4_REG_MISC + i, OPL4_DAMP_BIT);
spin_unlock_irqrestore(&opl4->reg_lock, flags);
INIT_LIST_HEAD(&opl4->off_voices);
INIT_LIST_HEAD(&opl4->on_voices);
memset(opl4->voices, 0 , sizeof (opl4->voices));
for (i = 0 ; i < OPL4_MAX_VOICES; i++) {
opl4->voices[i].number = i;
list_add_tail(&opl4->voices[i].list, &opl4->off_voices);
}
snd_midi_channel_set_clear(opl4->chset);
}
/*
* Shuts down all voices .
*/
void snd_opl4_synth_shutdown(struct snd_opl4 *opl4)
{
unsigned long flags;
int i;
spin_lock_irqsave(&opl4->reg_lock, flags);
for (i = 0 ; i < OPL4_MAX_VOICES; i++)
snd_opl4_write(opl4, OPL4_REG_MISC + i,
opl4->voices[i].reg_misc & ~OPL4_KEY_ON_BIT);
spin_unlock_irqrestore(&opl4->reg_lock, flags);
}
/*
* Executes the callback for all voices playing the specified note .
*/
static void 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))
{
int i;
unsigned long flags;
struct opl4_voice *voice;
spin_lock_irqsave(&opl4->reg_lock, flags);
for (i = 0 ; i < OPL4_MAX_VOICES; i++) {
voice = &opl4->voices[i];
if (voice->chan == chan && voice->note == note) {
func(opl4, voice);
}
}
spin_unlock_irqrestore(&opl4->reg_lock, flags);
}
/*
* Executes the callback for all voices of to the specified channel .
*/
static void snd_opl4_do_for_channel(struct snd_opl4 *opl4,
struct snd_midi_channel *chan,
void (*func)(struct snd_opl4 *opl4, struct opl4_voice *voice))
{
int i;
unsigned long flags;
struct opl4_voice *voice;
spin_lock_irqsave(&opl4->reg_lock, flags);
for (i = 0 ; i < OPL4_MAX_VOICES; i++) {
voice = &opl4->voices[i];
if (voice->chan == chan) {
func(opl4, voice);
}
}
spin_unlock_irqrestore(&opl4->reg_lock, flags);
}
/*
* Executes the callback for all active voices .
*/
static void snd_opl4_do_for_all(struct snd_opl4 *opl4,
void (*func)(struct snd_opl4 *opl4, struct opl4_voice *voice))
{
int i;
unsigned long flags;
struct opl4_voice *voice;
spin_lock_irqsave(&opl4->reg_lock, flags);
for (i = 0 ; i < OPL4_MAX_VOICES; i++) {
voice = &opl4->voices[i];
if (voice->chan)
func(opl4, voice);
}
spin_unlock_irqrestore(&opl4->reg_lock, flags);
}
static void snd_opl4_update_volume(struct snd_opl4 *opl4, struct opl4_voice *voice)
{
int att;
att = voice->sound->tone_attenuate;
att += snd_opl4_volume_table[opl4->chset->gs_master_volume & 0 x7f];
att += snd_opl4_volume_table[voice->chan->gm_volume & 0 x7f];
att += snd_opl4_volume_table[voice->chan->gm_expression & 0 x7f];
att += snd_opl4_volume_table[voice->velocity];
att = 0 x7f - (0 x7f - att) * (voice->sound->volume_factor) / 0 xfe - volume_boost;
if (att < 0 )
att = 0 ;
else if (att > 0 x7e)
att = 0 x7e;
snd_opl4_write(opl4, OPL4_REG_LEVEL + voice->number,
(att << 1 ) | voice->level_direct);
voice->level_direct = 0 ;
}
static void snd_opl4_update_pan(struct snd_opl4 *opl4, struct opl4_voice *voice)
{
int pan = voice->sound->panpot;
if (!voice->chan->drum_channel)
pan += (voice->chan->control[MIDI_CTL_MSB_PAN] - 0 x40) >> 3 ;
if (pan < -7 )
pan = -7 ;
else if (pan > 7 )
pan = 7 ;
voice->reg_misc = (voice->reg_misc & ~OPL4_PAN_POT_MASK)
| (pan & OPL4_PAN_POT_MASK);
snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc);
}
static void snd_opl4_update_vibrato_depth(struct snd_opl4 *opl4,
struct opl4_voice *voice)
{
int depth;
if (voice->chan->drum_channel)
return ;
depth = (7 - voice->sound->vibrato)
* (voice->chan->control[MIDI_CTL_VIBRATO_DEPTH] & 0 x7f);
depth = (depth >> 7 ) + voice->sound->vibrato;
voice->reg_lfo_vibrato &= ~OPL4_VIBRATO_DEPTH_MASK;
voice->reg_lfo_vibrato |= depth & OPL4_VIBRATO_DEPTH_MASK;
snd_opl4_write(opl4, OPL4_REG_LFO_VIBRATO + voice->number,
voice->reg_lfo_vibrato);
}
static void snd_opl4_update_pitch(struct snd_opl4 *opl4,
struct opl4_voice *voice)
{
struct snd_midi_channel *chan = voice->chan;
int note, pitch, octave;
note = chan->drum_channel ? 60 : voice->note;
/*
* pitch is in 100 / 128 cents , so 0 x80 is one semitone and
* 0 x600 is one octave .
*/
pitch = ((note - 60 ) << 7 ) * voice->sound->key_scaling / 100 + (60 << 7 );
pitch += voice->sound->pitch_offset;
if (!chan->drum_channel)
pitch += chan->gm_rpn_coarse_tuning;
pitch += chan->gm_rpn_fine_tuning >> 7 ;
pitch += chan->midi_pitchbend * chan->gm_rpn_pitch_bend_range / 0 x2000;
if (pitch < 0 )
pitch = 0 ;
else if (pitch >= 0 x6000)
pitch = 0 x5fff;
octave = pitch / 0 x600 - 8 ;
pitch = snd_opl4_pitch_map[pitch % 0 x600];
snd_opl4_write(opl4, OPL4_REG_OCTAVE + voice->number,
(octave << 4 ) | ((pitch >> 7 ) & OPL4_F_NUMBER_HIGH_MASK));
voice->reg_f_number = (voice->reg_f_number & OPL4_TONE_NUMBER_BIT8)
| ((pitch << 1 ) & OPL4_F_NUMBER_LOW_MASK);
snd_opl4_write(opl4, OPL4_REG_F_NUMBER + voice->number, voice->reg_f_number);
}
static void snd_opl4_update_tone_parameters(struct snd_opl4 *opl4,
struct opl4_voice *voice)
{
snd_opl4_write(opl4, OPL4_REG_ATTACK_DECAY1 + voice->number,
voice->sound->reg_attack_decay1);
snd_opl4_write(opl4, OPL4_REG_LEVEL_DECAY2 + voice->number,
voice->sound->reg_level_decay2);
snd_opl4_write(opl4, OPL4_REG_RELEASE_CORRECTION + voice->number,
voice->sound->reg_release_correction);
snd_opl4_write(opl4, OPL4_REG_TREMOLO + voice->number,
voice->sound->reg_tremolo);
}
/* allocate one voice */
static struct opl4_voice *snd_opl4_get_voice(struct snd_opl4 *opl4)
{
/* first, try to get the oldest key-off voice */
if (!list_empty(&opl4->off_voices))
return list_entry(opl4->off_voices.next, struct opl4_voice, list);
/* then get the oldest key-on voice */
snd_BUG_ON(list_empty(&opl4->on_voices));
return list_entry(opl4->on_voices.next, struct opl4_voice, list);
}
static void snd_opl4_wait_for_wave_headers(struct snd_opl4 *opl4)
{
int timeout = 200 ;
while ((inb(opl4->fm_port) & OPL4_STATUS_LOAD) && --timeout > 0 )
udelay(10 );
}
void snd_opl4_note_on(void *private_data, int note, int vel, struct snd_midi_channel *chan)
{
struct snd_opl4 *opl4 = private_data;
const struct opl4_region_ptr *regions;
struct opl4_voice *voice[2 ];
const struct opl4_sound *sound[2 ];
int voices = 0 , i;
unsigned long flags;
/* determine the number of voices and voice parameters */
i = chan->drum_channel ? 0 x80 : (chan->midi_program & 0 x7f);
regions = &snd_yrw801_regions[i];
for (i = 0 ; i < regions->count; i++) {
if (note >= regions->regions[i].key_min &&
note <= regions->regions[i].key_max) {
sound[voices] = ®ions->regions[i].sound;
if (++voices >= 2 )
break ;
}
}
/* allocate and initialize the needed voices */
spin_lock_irqsave(&opl4->reg_lock, flags);
for (i = 0 ; i < voices; i++) {
voice[i] = snd_opl4_get_voice(opl4);
list_move_tail(&voice[i]->list, &opl4->on_voices);
voice[i]->chan = chan;
voice[i]->note = note;
voice[i]->velocity = vel & 0 x7f;
voice[i]->sound = sound[i];
}
/* set tone number (triggers header loading) */
for (i = 0 ; i < voices; i++) {
voice[i]->reg_f_number =
(sound[i]->tone >> 8 ) & OPL4_TONE_NUMBER_BIT8;
snd_opl4_write(opl4, OPL4_REG_F_NUMBER + voice[i]->number,
voice[i]->reg_f_number);
snd_opl4_write(opl4, OPL4_REG_TONE_NUMBER + voice[i]->number,
sound[i]->tone & 0 xff);
}
/* set parameters which can be set while loading */
for (i = 0 ; i < voices; i++) {
voice[i]->reg_misc = OPL4_LFO_RESET_BIT;
snd_opl4_update_pan(opl4, voice[i]);
snd_opl4_update_pitch(opl4, voice[i]);
voice[i]->level_direct = OPL4_LEVEL_DIRECT_BIT;
snd_opl4_update_volume(opl4, voice[i]);
}
spin_unlock_irqrestore(&opl4->reg_lock, flags);
/* wait for completion of loading */
snd_opl4_wait_for_wave_headers(opl4);
/* set remaining parameters */
spin_lock_irqsave(&opl4->reg_lock, flags);
for (i = 0 ; i < voices; i++) {
snd_opl4_update_tone_parameters(opl4, voice[i]);
voice[i]->reg_lfo_vibrato = voice[i]->sound->reg_lfo_vibrato;
snd_opl4_update_vibrato_depth(opl4, voice[i]);
}
/* finally, switch on all voices */
for (i = 0 ; i < voices; i++) {
voice[i]->reg_misc =
(voice[i]->reg_misc & 0 x1f) | OPL4_KEY_ON_BIT;
snd_opl4_write(opl4, OPL4_REG_MISC + voice[i]->number,
voice[i]->reg_misc);
}
spin_unlock_irqrestore(&opl4->reg_lock, flags);
}
static void snd_opl4_voice_off(struct snd_opl4 *opl4, struct opl4_voice *voice)
{
list_move_tail(&voice->list, &opl4->off_voices);
voice->reg_misc &= ~OPL4_KEY_ON_BIT;
snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc);
}
void snd_opl4_note_off(void *private_data, int note, int vel, struct snd_midi_channel *chan)
{
struct snd_opl4 *opl4 = private_data;
snd_opl4_do_for_note(opl4, note, chan, snd_opl4_voice_off);
}
static void snd_opl4_terminate_voice(struct snd_opl4 *opl4, struct opl4_voice *voice)
{
list_move_tail(&voice->list, &opl4->off_voices);
voice->reg_misc = (voice->reg_misc & ~OPL4_KEY_ON_BIT) | OPL4_DAMP_BIT;
snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc);
}
void snd_opl4_terminate_note(void *private_data, int note, struct snd_midi_channel *chan)
{
struct snd_opl4 *opl4 = private_data;
snd_opl4_do_for_note(opl4, note, chan, snd_opl4_terminate_voice);
}
void snd_opl4_control(void *private_data, int type, struct snd_midi_channel *chan)
{
struct snd_opl4 *opl4 = private_data;
switch (type) {
case MIDI_CTL_MSB_MODWHEEL:
chan->control[MIDI_CTL_VIBRATO_DEPTH] = chan->control[MIDI_CTL_MSB_MODWHEEL];
snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_vibrato_depth);
break ;
case MIDI_CTL_MSB_MAIN_VOLUME:
snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_volume);
break ;
case MIDI_CTL_MSB_PAN:
snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_pan);
break ;
case MIDI_CTL_MSB_EXPRESSION:
snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_volume);
break ;
case MIDI_CTL_VIBRATO_RATE:
/* not yet supported */
break ;
case MIDI_CTL_VIBRATO_DEPTH:
snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_vibrato_depth);
break ;
case MIDI_CTL_VIBRATO_DELAY:
/* not yet supported */
break ;
case MIDI_CTL_E1_REVERB_DEPTH:
/*
* Each OPL4 voice has a bit called " Pseudo - Reverb " , but
* IMHO _ not_ using it enhances the listening experience .
*/
break ;
case MIDI_CTL_PITCHBEND:
snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_pitch);
break ;
}
}
void snd_opl4_sysex(void *private_data, unsigned char *buf, int len,
int parsed, struct snd_midi_channel_set *chset)
{
struct snd_opl4 *opl4 = private_data;
if (parsed == SNDRV_MIDI_SYSEX_GS_MASTER_VOLUME)
snd_opl4_do_for_all(opl4, snd_opl4_update_volume);
}
Messung V0.5 in Prozent C=97 H=86 G=91