mirror of
https://github.com/libretro/scummvm.git
synced 2025-04-04 07:41:58 +00:00
parent
9cb88f1d46
commit
9d0b746aaa
62
README
62
README
@ -30,11 +30,12 @@ Table of Contents:
|
|||||||
* 6.1 Autosaves
|
* 6.1 Autosaves
|
||||||
7.0) Music and Sound
|
7.0) Music and Sound
|
||||||
* 7.1 Adlib emulation
|
* 7.1 Adlib emulation
|
||||||
* 7.2 MIDI emulation
|
* 7.2 MT-32 emulation
|
||||||
* 7.3 Native MIDI support
|
* 7.3 MIDI emulation
|
||||||
* 7.4 UNIX native & ALSA sequencer support
|
* 7.4 Native MIDI support
|
||||||
* 7.5 Using compressed audiofiles (MP3, Ogg Vorbis, Flac)
|
* 7.5 UNIX native & ALSA sequencer support
|
||||||
* 7.6 Output sample rate
|
* 7.6 Using compressed audiofiles (MP3, Ogg Vorbis, Flac)
|
||||||
|
* 7.7 Output sample rate
|
||||||
8.0) Configuration Files
|
8.0) Configuration Files
|
||||||
9.0) Compiling
|
9.0) Compiling
|
||||||
X.X) Credits
|
X.X) Credits
|
||||||
@ -659,6 +660,7 @@ manual configuration. If you ARE using MIDI, you have several different
|
|||||||
choices of output, depending on your operating system and configuration.
|
choices of output, depending on your operating system and configuration.
|
||||||
|
|
||||||
adlib - Uses internal Adlib Emulation (default)
|
adlib - Uses internal Adlib Emulation (default)
|
||||||
|
mt32 - Uses internal MT-32 Emulation
|
||||||
pcjr - Uses internal PCjr Emulation
|
pcjr - Uses internal PCjr Emulation
|
||||||
pcspk - Uses internal PC Speaker Emulation
|
pcspk - Uses internal PC Speaker Emulation
|
||||||
towns - Uses FM-TOWNS YM2612 Emulation
|
towns - Uses FM-TOWNS YM2612 Emulation
|
||||||
@ -682,25 +684,38 @@ By default an Adlib card will be emulated and ScummVM will output the music
|
|||||||
as sampled waves. This is the default mode for most games, and offers the
|
as sampled waves. This is the default mode for most games, and offers the
|
||||||
best compatibility between machines and games.
|
best compatibility between machines and games.
|
||||||
|
|
||||||
|
7.2) Playing sound with MT-32 emulation:
|
||||||
|
---- -----------------------------------
|
||||||
|
Some games which contain MIDI music data also have improved tracks designed
|
||||||
|
for MT-32 sound module. ScummVM can now emulate this card, however you should
|
||||||
|
provide original MT-32 ROMs to make it work. Put the roms in game directory or
|
||||||
|
directory specified by extrapath.
|
||||||
|
|
||||||
7.2) Playing sound with MIDI emulation:
|
You don't need to specify --native-mt32 with this driver, as it automatically
|
||||||
|
gets turned on.
|
||||||
|
|
||||||
|
NOTE: You need to have enough processor power to use this emulator as it uses
|
||||||
|
heavy floating-point computations.
|
||||||
|
|
||||||
|
|
||||||
|
7.3) Playing sound with MIDI emulation:
|
||||||
---- ----------------------------------
|
---- ----------------------------------
|
||||||
Some games (such as Sam and Max) only contain MIDI music data. This once
|
Some games (such as Sam and Max) only contain MIDI music data. This once
|
||||||
prevented music for these games from working on platforms that do not support
|
prevented music for these games from working on platforms that do not support
|
||||||
MIDI, or soundcards that do not provide MIDI drivers (e.g, many soundcards will
|
MIDI, or soundcards that do not provide MIDI drivers (e.g, many soundcards will
|
||||||
not play MIDI under Linux). ScummVM can now emulate MIDI mode using sampled
|
not play MIDI under Linux). ScummVM can now emulate MIDI mode using sampled
|
||||||
waves and Adlib emulation using the -eadlib option. However, if you are capable
|
waves and Adlib or MT-32 emulation using the -eadlib or -emt32 options respectively.
|
||||||
of using native MIDI, we recommend using one of the MIDI modes below for best
|
However, if you are capable of using native MIDI, we recommend using one of the MIDI
|
||||||
sound.
|
modes below for best sound.
|
||||||
|
|
||||||
7.3) Playing sound with Native MIDI:
|
7.4) Playing sound with Native MIDI:
|
||||||
---- -------------------------------
|
---- -------------------------------
|
||||||
Use the appropriate -e<mode> command line option from the list above to
|
Use the appropriate -e<mode> command line option from the list above to
|
||||||
select your preferred MIDI device. For example, if you wish to use the
|
select your preferred MIDI device. For example, if you wish to use the
|
||||||
Windows MIDI driver, use the -ewindows option.
|
Windows MIDI driver, use the -ewindows option.
|
||||||
|
|
||||||
|
|
||||||
7.4.0) Playing sound with Sequencer MIDI: [UNIX ONLY]
|
7.5.0) Playing sound with Sequencer MIDI: [UNIX ONLY]
|
||||||
------ ----------------------------------
|
------ ----------------------------------
|
||||||
If your soundcard driver supports a sequencer, you may set the environment
|
If your soundcard driver supports a sequencer, you may set the environment
|
||||||
variable "SCUMMVM_MIDI" to your sequencer device - e.g., /dev/sequencer
|
variable "SCUMMVM_MIDI" to your sequencer device - e.g., /dev/sequencer
|
||||||
@ -713,7 +728,7 @@ performance and quality than Adlib emulation. However, for those systems where
|
|||||||
sequencer support does not work, you can always fall back on Adlib emulation.
|
sequencer support does not work, you can always fall back on Adlib emulation.
|
||||||
|
|
||||||
|
|
||||||
7.4.1) Playing sound with ALSA sequencer: [UNIX ONLY]
|
7.5.1) Playing sound with ALSA sequencer: [UNIX ONLY]
|
||||||
------ ----------------------------------
|
------ ----------------------------------
|
||||||
If you have installed the ALSA driver with the sequencer support, then
|
If you have installed the ALSA driver with the sequencer support, then
|
||||||
set the environment variable SCUMMVM_PORT or the config file parameter
|
set the environment variable SCUMMVM_PORT or the config file parameter
|
||||||
@ -762,7 +777,7 @@ Asking FluidSynth to become an ALSA sequencer (using SoundFonts):
|
|||||||
Once either TiMidity or FluidSynth are running, use the 'aconnect -o -l'
|
Once either TiMidity or FluidSynth are running, use the 'aconnect -o -l'
|
||||||
command as described earlier in this section.
|
command as described earlier in this section.
|
||||||
|
|
||||||
7.5.0) Using MP3 files for CD audio:
|
7.6.0) Using MP3 files for CD audio:
|
||||||
------ -----------------------------
|
------ -----------------------------
|
||||||
Use LAME or some other MP3 encoder to rip the cd audio tracks to files. Name
|
Use LAME or some other MP3 encoder to rip the cd audio tracks to files. Name
|
||||||
the files track1.mp3 track2.mp3 etc. ScummVM must be compiled with MAD support
|
the files track1.mp3 track2.mp3 etc. ScummVM must be compiled with MAD support
|
||||||
@ -773,7 +788,7 @@ following LAME command line:
|
|||||||
lame -t -q 0 -b 96 track1.wav track1.mp3
|
lame -t -q 0 -b 96 track1.wav track1.mp3
|
||||||
|
|
||||||
|
|
||||||
7.5.1) Using Ogg Vorbis files for CD audio:
|
7.6.1) Using Ogg Vorbis files for CD audio:
|
||||||
------ ------------------------------------
|
------ ------------------------------------
|
||||||
Use oggenc or some other vorbis encoder to encode the audio tracks to files.
|
Use oggenc or some other vorbis encoder to encode the audio tracks to files.
|
||||||
Name the files track1.ogg track2.ogg etc. ScummVM must be compiled with vorbis
|
Name the files track1.ogg track2.ogg etc. ScummVM must be compiled with vorbis
|
||||||
@ -784,7 +799,7 @@ command line with the value after q specifying the desired quality from 0 to 10:
|
|||||||
oggenc -q 5 track1.wav
|
oggenc -q 5 track1.wav
|
||||||
|
|
||||||
|
|
||||||
7.5.2) Using Flac files for CD audio:
|
7.6.2) Using Flac files for CD audio:
|
||||||
------ ------------------------------------
|
------ ------------------------------------
|
||||||
Use flac or some other flac encoder to encode the audio tracks to files.
|
Use flac or some other flac encoder to encode the audio tracks to files.
|
||||||
Name the files track1.flac track2.flac etc. In your filesystem only allows
|
Name the files track1.flac track2.flac etc. In your filesystem only allows
|
||||||
@ -799,7 +814,7 @@ Remember that the quality is always the same, varying encoder options will only
|
|||||||
affect the encoding time and resulting filesize.
|
affect the encoding time and resulting filesize.
|
||||||
|
|
||||||
|
|
||||||
7.5.3) Compressing MONSTER.SOU with MP3:
|
7.6.3) Compressing MONSTER.SOU with MP3:
|
||||||
------ ---------------------------------
|
------ ---------------------------------
|
||||||
You need LAME, and our extract util from the scummvm-tools package to perform
|
You need LAME, and our extract util from the scummvm-tools package to perform
|
||||||
this task, and ScummVM must be compiled with MAD support.
|
this task, and ScummVM must be compiled with MAD support.
|
||||||
@ -810,7 +825,7 @@ Eventually you will have a much smaller monster.so3 file, copy this file
|
|||||||
to your game directory. You can safely remove the monster.sou file.
|
to your game directory. You can safely remove the monster.sou file.
|
||||||
|
|
||||||
|
|
||||||
7.5.4) Compressing MONSTER.SOU with Ogg Vorbis:
|
7.6.4) Compressing MONSTER.SOU with Ogg Vorbis:
|
||||||
------ ----------------------------------------
|
------ ----------------------------------------
|
||||||
As above, but ScummVM must be compiled with OGG support. Run:
|
As above, but ScummVM must be compiled with OGG support. Run:
|
||||||
|
|
||||||
@ -821,7 +836,7 @@ game directory. Ogg encoding may take a considerable longer amount of time
|
|||||||
than MP3, so have a good book handy.
|
than MP3, so have a good book handy.
|
||||||
|
|
||||||
|
|
||||||
7.5.5) Compressing MONSTER.SOU with Flac:
|
7.6.5) Compressing MONSTER.SOU with Flac:
|
||||||
------ ----------------------------------------
|
------ ----------------------------------------
|
||||||
As above, but ScummVM must be compiled with Flac support. Run:
|
As above, but ScummVM must be compiled with Flac support. Run:
|
||||||
|
|
||||||
@ -835,7 +850,7 @@ filesize - 1152 seems to be a good value for those kind of soundfiles. Be sure
|
|||||||
to read the encoder documentation before you use other values.
|
to read the encoder documentation before you use other values.
|
||||||
|
|
||||||
|
|
||||||
7.5.6) Compressing sfx/speech in Simon the Sorcerer 1 and 2
|
7.6.6) Compressing sfx/speech in Simon the Sorcerer 1 and 2
|
||||||
------ ----------------------------------------------------
|
------ ----------------------------------------------------
|
||||||
Use our simon2mp3 util from the scummvm-tools package to perform this task.
|
Use our simon2mp3 util from the scummvm-tools package to perform this task.
|
||||||
You can choose between multiple target formats, but note that you can only use
|
You can choose between multiple target formats, but note that you can only use
|
||||||
@ -861,7 +876,7 @@ For Flac add --flac and optional parameters, i.e.
|
|||||||
Eventually you will have a much smaller *.mp3, *.ogg or *.fla file, copy this
|
Eventually you will have a much smaller *.mp3, *.ogg or *.fla file, copy this
|
||||||
file to your game dir. You can safely remove the old file.
|
file to your game dir. You can safely remove the old file.
|
||||||
|
|
||||||
7.5.7) Compressing speech/music in Broken Sword 1
|
7.6.7) Compressing speech/music in Broken Sword 1
|
||||||
------ ------------------------------------------
|
------ ------------------------------------------
|
||||||
The sword1mp3 tool from the scummvm-tools package can encode music and speech
|
The sword1mp3 tool from the scummvm-tools package can encode music and speech
|
||||||
to MP3 as well as Ogg Vorbis.
|
to MP3 as well as Ogg Vorbis.
|
||||||
@ -876,7 +891,7 @@ of MP3.
|
|||||||
Use "sword1mp3 --help" to get a full list of the options.
|
Use "sword1mp3 --help" to get a full list of the options.
|
||||||
|
|
||||||
|
|
||||||
7.5.8) Compressing speech/music in Broken Sword 2
|
7.6.8) Compressing speech/music in Broken Sword 2
|
||||||
------ ------------------------------------------
|
------ ------------------------------------------
|
||||||
Use our sword2mp3 util from the scummvm-tools package to perform this task.
|
Use our sword2mp3 util from the scummvm-tools package to perform this task.
|
||||||
You can choose between multiple target formats, but note that you can only use
|
You can choose between multiple target formats, but note that you can only use
|
||||||
@ -900,7 +915,7 @@ Broken Sword 2. It will not work with any of the other *.clu files, nor will it
|
|||||||
work with the speech files from Broken Sword 1.
|
work with the speech files from Broken Sword 1.
|
||||||
|
|
||||||
|
|
||||||
7.6) Output sample rate:
|
7.7) Output sample rate:
|
||||||
---- -------------------
|
---- -------------------
|
||||||
|
|
||||||
The output sample rate tells ScummVM how many sound samples to play per channel
|
The output sample rate tells ScummVM how many sound samples to play per channel
|
||||||
@ -1181,9 +1196,12 @@ X.X) Credits:
|
|||||||
|
|
||||||
Special thanks to:
|
Special thanks to:
|
||||||
Sander Buskens - For his work on the initial reversing of Monkey2
|
Sander Buskens - For his work on the initial reversing of Monkey2
|
||||||
|
Canadacow - For his MT-32 emulator
|
||||||
Kevin Carnes - For Scumm16, the basis of ScummVM older gfx codec
|
Kevin Carnes - For Scumm16, the basis of ScummVM older gfx codec
|
||||||
|
Jezar - For his freeverb filter implementation
|
||||||
Jim Leiterman - Various info on his FM-TOWNS/Marty SCUMM ports
|
Jim Leiterman - Various info on his FM-TOWNS/Marty SCUMM ports
|
||||||
Jimmi Thogersen - For ScummRev, and much obscure code/documentation
|
Jimmi Thogersen - For ScummRev, and much obscure code/documentation
|
||||||
|
Tristan - For his Linux port of MT-32 emulator
|
||||||
|
|
||||||
Tony Warriner and everyone at Revolution Software Ltd. for sharing
|
Tony Warriner and everyone at Revolution Software Ltd. for sharing
|
||||||
with us the source of some of their brilliant games, allowing us to
|
with us the source of some of their brilliant games, allowing us to
|
||||||
|
1
backends/midi/mt32/.cvsignore
Normal file
1
backends/midi/mt32/.cvsignore
Normal file
@ -0,0 +1 @@
|
|||||||
|
.deps
|
356
backends/midi/mt32/freeverb.cpp
Normal file
356
backends/midi/mt32/freeverb.cpp
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2004 The ScummVM project
|
||||||
|
* Copyright (C) 2000 Jezar at Dreampoint
|
||||||
|
*
|
||||||
|
* This code is public domain
|
||||||
|
*
|
||||||
|
* Parts of this code are:
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it 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 program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Comb filter implementation
|
||||||
|
//
|
||||||
|
// Written by
|
||||||
|
// http://www.dreampoint.co.uk
|
||||||
|
// This code is public domain
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "backends/midi/mt32/freeverb.h"
|
||||||
|
|
||||||
|
comb::comb()
|
||||||
|
{
|
||||||
|
filterstore = 0;
|
||||||
|
bufidx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void comb::setbuffer(float *buf, int size)
|
||||||
|
{
|
||||||
|
buffer = buf;
|
||||||
|
bufsize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void comb::mute()
|
||||||
|
{
|
||||||
|
for (int i=0; i<bufsize; i++)
|
||||||
|
buffer[i]=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void comb::setdamp(float val)
|
||||||
|
{
|
||||||
|
damp1 = val;
|
||||||
|
damp2 = 1-val;
|
||||||
|
}
|
||||||
|
|
||||||
|
float comb::getdamp()
|
||||||
|
{
|
||||||
|
return damp1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void comb::setfeedback(float val)
|
||||||
|
{
|
||||||
|
feedback = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
float comb::getfeedback()
|
||||||
|
{
|
||||||
|
return feedback;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allpass filter implementation
|
||||||
|
|
||||||
|
allpass::allpass()
|
||||||
|
{
|
||||||
|
bufidx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void allpass::setbuffer(float *buf, int size)
|
||||||
|
{
|
||||||
|
buffer = buf;
|
||||||
|
bufsize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void allpass::mute()
|
||||||
|
{
|
||||||
|
for (int i=0; i<bufsize; i++)
|
||||||
|
buffer[i]=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void allpass::setfeedback(float val)
|
||||||
|
{
|
||||||
|
feedback = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
float allpass::getfeedback()
|
||||||
|
{
|
||||||
|
return feedback;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverb model implementation
|
||||||
|
|
||||||
|
revmodel::revmodel()
|
||||||
|
{
|
||||||
|
// Tie the components to their buffers
|
||||||
|
combL[0].setbuffer(bufcombL1,combtuningL1);
|
||||||
|
combR[0].setbuffer(bufcombR1,combtuningR1);
|
||||||
|
combL[1].setbuffer(bufcombL2,combtuningL2);
|
||||||
|
combR[1].setbuffer(bufcombR2,combtuningR2);
|
||||||
|
combL[2].setbuffer(bufcombL3,combtuningL3);
|
||||||
|
combR[2].setbuffer(bufcombR3,combtuningR3);
|
||||||
|
combL[3].setbuffer(bufcombL4,combtuningL4);
|
||||||
|
combR[3].setbuffer(bufcombR4,combtuningR4);
|
||||||
|
combL[4].setbuffer(bufcombL5,combtuningL5);
|
||||||
|
combR[4].setbuffer(bufcombR5,combtuningR5);
|
||||||
|
combL[5].setbuffer(bufcombL6,combtuningL6);
|
||||||
|
combR[5].setbuffer(bufcombR6,combtuningR6);
|
||||||
|
combL[6].setbuffer(bufcombL7,combtuningL7);
|
||||||
|
combR[6].setbuffer(bufcombR7,combtuningR7);
|
||||||
|
combL[7].setbuffer(bufcombL8,combtuningL8);
|
||||||
|
combR[7].setbuffer(bufcombR8,combtuningR8);
|
||||||
|
allpassL[0].setbuffer(bufallpassL1,allpasstuningL1);
|
||||||
|
allpassR[0].setbuffer(bufallpassR1,allpasstuningR1);
|
||||||
|
allpassL[1].setbuffer(bufallpassL2,allpasstuningL2);
|
||||||
|
allpassR[1].setbuffer(bufallpassR2,allpasstuningR2);
|
||||||
|
allpassL[2].setbuffer(bufallpassL3,allpasstuningL3);
|
||||||
|
allpassR[2].setbuffer(bufallpassR3,allpasstuningR3);
|
||||||
|
allpassL[3].setbuffer(bufallpassL4,allpasstuningL4);
|
||||||
|
allpassR[3].setbuffer(bufallpassR4,allpasstuningR4);
|
||||||
|
|
||||||
|
// Set default values
|
||||||
|
allpassL[0].setfeedback(0.5f);
|
||||||
|
allpassR[0].setfeedback(0.5f);
|
||||||
|
allpassL[1].setfeedback(0.5f);
|
||||||
|
allpassR[1].setfeedback(0.5f);
|
||||||
|
allpassL[2].setfeedback(0.5f);
|
||||||
|
allpassR[2].setfeedback(0.5f);
|
||||||
|
allpassL[3].setfeedback(0.5f);
|
||||||
|
allpassR[3].setfeedback(0.5f);
|
||||||
|
setwet(initialwet);
|
||||||
|
setroomsize(initialroom);
|
||||||
|
setdry(initialdry);
|
||||||
|
setdamp(initialdamp);
|
||||||
|
setwidth(initialwidth);
|
||||||
|
setmode(initialmode);
|
||||||
|
|
||||||
|
// Buffer will be full of rubbish - so we MUST mute them
|
||||||
|
mute();
|
||||||
|
}
|
||||||
|
|
||||||
|
void revmodel::mute()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (getmode() >= freezemode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i=0;i<numcombs;i++)
|
||||||
|
{
|
||||||
|
combL[i].mute();
|
||||||
|
combR[i].mute();
|
||||||
|
}
|
||||||
|
for (i=0;i<numallpasses;i++)
|
||||||
|
{
|
||||||
|
allpassL[i].mute();
|
||||||
|
allpassR[i].mute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void revmodel::processreplace(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip)
|
||||||
|
{
|
||||||
|
float outL,outR,input;
|
||||||
|
|
||||||
|
while(numsamples-- > 0)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
outL = outR = 0;
|
||||||
|
input = (*inputL + *inputR) * gain;
|
||||||
|
|
||||||
|
// Accumulate comb filters in parallel
|
||||||
|
for(i=0; i<numcombs; i++)
|
||||||
|
{
|
||||||
|
outL += combL[i].process(input);
|
||||||
|
outR += combR[i].process(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feed through allpasses in series
|
||||||
|
for(i=0; i<numallpasses; i++)
|
||||||
|
{
|
||||||
|
outL = allpassL[i].process(outL);
|
||||||
|
outR = allpassR[i].process(outR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate output REPLACING anything already there
|
||||||
|
*outputL = outL*wet1 + outR*wet2 + *inputL*dry;
|
||||||
|
*outputR = outR*wet1 + outL*wet2 + *inputR*dry;
|
||||||
|
|
||||||
|
// Increment sample pointers, allowing for interleave (if any)
|
||||||
|
inputL += skip;
|
||||||
|
inputR += skip;
|
||||||
|
outputL += skip;
|
||||||
|
outputR += skip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void revmodel::processmix(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip)
|
||||||
|
{
|
||||||
|
float outL,outR,input;
|
||||||
|
|
||||||
|
while(numsamples-- > 0)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
outL = outR = 0;
|
||||||
|
input = (*inputL + *inputR) * gain;
|
||||||
|
|
||||||
|
// Accumulate comb filters in parallel
|
||||||
|
for(i=0; i<numcombs; i++)
|
||||||
|
{
|
||||||
|
outL += combL[i].process(input);
|
||||||
|
outR += combR[i].process(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feed through allpasses in series
|
||||||
|
for(i=0; i<numallpasses; i++)
|
||||||
|
{
|
||||||
|
outL = allpassL[i].process(outL);
|
||||||
|
outR = allpassR[i].process(outR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate output MIXING with anything already there
|
||||||
|
*outputL += outL*wet1 + outR*wet2 + *inputL*dry;
|
||||||
|
*outputR += outR*wet1 + outL*wet2 + *inputR*dry;
|
||||||
|
|
||||||
|
// Increment sample pointers, allowing for interleave (if any)
|
||||||
|
inputL += skip;
|
||||||
|
inputR += skip;
|
||||||
|
outputL += skip;
|
||||||
|
outputR += skip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void revmodel::update()
|
||||||
|
{
|
||||||
|
// Recalculate internal values after parameter change
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
wet1 = wet*(width/2 + 0.5f);
|
||||||
|
wet2 = wet*((1-width)/2);
|
||||||
|
|
||||||
|
if (mode >= freezemode)
|
||||||
|
{
|
||||||
|
roomsize1 = 1;
|
||||||
|
damp1 = 0;
|
||||||
|
gain = muted;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
roomsize1 = roomsize;
|
||||||
|
damp1 = damp;
|
||||||
|
gain = fixedgain;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i=0; i<numcombs; i++)
|
||||||
|
{
|
||||||
|
combL[i].setfeedback(roomsize1);
|
||||||
|
combR[i].setfeedback(roomsize1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i=0; i<numcombs; i++)
|
||||||
|
{
|
||||||
|
combL[i].setdamp(damp1);
|
||||||
|
combR[i].setdamp(damp1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following get/set functions are not inlined, because
|
||||||
|
// speed is never an issue when calling them, and also
|
||||||
|
// because as you develop the reverb model, you may
|
||||||
|
// wish to take dynamic action when they are called.
|
||||||
|
|
||||||
|
void revmodel::setroomsize(float value)
|
||||||
|
{
|
||||||
|
roomsize = (value*scaleroom) + offsetroom;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
float revmodel::getroomsize()
|
||||||
|
{
|
||||||
|
return (roomsize-offsetroom)/scaleroom;
|
||||||
|
}
|
||||||
|
|
||||||
|
void revmodel::setdamp(float value)
|
||||||
|
{
|
||||||
|
damp = value*scaledamp;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
float revmodel::getdamp()
|
||||||
|
{
|
||||||
|
return damp/scaledamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void revmodel::setwet(float value)
|
||||||
|
{
|
||||||
|
wet = value*scalewet;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
float revmodel::getwet()
|
||||||
|
{
|
||||||
|
return wet/scalewet;
|
||||||
|
}
|
||||||
|
|
||||||
|
void revmodel::setdry(float value)
|
||||||
|
{
|
||||||
|
dry = value*scaledry;
|
||||||
|
}
|
||||||
|
|
||||||
|
float revmodel::getdry()
|
||||||
|
{
|
||||||
|
return dry/scaledry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void revmodel::setwidth(float value)
|
||||||
|
{
|
||||||
|
width = value;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
float revmodel::getwidth()
|
||||||
|
{
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
void revmodel::setmode(float value)
|
||||||
|
{
|
||||||
|
mode = value;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
float revmodel::getmode()
|
||||||
|
{
|
||||||
|
if (mode >= freezemode)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//ends
|
||||||
|
|
246
backends/midi/mt32/freeverb.h
Normal file
246
backends/midi/mt32/freeverb.h
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2004 The ScummVM project
|
||||||
|
* Copyright (C) 2000 Jezar at Dreampoint
|
||||||
|
*
|
||||||
|
* This code is public domain
|
||||||
|
*
|
||||||
|
* Parts of this code are:
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it 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 program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Macro for killing denormalled numbers
|
||||||
|
//
|
||||||
|
// Written by Jezar at Dreampoint, June 2000
|
||||||
|
// http://www.dreampoint.co.uk
|
||||||
|
// Based on IS_DENORMAL macro by Jon Watte
|
||||||
|
// This code is public domain
|
||||||
|
|
||||||
|
#ifndef _freeverb_h_
|
||||||
|
#define _freeverb_h_
|
||||||
|
|
||||||
|
#define undenormalise(sample) if(((*(unsigned int*)&sample)&0x7f800000)==0) sample=0.0f
|
||||||
|
|
||||||
|
// Comb filter class declaration
|
||||||
|
|
||||||
|
class comb
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
comb();
|
||||||
|
void setbuffer(float *buf, int size);
|
||||||
|
inline float process(float inp);
|
||||||
|
void mute();
|
||||||
|
void setdamp(float val);
|
||||||
|
float getdamp();
|
||||||
|
void setfeedback(float val);
|
||||||
|
float getfeedback();
|
||||||
|
private:
|
||||||
|
float feedback;
|
||||||
|
float filterstore;
|
||||||
|
float damp1;
|
||||||
|
float damp2;
|
||||||
|
float *buffer;
|
||||||
|
int bufsize;
|
||||||
|
int bufidx;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Big to inline - but crucial for speed
|
||||||
|
|
||||||
|
inline float comb::process(float input)
|
||||||
|
{
|
||||||
|
float output;
|
||||||
|
|
||||||
|
output = buffer[bufidx];
|
||||||
|
undenormalise(output);
|
||||||
|
|
||||||
|
filterstore = (output*damp2) + (filterstore*damp1);
|
||||||
|
undenormalise(filterstore);
|
||||||
|
|
||||||
|
buffer[bufidx] = input + (filterstore*feedback);
|
||||||
|
|
||||||
|
if(++bufidx>=bufsize) bufidx = 0;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allpass filter declaration
|
||||||
|
|
||||||
|
class allpass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
allpass();
|
||||||
|
void setbuffer(float *buf, int size);
|
||||||
|
inline float process(float inp);
|
||||||
|
void mute();
|
||||||
|
void setfeedback(float val);
|
||||||
|
float getfeedback();
|
||||||
|
// private:
|
||||||
|
float feedback;
|
||||||
|
float *buffer;
|
||||||
|
int bufsize;
|
||||||
|
int bufidx;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Big to inline - but crucial for speed
|
||||||
|
|
||||||
|
inline float allpass::process(float input)
|
||||||
|
{
|
||||||
|
float output;
|
||||||
|
float bufout;
|
||||||
|
|
||||||
|
bufout = buffer[bufidx];
|
||||||
|
undenormalise(bufout);
|
||||||
|
|
||||||
|
output = -input + bufout;
|
||||||
|
buffer[bufidx] = input + (bufout*feedback);
|
||||||
|
|
||||||
|
if(++bufidx>=bufsize) bufidx = 0;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Reverb model tuning values
|
||||||
|
|
||||||
|
const int numcombs = 8;
|
||||||
|
const int numallpasses = 4;
|
||||||
|
const float muted = 0;
|
||||||
|
const float fixedgain = 0.015f;
|
||||||
|
const float scalewet = 3;
|
||||||
|
const float scaledry = 2;
|
||||||
|
const float scaledamp = 0.4f;
|
||||||
|
const float scaleroom = 0.28f;
|
||||||
|
const float offsetroom = 0.7f;
|
||||||
|
const float initialroom = 0.5f;
|
||||||
|
const float initialdamp = 0.5f;
|
||||||
|
const float initialwet = 1/scalewet;
|
||||||
|
const float initialdry = 0;
|
||||||
|
const float initialwidth = 1;
|
||||||
|
const float initialmode = 0;
|
||||||
|
const float freezemode = 0.5f;
|
||||||
|
const int stereospread = 23;
|
||||||
|
|
||||||
|
// These values assume 44.1KHz sample rate
|
||||||
|
// they will probably be OK for 48KHz sample rate
|
||||||
|
// but would need scaling for 96KHz (or other) sample rates.
|
||||||
|
// The values were obtained by listening tests.
|
||||||
|
const int combtuningL1 = 1116;
|
||||||
|
const int combtuningR1 = 1116+stereospread;
|
||||||
|
const int combtuningL2 = 1188;
|
||||||
|
const int combtuningR2 = 1188+stereospread;
|
||||||
|
const int combtuningL3 = 1277;
|
||||||
|
const int combtuningR3 = 1277+stereospread;
|
||||||
|
const int combtuningL4 = 1356;
|
||||||
|
const int combtuningR4 = 1356+stereospread;
|
||||||
|
const int combtuningL5 = 1422;
|
||||||
|
const int combtuningR5 = 1422+stereospread;
|
||||||
|
const int combtuningL6 = 1491;
|
||||||
|
const int combtuningR6 = 1491+stereospread;
|
||||||
|
const int combtuningL7 = 1557;
|
||||||
|
const int combtuningR7 = 1557+stereospread;
|
||||||
|
const int combtuningL8 = 1617;
|
||||||
|
const int combtuningR8 = 1617+stereospread;
|
||||||
|
const int allpasstuningL1 = 556;
|
||||||
|
const int allpasstuningR1 = 556+stereospread;
|
||||||
|
const int allpasstuningL2 = 441;
|
||||||
|
const int allpasstuningR2 = 441+stereospread;
|
||||||
|
const int allpasstuningL3 = 341;
|
||||||
|
const int allpasstuningR3 = 341+stereospread;
|
||||||
|
const int allpasstuningL4 = 225;
|
||||||
|
const int allpasstuningR4 = 225+stereospread;
|
||||||
|
|
||||||
|
|
||||||
|
// Reverb model declaration
|
||||||
|
|
||||||
|
class revmodel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
revmodel();
|
||||||
|
void mute();
|
||||||
|
void processmix(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip);
|
||||||
|
void processreplace(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip);
|
||||||
|
void setroomsize(float value);
|
||||||
|
float getroomsize();
|
||||||
|
void setdamp(float value);
|
||||||
|
float getdamp();
|
||||||
|
void setwet(float value);
|
||||||
|
float getwet();
|
||||||
|
void setdry(float value);
|
||||||
|
float getdry();
|
||||||
|
void setwidth(float value);
|
||||||
|
float getwidth();
|
||||||
|
void setmode(float value);
|
||||||
|
float getmode();
|
||||||
|
private:
|
||||||
|
void update();
|
||||||
|
private:
|
||||||
|
float gain;
|
||||||
|
float roomsize,roomsize1;
|
||||||
|
float damp,damp1;
|
||||||
|
float wet,wet1,wet2;
|
||||||
|
float dry;
|
||||||
|
float width;
|
||||||
|
float mode;
|
||||||
|
|
||||||
|
// The following are all declared inline
|
||||||
|
// to remove the need for dynamic allocation
|
||||||
|
// with its subsequent error-checking messiness
|
||||||
|
|
||||||
|
// Comb filters
|
||||||
|
comb combL[numcombs];
|
||||||
|
comb combR[numcombs];
|
||||||
|
|
||||||
|
// Allpass filters
|
||||||
|
allpass allpassL[numallpasses];
|
||||||
|
allpass allpassR[numallpasses];
|
||||||
|
|
||||||
|
// Buffers for the combs
|
||||||
|
float bufcombL1[combtuningL1];
|
||||||
|
float bufcombR1[combtuningR1];
|
||||||
|
float bufcombL2[combtuningL2];
|
||||||
|
float bufcombR2[combtuningR2];
|
||||||
|
float bufcombL3[combtuningL3];
|
||||||
|
float bufcombR3[combtuningR3];
|
||||||
|
float bufcombL4[combtuningL4];
|
||||||
|
float bufcombR4[combtuningR4];
|
||||||
|
float bufcombL5[combtuningL5];
|
||||||
|
float bufcombR5[combtuningR5];
|
||||||
|
float bufcombL6[combtuningL6];
|
||||||
|
float bufcombR6[combtuningR6];
|
||||||
|
float bufcombL7[combtuningL7];
|
||||||
|
float bufcombR7[combtuningR7];
|
||||||
|
float bufcombL8[combtuningL8];
|
||||||
|
float bufcombR8[combtuningR8];
|
||||||
|
|
||||||
|
// Buffers for the allpasses
|
||||||
|
float bufallpassL1[allpasstuningL1];
|
||||||
|
float bufallpassR1[allpasstuningR1];
|
||||||
|
float bufallpassL2[allpasstuningL2];
|
||||||
|
float bufallpassR2[allpasstuningR2];
|
||||||
|
float bufallpassL3[allpasstuningL3];
|
||||||
|
float bufallpassR3[allpasstuningR3];
|
||||||
|
float bufallpassL4[allpasstuningL4];
|
||||||
|
float bufallpassR4[allpasstuningR4];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif//_freeverb_h_
|
||||||
|
|
||||||
|
//ends
|
||||||
|
|
135
backends/midi/mt32/mt32.cpp
Normal file
135
backends/midi/mt32/mt32.cpp
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2001-2004 The ScummVM project
|
||||||
|
*
|
||||||
|
* YM2612 tone generation code written by Tomoaki Hayasaka.
|
||||||
|
* Used under the terms of the GNU General Public License.
|
||||||
|
* Adpated to ScummVM by Jamieson Christian.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it 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 program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "backends/midi/emumidi.h"
|
||||||
|
|
||||||
|
#include "common/util.h"
|
||||||
|
#include "common/file.h"
|
||||||
|
|
||||||
|
#include "backends/midi/mt32/synth.h"
|
||||||
|
|
||||||
|
class MidiDriver_MT32 : public MidiDriver_Emulated {
|
||||||
|
private:
|
||||||
|
CSynthMT32 *_synth;
|
||||||
|
|
||||||
|
const char *rom_path;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void generate_samples(int16 *buf, int len);
|
||||||
|
|
||||||
|
public:
|
||||||
|
MidiDriver_MT32(SoundMixer *mixer, const char *path);
|
||||||
|
virtual ~MidiDriver_MT32();
|
||||||
|
|
||||||
|
int open();
|
||||||
|
void close();
|
||||||
|
void send(uint32 b);
|
||||||
|
uint32 property(int prop, uint32 param) { return 0; }
|
||||||
|
|
||||||
|
void setPitchBendRange(byte channel, uint range) { }
|
||||||
|
void sysEx(byte *msg, uint16 length);
|
||||||
|
|
||||||
|
MidiChannel *allocateChannel() { return 0; }
|
||||||
|
MidiChannel *getPercussionChannel() { return 0; }
|
||||||
|
|
||||||
|
|
||||||
|
// AudioStream API
|
||||||
|
bool isStereo() const { return true; }
|
||||||
|
int getRate() const { return 32000; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// MidiDriver_MT32
|
||||||
|
//
|
||||||
|
////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
MidiDriver_MT32::MidiDriver_MT32(SoundMixer *mixer, const char *path)
|
||||||
|
: MidiDriver_Emulated(mixer) {
|
||||||
|
_synth = new CSynthMT32();
|
||||||
|
rom_path = path;
|
||||||
|
File::addDefaultDirectory(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
MidiDriver_MT32::~MidiDriver_MT32() {
|
||||||
|
delete _synth;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MidiDriver_MT32::open() {
|
||||||
|
SynthProperties prop;
|
||||||
|
|
||||||
|
if (_isOpen)
|
||||||
|
return MERR_ALREADY_OPEN;
|
||||||
|
|
||||||
|
MidiDriver_Emulated::open();
|
||||||
|
|
||||||
|
prop.SampleRate = getRate(); // 32000;
|
||||||
|
prop.UseReverb = true;
|
||||||
|
prop.UseDefault = true;
|
||||||
|
//prop.RevType = 0;
|
||||||
|
//prop.RevTime = 5;
|
||||||
|
//prop.RevLevel = 3;
|
||||||
|
|
||||||
|
_synth->ClassicOpen(rom_path, prop);
|
||||||
|
|
||||||
|
_mixer->setupPremix(this);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiDriver_MT32::send(uint32 b) {
|
||||||
|
_synth->PlayMsg(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiDriver_MT32::sysEx(byte *msg, uint16 length) {
|
||||||
|
_synth->PlaySysex(msg, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiDriver_MT32::close() {
|
||||||
|
if (!_isOpen)
|
||||||
|
return;
|
||||||
|
_isOpen = false;
|
||||||
|
|
||||||
|
// Detach the premix callback handler
|
||||||
|
_mixer->setupPremix(0);
|
||||||
|
|
||||||
|
_synth->Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MidiDriver_MT32::generate_samples(int16 *data, int len) {
|
||||||
|
_synth->MT32_CallBack((Bit8u *)data, len, _mixer->getMusicVolume());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// MidiDriver_MT32 factory
|
||||||
|
//
|
||||||
|
////////////////////////////////////////
|
||||||
|
|
||||||
|
MidiDriver *MidiDriver_MT32_create(SoundMixer *mixer, const char *path) {
|
||||||
|
return new MidiDriver_MT32(mixer, path);
|
||||||
|
}
|
591
backends/midi/mt32/partial.cpp
Normal file
591
backends/midi/mt32/partial.cpp
Normal file
@ -0,0 +1,591 @@
|
|||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2004 The ScummVM project
|
||||||
|
* Based on Tristan's conversion of Canadacow's code
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it 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 program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Implementation of the MT-32 partial class
|
||||||
|
|
||||||
|
#include "backends/midi/mt32/synth.h"
|
||||||
|
#include "backends/midi/mt32/partial.h"
|
||||||
|
|
||||||
|
INLINE void CPartialMT32::generateSamples(Bit16s * partialBuf, long length) {
|
||||||
|
if (!isActive) return;
|
||||||
|
if (alreadyOutputed) return;
|
||||||
|
|
||||||
|
|
||||||
|
alreadyOutputed = true;
|
||||||
|
|
||||||
|
// Generate samples
|
||||||
|
|
||||||
|
int r;
|
||||||
|
int i;
|
||||||
|
Bit32s envval, ampval, filtval;
|
||||||
|
soundaddr *pOff = &partCache->partialOff;
|
||||||
|
int noteval = partCache->keyedval;
|
||||||
|
for(i=0;i<length;i++) {
|
||||||
|
Bit32s ptemp = 0;
|
||||||
|
|
||||||
|
if(partCache->envs[AMPENV].sustaining) {
|
||||||
|
ampval = partCache->ampEnvCache;
|
||||||
|
} else {
|
||||||
|
if(partCache->envs[AMPENV].count<=0) {
|
||||||
|
|
||||||
|
ampval = getAmpEnvelope(partCache,tmppoly);
|
||||||
|
isActive = partCache->playPartial;
|
||||||
|
//TODO: check what is going on here
|
||||||
|
// if (ampval < 0) ampval = 0;
|
||||||
|
//printf("%d %d\n", (int)ampval, (int)isActive);
|
||||||
|
if(!isActive) {
|
||||||
|
tmppoly->partActive[timbreNum] = false;
|
||||||
|
tmppoly->isActive = tmppoly->partActive[0] || tmppoly->partActive[1] || tmppoly->partActive[2] || tmppoly->partActive[3];
|
||||||
|
}
|
||||||
|
if(ampval>=128) ampval = 127;
|
||||||
|
|
||||||
|
ampval = amptable[ampval];
|
||||||
|
int tmpvel = tmppoly->vel;
|
||||||
|
if(tcache->ampenvdir==1) tmpvel = 127-tmpvel;
|
||||||
|
ampval = (ampval * ampveltable[tmpvel][(int)tcache->ampEnv.velosens]) >> 8;
|
||||||
|
//if(partCache->envs[AMPENV].sustaining)
|
||||||
|
partCache->ampEnvCache = ampval;
|
||||||
|
} else {
|
||||||
|
ampval = partCache->ampEnvCache;
|
||||||
|
}
|
||||||
|
--partCache->envs[AMPENV].count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int delta = 0x10707;
|
||||||
|
|
||||||
|
// Calculate Pitch envelope
|
||||||
|
int lfoat = 0x1000;
|
||||||
|
int pdep;
|
||||||
|
if(partCache->pitchsustain) {
|
||||||
|
// Calculate LFO position
|
||||||
|
// LFO does not kick in completely until pitch envelope sustains
|
||||||
|
|
||||||
|
if(tcache->lfodepth>0) {
|
||||||
|
partCache->lfopos++;
|
||||||
|
|
||||||
|
if(partCache->lfopos>=tcache->lfoperiod) partCache->lfopos = 0;
|
||||||
|
int lfoatm = (partCache->lfopos << 16) / tcache->lfoperiod;
|
||||||
|
|
||||||
|
int lfoatr = sintable[lfoatm];
|
||||||
|
|
||||||
|
lfoat = lfoptable[tcache->lfodepth][lfoatr];
|
||||||
|
}
|
||||||
|
pdep = partCache->pitchEnvCache;
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
envval = getPitchEnvelope(partCache,tmppoly);
|
||||||
|
int pd=tcache->pitchEnv.depth;
|
||||||
|
pdep = penvtable[pd][envval];
|
||||||
|
if(partCache->pitchsustain) partCache->pitchEnvCache = pdep;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get waveform - either PCM or synthesized sawtooth or square
|
||||||
|
|
||||||
|
|
||||||
|
if (tcache->PCMPartial) {
|
||||||
|
// PCM partial
|
||||||
|
|
||||||
|
if(!partCache->PCMDone) {
|
||||||
|
|
||||||
|
int addr,len,tmppcm;
|
||||||
|
partialTable *tPCM = &tcache->convPCM;
|
||||||
|
|
||||||
|
if(tPCM->aggSound==-1) {
|
||||||
|
delta = wavtabler[tPCM->pcmnum][noteval];
|
||||||
|
addr = tPCM->addr;
|
||||||
|
len = tPCM->len;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
tmppcm = LoopPatterns[tPCM->aggSound][partCache->looppos];
|
||||||
|
addr = PCM[tmppcm].addr;
|
||||||
|
len = PCM[tmppcm].len;
|
||||||
|
delta = looptabler[tPCM->aggSound][partCache->looppos][noteval];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ampval>0) {
|
||||||
|
int ra,rb,dist;
|
||||||
|
int taddr;
|
||||||
|
if(delta<0x10000) {
|
||||||
|
// Linear sound interpolation
|
||||||
|
|
||||||
|
taddr = addr + pOff->pcmoffs.pcmplace;
|
||||||
|
ra = romfile[taddr];
|
||||||
|
rb = romfile[taddr+1];
|
||||||
|
|
||||||
|
dist = rb-ra;
|
||||||
|
r = (ra + ((dist * (Bit32s)(pOff->pcmoffs.pcmoffset>>8)) >>8));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
//r = romfile[addr + pOff->pcmoffs.pcmplace];
|
||||||
|
// Sound decimation
|
||||||
|
// The right way to do it is to use a lowpass filter on the waveform before selecting
|
||||||
|
// a point. This is too slow. The following appoximates this as fast as possible
|
||||||
|
int idelta = delta >> 16;
|
||||||
|
int ix;
|
||||||
|
taddr = addr + pOff->pcmoffs.pcmplace;
|
||||||
|
ra = 0;
|
||||||
|
for(ix=0;ix<idelta;ix++) {
|
||||||
|
ra += romfile[taddr++];
|
||||||
|
}
|
||||||
|
r = ra / idelta;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
} else r = 0;
|
||||||
|
|
||||||
|
ptemp = r;
|
||||||
|
|
||||||
|
if ((pOff->pcmoffs.pcmplace) >= len) {
|
||||||
|
if(tPCM->aggSound==-1) {
|
||||||
|
if(tPCM->loop) {
|
||||||
|
pOff->pcmabs = 0;
|
||||||
|
} else {
|
||||||
|
partCache->PCMDone = true;
|
||||||
|
partCache->playPartial = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
partCache->looppos++;
|
||||||
|
if(LoopPatterns[tPCM->aggSound][partCache->looppos]==-1) partCache->looppos=0;
|
||||||
|
pOff->pcmabs = 0;
|
||||||
|
}
|
||||||
|
//LOG_MSG("tPCM %d loops %d done %d playPart %d", tPCM->pcmnum, tPCM->loop, partCache->PCMDone, partCache->playPartial);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Synthesis partial
|
||||||
|
int divis, hdivis, ofs, ofs3, toff;
|
||||||
|
int minorplace;
|
||||||
|
|
||||||
|
int wf = tcache->waveform ;
|
||||||
|
|
||||||
|
divis = divtable[noteval]>>15;
|
||||||
|
|
||||||
|
if(pOff->pcmoffs.pcmplace>=divis) pOff->pcmoffs.pcmplace = (Bit16u)(pOff->pcmoffs.pcmplace-divis);
|
||||||
|
|
||||||
|
toff = pOff->pcmoffs.pcmplace;
|
||||||
|
minorplace = pOff->pcmoffs.pcmoffset >> 14;
|
||||||
|
|
||||||
|
int pa, pb;
|
||||||
|
|
||||||
|
if(ampval>0) {
|
||||||
|
|
||||||
|
filtval = getFiltEnvelope((Bit16s)ptemp,partCache,tmppoly);
|
||||||
|
|
||||||
|
//LOG_MSG("Filtval: %d", filtval);
|
||||||
|
|
||||||
|
if(wf==0) {
|
||||||
|
// Square waveform. Made by combining two pregenerated bandlimited
|
||||||
|
// sawtooth waveforms
|
||||||
|
// Pulse width is not yet correct
|
||||||
|
|
||||||
|
hdivis = divis >> 1;
|
||||||
|
int divmark = smalldivtable[noteval];
|
||||||
|
//int pw = (tcache->pulsewidth * pulsemod[filtval]) >> 8;
|
||||||
|
|
||||||
|
|
||||||
|
ofs = toff % (hdivis);
|
||||||
|
|
||||||
|
ofs3 = toff + ((divmark*pulsetable[partCache->pulsewidth])>>16);
|
||||||
|
ofs3 = ofs3 % (hdivis);
|
||||||
|
|
||||||
|
pa = waveforms[1][noteval][(ofs<<2)+minorplace];
|
||||||
|
pb = waveforms[0][noteval][(ofs3<<2)+minorplace];
|
||||||
|
//ptemp = pa+pb+pulseoffset[tcache->pulsewidth];
|
||||||
|
ptemp = (pa+pb)*4;
|
||||||
|
|
||||||
|
// Non-bandlimited squarewave
|
||||||
|
/*
|
||||||
|
ofs = (divis*pulsetable[tcache->pulsewidth])>>8;
|
||||||
|
if(toff < ofs) {
|
||||||
|
ptemp = 1 * WGAMP;
|
||||||
|
} else {
|
||||||
|
ptemp = -1 * WGAMP;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Sawtooth. Made by combining the full cosine and half cosine according
|
||||||
|
// to how it looks on the MT-32. What it really does it takes the
|
||||||
|
// square wave and multiplies it by a full cosine
|
||||||
|
// TODO: This area here crashes DosBox due to read overflow
|
||||||
|
int offsetpos = (toff<<2)+minorplace;
|
||||||
|
//int a = 0;
|
||||||
|
if(toff < sawtable[noteval][partCache->pulsewidth]) {
|
||||||
|
while(offsetpos>waveformsize[2][noteval]) {
|
||||||
|
offsetpos-=waveformsize[2][noteval];
|
||||||
|
}
|
||||||
|
ptemp = waveforms[2][noteval][offsetpos];
|
||||||
|
} else {
|
||||||
|
while(offsetpos>waveformsize[3][noteval]) {
|
||||||
|
offsetpos-=waveformsize[3][noteval];
|
||||||
|
}
|
||||||
|
ptemp = waveforms[3][noteval][offsetpos];
|
||||||
|
}
|
||||||
|
ptemp = ptemp *4;
|
||||||
|
|
||||||
|
// ptemp = (int)(sin((double)toff / 100.0) * 100.0);
|
||||||
|
//ptemp = pa;
|
||||||
|
|
||||||
|
// This is the correct way
|
||||||
|
// Seems slow to me (though bandlimited) -- doesn't seem to
|
||||||
|
// sound any better though
|
||||||
|
/*
|
||||||
|
hdivis = divis >> 1;
|
||||||
|
int divmark = smalldivtable[noteval];
|
||||||
|
//int pw = (tcache->pulsewidth * pulsemod[filtval]) >> 8;
|
||||||
|
|
||||||
|
|
||||||
|
ofs = toff % (hdivis);
|
||||||
|
|
||||||
|
ofs3 = toff + ((divmark*pulsetable[tcache->pulsewidth])>>16);
|
||||||
|
ofs3 = ofs3 % (hdivis);
|
||||||
|
|
||||||
|
pa = waveforms[0][noteval][ofs];
|
||||||
|
pb = waveforms[1][noteval][ofs3];
|
||||||
|
ptemp = ((pa+pb) * waveforms[3][noteval][toff]) / WGAMP;
|
||||||
|
ptemp = ptemp *4;
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Very exact filter
|
||||||
|
//ptemp[t] = (int)iir_filter((float)ptemp[t],&partCache->history[t],filtcoeff[filtval][tcache->filtEnv.resonance]);
|
||||||
|
if(filtval>((FILTERGRAN*15)/16)) filtval = ((FILTERGRAN*15)/16);
|
||||||
|
ptemp = (Bit32s)(usefilter)((float)ptemp,&partCache->history[0],filtcoeff[filtval][(int)tcache->filtEnv.resonance], tcache->filtEnv.resonance);
|
||||||
|
} else ptemp = 0;
|
||||||
|
|
||||||
|
//ptemp[t] = Moog1(ptemp[t],&partCache->history[t],(float)filtval/8192.0,tcache->filtEnv.resonance);
|
||||||
|
//ptemp[t] = Moog2(ptemp[t],&partCache->history[t],(float)filtval/8192.0,tcache->filtEnv.resonance);
|
||||||
|
//ptemp[t] = simpleLowpass(ptemp[t],&partCache->history[t],(float)filtval/8192.0,tcache->filtEnv.resonance);
|
||||||
|
|
||||||
|
// Use this to mute analogue synthesis
|
||||||
|
// ptemp = 0;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build delta for position of next sample
|
||||||
|
/*
|
||||||
|
delta = (delta * tcache->fineshift)>>12;
|
||||||
|
delta = (delta * pdep)>>12;
|
||||||
|
delta = (delta * lfoat)>>12;
|
||||||
|
if(tcache->useBender) delta = (delta * *tmppoly->bendptr)>>12;
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Fix delta code
|
||||||
|
__int64 tdelta = (__int64)delta;
|
||||||
|
tdelta = (tdelta * tcache->fineshift)>>12;
|
||||||
|
tdelta = (tdelta * pdep)>>12;
|
||||||
|
tdelta = (tdelta * lfoat)>>12;
|
||||||
|
if(tcache->useBender) tdelta = (tdelta * *tmppoly->bendptr)>>12;
|
||||||
|
|
||||||
|
// Add calculated delta to our waveform offset
|
||||||
|
pOff->pcmabs+=(int)tdelta;
|
||||||
|
|
||||||
|
// Put volume envelope over generated sample
|
||||||
|
ptemp = (ptemp * ampval) >> 9;
|
||||||
|
ptemp = (ptemp * *tmppoly->volumeptr) >> 7;
|
||||||
|
|
||||||
|
partCache->envs[AMPENV].envpos++;
|
||||||
|
partCache->envs[PITCHENV].envpos++;
|
||||||
|
partCache->envs[FILTENV].envpos++;
|
||||||
|
|
||||||
|
*partialBuf++ = (Bit16s)ptemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
INLINE void CPartialMT32::mixBuffers(Bit16s * buf1, Bit16s *buf2, int len) {
|
||||||
|
// Early exit if no need to mix
|
||||||
|
if(tibrePair==NULL) return;
|
||||||
|
|
||||||
|
#if USE_MMX == 0
|
||||||
|
int i;
|
||||||
|
for(i=0;i<len;i++) {
|
||||||
|
Bit32s tmp1 = buf1[i];
|
||||||
|
Bit32s tmp2 = buf2[i];
|
||||||
|
tmp1 += tmp2;
|
||||||
|
buf1[i] = (Bit16s)tmp1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
len = (len>>2)+4;
|
||||||
|
#ifdef I_ASM
|
||||||
|
__asm {
|
||||||
|
mov ecx, len
|
||||||
|
mov esi, buf1
|
||||||
|
mov edi, buf2
|
||||||
|
|
||||||
|
mixloop1:
|
||||||
|
movq mm1, [edi]
|
||||||
|
movq mm2, [esi]
|
||||||
|
paddw mm1,mm2
|
||||||
|
movq [esi],mm1
|
||||||
|
add edi,8
|
||||||
|
add esi,8
|
||||||
|
|
||||||
|
dec ecx
|
||||||
|
cmp ecx,0
|
||||||
|
jg mixloop1
|
||||||
|
emms
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
atti386_mixBuffers(buf1, buf2, len);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
INLINE void CPartialMT32::mixBuffersRingMix(Bit16s * buf1, Bit16s *buf2, int len) {
|
||||||
|
#if USE_MMX != 2
|
||||||
|
int i;
|
||||||
|
for(i=0;i<len;i++) {
|
||||||
|
float a, b;
|
||||||
|
a = ((float)buf1[i]) / 8192.0;
|
||||||
|
b = ((float)buf2[i]) / 8192.0;
|
||||||
|
a = (a * b) + a;
|
||||||
|
if(a>1.0) a = 1.0;
|
||||||
|
if(a<-1.0) a = -1.0;
|
||||||
|
buf1[i] = (Bit16s)(a * 8192.0);
|
||||||
|
|
||||||
|
//buf1[i] = (Bit16s)(((Bit32s)buf1[i] * (Bit32s)buf2[i]) >> 10) + buf1[i];
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
len = (len>>2)+4;
|
||||||
|
#ifdef I_ASM
|
||||||
|
__asm {
|
||||||
|
mov ecx, len
|
||||||
|
mov esi, buf1
|
||||||
|
mov edi, buf2
|
||||||
|
|
||||||
|
mixloop2:
|
||||||
|
movq mm1, [esi]
|
||||||
|
movq mm2, [edi]
|
||||||
|
movq mm3, mm1
|
||||||
|
pmulhw mm1, mm2
|
||||||
|
paddw mm1,mm3
|
||||||
|
movq [esi],mm1
|
||||||
|
add edi,8
|
||||||
|
add esi,8
|
||||||
|
|
||||||
|
dec ecx
|
||||||
|
cmp ecx,0
|
||||||
|
jg mixloop2
|
||||||
|
emms
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
atti386_mixBuffersRingMix(buf1, buf2, len);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
INLINE void CPartialMT32::mixBuffersRing(Bit16s * buf1, Bit16s *buf2, int len) {
|
||||||
|
#if USE_MMX != 2
|
||||||
|
int i;
|
||||||
|
for(i=0;i<len;i++) {
|
||||||
|
float a, b;
|
||||||
|
a = ((float)buf1[i]) / 8192.0;
|
||||||
|
b = ((float)buf2[i]) / 8192.0;
|
||||||
|
a *= b;
|
||||||
|
if(a>1.0) a = 1.0;
|
||||||
|
if(a<-1.0) a = -1.0;
|
||||||
|
buf1[i] = (Bit16s)(a * 8192.0);
|
||||||
|
//buf1[i] = (Bit16s)(((Bit32s)buf1[i] * (Bit32s)buf2[i]) >> 10);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
len = (len>>2)+4;
|
||||||
|
#ifdef I_ASM
|
||||||
|
__asm {
|
||||||
|
mov ecx, len
|
||||||
|
mov esi, buf1
|
||||||
|
mov edi, buf2
|
||||||
|
|
||||||
|
mixloop3:
|
||||||
|
movq mm1, [esi]
|
||||||
|
movq mm2, [edi]
|
||||||
|
pmulhw mm1, mm2
|
||||||
|
movq [esi],mm1
|
||||||
|
add edi,8
|
||||||
|
add esi,8
|
||||||
|
|
||||||
|
dec ecx
|
||||||
|
cmp ecx,0
|
||||||
|
jg mixloop3
|
||||||
|
emms
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
atti386_mixBuffersRing(buf1, buf2, len);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
INLINE void CPartialMT32::mixBuffersStereo(Bit16s *buf1, Bit16s *buf2, Bit16s *outBuf, int len) {
|
||||||
|
int i,m;
|
||||||
|
m=0;
|
||||||
|
for(i=0;i<len;i++) {
|
||||||
|
*outBuf++ = (*buf1);
|
||||||
|
buf1++;
|
||||||
|
*outBuf++ = (*buf2);
|
||||||
|
buf2++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CPartialMT32::produceOutput(Bit16s * partialBuf, long length) {
|
||||||
|
if (!isActive) return false;
|
||||||
|
if (alreadyOutputed) return false;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
//alreadyOutputed = true;
|
||||||
|
|
||||||
|
memset(&pairBuffer[0],0,length*4);
|
||||||
|
memset(&myBuffer[0],0,length*4);
|
||||||
|
// Check for dependant partial
|
||||||
|
if(tibrePair != NULL) {
|
||||||
|
if ((tibrePair->ownerChan == this->ownerChan) && (!tibrePair->alreadyOutputed)) {
|
||||||
|
tibrePair->generateSamples(pairBuffer,length);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if((useMix!=0) && (useMix != 3)){
|
||||||
|
// Generate noise for parialless ring mix
|
||||||
|
for(i=0;i<length;i++) pairBuffer[i] = smallnoise[i] << 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
generateSamples(myBuffer, length);
|
||||||
|
/* FILE *fo = fopen("/tmp/samp.raw", "a");
|
||||||
|
for(i = 0; i < length; i++)
|
||||||
|
fwrite(myBuffer + i, 1, 2, fo);
|
||||||
|
fclose(fo);
|
||||||
|
*/
|
||||||
|
Bit16s * p1buf, * p2buf;
|
||||||
|
|
||||||
|
if((partNum==0) || ((partNum==1) && (tibrePair==NULL))) {
|
||||||
|
p1buf = &myBuffer[0];
|
||||||
|
p2buf = &pairBuffer[0];
|
||||||
|
} else {
|
||||||
|
p2buf = &myBuffer[0];
|
||||||
|
p1buf = &pairBuffer[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOG_MSG("useMix: %d", useMix);
|
||||||
|
|
||||||
|
switch(useMix) {
|
||||||
|
case 0:
|
||||||
|
// Standard sound mix
|
||||||
|
mixBuffers(p1buf, p2buf, length);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
// Ring modulation with sound mix
|
||||||
|
mixBuffersRingMix(p1buf, p2buf, length);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
// Ring modulation alone
|
||||||
|
mixBuffersRing(p1buf, p2buf, length);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
// Stereo mixing. One partial to one channel, one to another.
|
||||||
|
mixBuffersStereo(p1buf, p2buf, partialBuf, length);
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mixBuffers(p1buf, p2buf, length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int m;
|
||||||
|
m = 0;
|
||||||
|
Bit16s leftvol, rightvol;
|
||||||
|
if (!tmppoly->isRy) {
|
||||||
|
leftvol = tmppoly->pansetptr->leftvol;
|
||||||
|
rightvol = tmppoly->pansetptr->rightvol;
|
||||||
|
} else {
|
||||||
|
leftvol = (Bit16s)drumPan[tmppoly->pcmnum][0];
|
||||||
|
rightvol = (Bit16s)drumPan[tmppoly->pcmnum][1];
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_MMX == 0
|
||||||
|
for(i=0;i<length;i++) {
|
||||||
|
partialBuf[m] = (Bit16s)(((Bit32s)p1buf[i] * (Bit32s)leftvol) >> 16);
|
||||||
|
m++;
|
||||||
|
partialBuf[m] = (Bit16s)(((Bit32s)p1buf[i] * (Bit32s)rightvol) >> 16);
|
||||||
|
m++;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
long quadlen = (length >> 1)+2;
|
||||||
|
#ifdef I_ASM
|
||||||
|
__asm {
|
||||||
|
mov ecx,quadlen
|
||||||
|
mov ax, leftvol
|
||||||
|
shl eax,16
|
||||||
|
mov ax, rightvol
|
||||||
|
movd mm1, eax
|
||||||
|
movd mm2, eax
|
||||||
|
psllq mm1, 32
|
||||||
|
por mm1, mm2
|
||||||
|
mov edi, partialBuf
|
||||||
|
mov esi, p1buf
|
||||||
|
mmxloop1:
|
||||||
|
mov bx, [esi]
|
||||||
|
add esi,2
|
||||||
|
mov dx, [esi]
|
||||||
|
add esi,2
|
||||||
|
|
||||||
|
mov ax, dx
|
||||||
|
shl eax, 16
|
||||||
|
mov ax, dx
|
||||||
|
movd mm2,eax
|
||||||
|
psllq mm2, 32
|
||||||
|
mov ax, bx
|
||||||
|
shl eax, 16
|
||||||
|
mov ax, bx
|
||||||
|
movd mm3,eax
|
||||||
|
por mm2,mm3
|
||||||
|
|
||||||
|
pmulhw mm2, mm1
|
||||||
|
movq [edi], mm2
|
||||||
|
add edi, 8
|
||||||
|
|
||||||
|
dec ecx
|
||||||
|
cmp ecx,0
|
||||||
|
jg mmxloop1
|
||||||
|
emms
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
atti386_PartProductOutput(quadlen, leftvol, rightvol, partialBuf, p1buf);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
115
backends/midi/mt32/partial.h
Normal file
115
backends/midi/mt32/partial.h
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2004 The ScummVM project
|
||||||
|
* Based on Tristan's conversion of Canadacow's code
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it 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 program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CPARTIALMT32_H__
|
||||||
|
#define __CPARTIALMT32_H__
|
||||||
|
|
||||||
|
#include "backends/midi/mt32/structures.h"
|
||||||
|
|
||||||
|
// Class definition of MT-32 partials. 32 in all.
|
||||||
|
class CPartialMT32 {
|
||||||
|
private:
|
||||||
|
int useMix;
|
||||||
|
int partNum;
|
||||||
|
|
||||||
|
int pN;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Bit16s myBuffer[2048];
|
||||||
|
// For temporary output of paired buffer
|
||||||
|
Bit16s pairBuffer[2048];
|
||||||
|
|
||||||
|
void mixBuffers(Bit16s * buf1, Bit16s * buf2, int len);
|
||||||
|
void mixBuffersRingMix(Bit16s * buf1, Bit16s * buf2, int len);
|
||||||
|
void mixBuffersRing(Bit16s * buf1, Bit16s * buf2, int len);
|
||||||
|
void mixBuffersStereo(Bit16s * buf1, Bit16s * buf2, Bit16s * outBuf, int len);
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
patchCache *tcache;
|
||||||
|
patchCache cachebackup[4];
|
||||||
|
|
||||||
|
//FILE *fp;
|
||||||
|
//FILE *fp2;
|
||||||
|
|
||||||
|
dpoly::partialStatus *partCache;
|
||||||
|
|
||||||
|
CPartialMT32 *tibrePair;
|
||||||
|
bool isActive;
|
||||||
|
bool alreadyOutputed;
|
||||||
|
int ownerChan;
|
||||||
|
Bit64s age;
|
||||||
|
int timbreNum;
|
||||||
|
dpoly *tmppoly;
|
||||||
|
|
||||||
|
CPartialMT32(int partialNum) {
|
||||||
|
|
||||||
|
isActive = false;
|
||||||
|
pN = partialNum;
|
||||||
|
|
||||||
|
/*
|
||||||
|
sprintf(buffer, "partial%d.raw",pN);
|
||||||
|
fp = fopen(buffer,"wb");
|
||||||
|
|
||||||
|
sprintf(buffer, "partial%dx.raw",pN);
|
||||||
|
fp2 = fopen(buffer,"wb");
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
void startPartial(dpoly *usePoly, patchCache *useCache, dpoly::partialStatus * usePart, CPartialMT32 * pairPart, int mixType, int num, int ownChan, int timNum) {
|
||||||
|
|
||||||
|
//LOG_MSG("Starting partial %d for %d", num, ownChan);
|
||||||
|
tmppoly = usePoly;
|
||||||
|
tcache = useCache;
|
||||||
|
partCache = usePart;
|
||||||
|
tibrePair = pairPart;
|
||||||
|
isActive = true;
|
||||||
|
useMix = mixType;
|
||||||
|
partNum = num;
|
||||||
|
age = 0;
|
||||||
|
ownerChan = ownChan;
|
||||||
|
alreadyOutputed = false;
|
||||||
|
timbreNum = timNum;
|
||||||
|
memset(usePart->history,0,sizeof(usePart->history));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopPartial(void) { isActive = false; }
|
||||||
|
|
||||||
|
|
||||||
|
// Returns true only if data written to buffer
|
||||||
|
// This function (unline the one below it) returns processed stereo samples
|
||||||
|
// made from combining this single partial with its pair, if it has one.
|
||||||
|
bool produceOutput(Bit16s * partialBuf, long length);
|
||||||
|
|
||||||
|
// This function produces mono sample output of the specific partial
|
||||||
|
void generateSamples(Bit16s * partialBuf, long length);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
780
backends/midi/mt32/structures.h
Normal file
780
backends/midi/mt32/structures.h
Normal file
@ -0,0 +1,780 @@
|
|||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2004 The ScummVM project
|
||||||
|
* Based on Tristan's conversion of Canadacow's code
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it 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 program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined __MT32STRUCTURES_H__
|
||||||
|
#define __MT32STRUCTURES_H__
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "common/scummsys.h"
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
typedef unsigned __int64 Bit64u;
|
||||||
|
typedef signed __int64 Bit64s;
|
||||||
|
#else
|
||||||
|
typedef unsigned long long Bit64u;
|
||||||
|
typedef signed long long Bit64s;
|
||||||
|
#endif
|
||||||
|
typedef unsigned int Bit32u;
|
||||||
|
typedef signed int Bit32s;
|
||||||
|
typedef unsigned short int Bit16u;
|
||||||
|
typedef signed short int Bit16s;
|
||||||
|
typedef unsigned char Bit8u;
|
||||||
|
typedef signed char Bit8s;
|
||||||
|
|
||||||
|
// The occurences of __int64 should be changed to Bit64s
|
||||||
|
#define __int64 Bit64u
|
||||||
|
|
||||||
|
#define INLINE
|
||||||
|
|
||||||
|
|
||||||
|
static inline void LOG_MSG(char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(stdout, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(WIN32) && !(defined(__CYGWIN__) || defined(__MINGW__))
|
||||||
|
|
||||||
|
#define ALIGN_PACKED
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
//#define ALIGN_PACKED __attribute__ ((__packed__))
|
||||||
|
#define ALIGN_PACKED __attribute__ ((aligned (1)))
|
||||||
|
|
||||||
|
#ifdef HAVE_X86
|
||||||
|
#define eflag(value) __asm__ __volatile__("pushfl \n popfl \n" : : "a"(value))
|
||||||
|
#define cpuid_flag (1 << 21)
|
||||||
|
|
||||||
|
static inline bool atti386_DetectCPUID()
|
||||||
|
{
|
||||||
|
unsigned int result;
|
||||||
|
|
||||||
|
/* is there a cpuid */
|
||||||
|
result = cpuid_flag; /* set test */
|
||||||
|
eflag(result);
|
||||||
|
if (!(result & cpuid_flag))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
result = 0; /* clear test */
|
||||||
|
eflag(result);
|
||||||
|
if (result & cpuid_flag)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool atti386_DetectSIMD()
|
||||||
|
{
|
||||||
|
unsigned int result;
|
||||||
|
|
||||||
|
if (atti386_DetectCPUID() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* check cpuid */
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"movl $1, %%eax \n" \
|
||||||
|
"cpuid \n" \
|
||||||
|
"movl %%edx, %0 \n" \
|
||||||
|
: "=r"(result) : : "eax", "ebx", "ecx", "edx");
|
||||||
|
|
||||||
|
if (result & (1 << 25))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool atti386_Detect3DNow()
|
||||||
|
{
|
||||||
|
unsigned int result;
|
||||||
|
|
||||||
|
if (atti386_DetectCPUID() == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* get cpuid */
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"movl $0x80000001, %%eax \n" \
|
||||||
|
"cpuid \n" \
|
||||||
|
"movl %%edx, %0 \n" \
|
||||||
|
: "=r"(result) : : "eax", "ebx", "ecx", "edx");
|
||||||
|
|
||||||
|
if (result & 0x80000000)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline float atti386_iir_filter_sse(float *output, float *hist1_ptr, float *coef_ptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
"pushl %1 \n" \
|
||||||
|
"pushl %2 \n" \
|
||||||
|
"movss 0(%0), %%xmm1 \n" \
|
||||||
|
"movups 0(%1), %%xmm2 \n" \
|
||||||
|
"movlps 0(%2), %%xmm3 \n" \
|
||||||
|
" \n" \
|
||||||
|
"shufps $0x44, %%xmm3, %%xmm3 \n" \
|
||||||
|
" \n" \
|
||||||
|
"mulps %%xmm3, %%xmm2 \n" \
|
||||||
|
" \n" \
|
||||||
|
"subss %%xmm2, %%xmm1 \n" \
|
||||||
|
"shufps $0x39, %%xmm2, %%xmm2 \n" \
|
||||||
|
"subss %%xmm2, %%xmm1 \n" \
|
||||||
|
" \n" \
|
||||||
|
"movss %%xmm1, 0(%2) \n" \
|
||||||
|
" \n" \
|
||||||
|
"shufps $0x39, %%xmm2, %%xmm2 \n" \
|
||||||
|
"addss %%xmm2, %%xmm1 \n" \
|
||||||
|
" \n" \
|
||||||
|
"shufps $0x39, %%xmm2, %%xmm2 \n" \
|
||||||
|
"addss %%xmm2, %%xmm1 \n" \
|
||||||
|
" \n" \
|
||||||
|
"movss %%xmm3, 4(%2) \n" \
|
||||||
|
" \n" \
|
||||||
|
"addl $16, %1 \n" \
|
||||||
|
"addl $8, %2 \n" \
|
||||||
|
" \n" \
|
||||||
|
"movups 0(%1), %%xmm2 \n" \
|
||||||
|
" \n" \
|
||||||
|
"movlps 0(%2), %%xmm3 \n" \
|
||||||
|
"shufps $0x44, %%xmm3, %%xmm3 \n" \
|
||||||
|
" \n" \
|
||||||
|
"mulps %%xmm3, %%xmm2 \n" \
|
||||||
|
" \n" \
|
||||||
|
"subss %%xmm2, %%xmm1 \n" \
|
||||||
|
"shufps $0x39, %%xmm2, %%xmm2 \n" \
|
||||||
|
"subss %%xmm2, %%xmm1 \n" \
|
||||||
|
" \n" \
|
||||||
|
"movss %%xmm1, 0(%2) \n" \
|
||||||
|
" \n" \
|
||||||
|
"shufps $0x39, %%xmm2, %%xmm2 \n" \
|
||||||
|
"addss %%xmm2, %%xmm1 \n" \
|
||||||
|
" \n" \
|
||||||
|
"shufps $0x39, %%xmm2, %%xmm2 \n" \
|
||||||
|
"addss %%xmm2, %%xmm1 \n" \
|
||||||
|
" \n" \
|
||||||
|
"movss %%xmm3, 4(%2) \n" \
|
||||||
|
"movss %%xmm1, 0(%0) \n" \
|
||||||
|
"popl %2 \n" \
|
||||||
|
"popl %1 \n" \
|
||||||
|
: : "r"(output), "r"(coef_ptr), "r"(hist1_ptr)
|
||||||
|
: "xmm1", "xmm2", "xmm3", "memory");
|
||||||
|
|
||||||
|
return(*output);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float atti386_iir_filter_3DNow(float output, float *hist1_ptr, float *coef_ptr)
|
||||||
|
{
|
||||||
|
float tmp;
|
||||||
|
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
"movq %0, %%mm1 \n" \
|
||||||
|
" \n" \
|
||||||
|
"movl %1, %%ebx \n" \
|
||||||
|
"movq 0(%%ebx), %%mm2 \n" \
|
||||||
|
" \n" \
|
||||||
|
"movl %2, %%eax; \n" \
|
||||||
|
"movq 0(%%eax), %%mm3 \n" \
|
||||||
|
" \n" \
|
||||||
|
"pfmul %%mm3, %%mm2 \n" \
|
||||||
|
"pfsub %%mm2, %%mm1 \n" \
|
||||||
|
" \n" \
|
||||||
|
"psrlq $32, %%mm2 \n" \
|
||||||
|
"pfsub %%mm2, %%mm1 \n" \
|
||||||
|
" \n" \
|
||||||
|
"movd %%mm1, %3 \n" \
|
||||||
|
" \n" \
|
||||||
|
"addl $8, %%ebx \n" \
|
||||||
|
"movq 0(%%ebx), %%mm2 \n" \
|
||||||
|
"movq 0(%%eax), %%mm3 \n" \
|
||||||
|
" \n" \
|
||||||
|
"pfmul %%mm3, %%mm2 \n" \
|
||||||
|
"pfadd %%mm2, %%mm1 \n" \
|
||||||
|
" \n" \
|
||||||
|
"psrlq $32, %%mm2 \n" \
|
||||||
|
"pfadd %%mm2, %%mm1 \n" \
|
||||||
|
" \n" \
|
||||||
|
"pushl %3 \n" \
|
||||||
|
"popl 0(%%eax) \n" \
|
||||||
|
" \n" \
|
||||||
|
"movd %%mm3, 4(%%eax) \n" \
|
||||||
|
" \n" \
|
||||||
|
"addl $8, %%ebx \n" \
|
||||||
|
"addl $8, %%eax \n" \
|
||||||
|
" \n" \
|
||||||
|
"movq 0(%%ebx), %%mm2 \n" \
|
||||||
|
"movq 0(%%eax), %%mm3 \n" \
|
||||||
|
" \n" \
|
||||||
|
"pfmul %%mm3, %%mm2 \n" \
|
||||||
|
"pfsub %%mm2, %%mm1 \n" \
|
||||||
|
" \n" \
|
||||||
|
"psrlq $32, %%mm2 \n" \
|
||||||
|
"pfsub %%mm2, %%mm1 \n" \
|
||||||
|
" \n" \
|
||||||
|
"movd %%mm1, %3 \n" \
|
||||||
|
" \n" \
|
||||||
|
"addl $8, %%ebx \n" \
|
||||||
|
"movq 0(%%ebx), %%mm2 \n" \
|
||||||
|
"movq 0(%%eax), %%mm3 \n" \
|
||||||
|
" \n" \
|
||||||
|
"pfmul %%mm3, %%mm2 \n" \
|
||||||
|
"pfadd %%mm2, %%mm1 \n" \
|
||||||
|
" \n" \
|
||||||
|
"psrlq $32, %%mm2 \n" \
|
||||||
|
"pfadd %%mm2, %%mm1 \n" \
|
||||||
|
" \n" \
|
||||||
|
"pushl %3 \n" \
|
||||||
|
"popl 0(%%eax) \n" \
|
||||||
|
"movd %%mm3, 4(%%eax) \n" \
|
||||||
|
" \n" \
|
||||||
|
"movd %%mm1, %0 \n" \
|
||||||
|
"femms \n" \
|
||||||
|
: "=m"(output) : "g"(coef_ptr), "g"(hist1_ptr), "m"(tmp)
|
||||||
|
: "eax", "ebx", "mm1", "mm2", "mm3", "memory");
|
||||||
|
|
||||||
|
return(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float atti386_iir_filter_3dnow(float input,float *hist1_ptr, float *coef_ptr, int revLevel)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void atti386_produceOutput1(int tmplen, Bit16s myvolume, Bit16s *useBuf, Bit16s *snd)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"movl %0, %%ecx \n" \
|
||||||
|
"movw %1, %%ax \n" \
|
||||||
|
"shll $16, %%eax \n" \
|
||||||
|
"movw %1, %%ax \n" \
|
||||||
|
"movd %%eax, %%mm3 \n" \
|
||||||
|
"movd %%eax, %%mm2 \n" \
|
||||||
|
"psllq $32, %%mm3 \n" \
|
||||||
|
"por %%mm2, %%mm3 \n" \
|
||||||
|
"movl %2, %%esi \n" \
|
||||||
|
"movl %3, %%edi \n" \
|
||||||
|
"1: \n" \
|
||||||
|
"movq 0(%%esi), %%mm1 \n" \
|
||||||
|
"movq 0(%%edi), %%mm2 \n" \
|
||||||
|
"pmulhw %%mm3, %%mm1 \n" \
|
||||||
|
"paddw %%mm2, %%mm1 \n" \
|
||||||
|
"movq %%mm1, 0(%%edi) \n" \
|
||||||
|
" \n" \
|
||||||
|
"addl $8, %%esi \n" \
|
||||||
|
"addl $8, %%edi \n" \
|
||||||
|
" \n" \
|
||||||
|
"decl %%ecx \n" \
|
||||||
|
"cmpl $0, %%ecx \n" \
|
||||||
|
"jg 1b \n" \
|
||||||
|
"emms \n" \
|
||||||
|
: : "g"(tmplen), "g"(myvolume), "g"(useBuf), "g"(snd)
|
||||||
|
: "eax", "ecx", "edi", "esi", "mm1", "mm2", "mm3", "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: This is buggy
|
||||||
|
static inline void atti386_produceOutput2(Bit32u len, Bit16s *snd, float *sndbufl, float *sndbufr, float *multFactor)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"movl %4, %%ecx \n" \
|
||||||
|
"shrl $1, %%ecx \n" \
|
||||||
|
"addl $4, %%ecx \n" \
|
||||||
|
"pushl %%ecx \n" \
|
||||||
|
" \n" \
|
||||||
|
"movl %0, %%esi \n" \
|
||||||
|
"movups 0(%%esi), %%xmm1 \n" \
|
||||||
|
" \n" \
|
||||||
|
"movl %1, %%esi \n" \
|
||||||
|
"movl %2, %%edi \n" \
|
||||||
|
"1: \n" \
|
||||||
|
"xorl %%eax, %%eax \n" \
|
||||||
|
"movw 0(%1), %%ax \n" \
|
||||||
|
"cwde \n" \
|
||||||
|
"incl %1 \n" \
|
||||||
|
"incl %1 \n" \
|
||||||
|
"movd %%eax, %%mm1 \n" \
|
||||||
|
"psrlq $32, %%mm1 \n" \
|
||||||
|
"movw 0(%1), %%ax \n" \
|
||||||
|
"incl %1 \n" \
|
||||||
|
"incl %1 \n" \
|
||||||
|
"movd %%eax, %%mm2 \n" \
|
||||||
|
"por %%mm2, %%mm1 \n" \
|
||||||
|
" \n" \
|
||||||
|
"decl %%ecx \n" \
|
||||||
|
"jnz 1b \n" \
|
||||||
|
" \n" \
|
||||||
|
"popl %%ecx \n" \
|
||||||
|
"movl %1, %%esi \n" \
|
||||||
|
"movl %3, %%edi \n" \
|
||||||
|
"incl %%esi \n" \
|
||||||
|
"2: \n" \
|
||||||
|
"decl %%ecx \n" \
|
||||||
|
"jnz 2b \n" \
|
||||||
|
: : "g"(multFactor), "r"(snd), "g"(sndbufl), "g"(sndbufr), "g"(len)
|
||||||
|
: "eax", "ecx", "edi", "esi", "mm1", "mm2", "xmm1", "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void atti386_mixBuffers(Bit16s * buf1, Bit16s *buf2, int len)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"movl %0, %%ecx \n" \
|
||||||
|
"movl %1, %%esi \n" \
|
||||||
|
"movl %2, %%edi \n" \
|
||||||
|
"1: \n" \
|
||||||
|
"movq 0(%%edi), %%mm1 \n" \
|
||||||
|
"movq 0(%%esi), %%mm2 \n" \
|
||||||
|
"paddw %%mm2, %%mm1 \n" \
|
||||||
|
"movq %%mm1, 0(%%esi) \n" \
|
||||||
|
"addl $8, %%edi \n" \
|
||||||
|
"addl $8, %%esi \n" \
|
||||||
|
"decl %%ecx \n" \
|
||||||
|
"cmpl $0, %%ecx \n" \
|
||||||
|
"jg 1b \n" \
|
||||||
|
"emms \n" \
|
||||||
|
: : "g"(len), "g"(buf1), "g"(buf2)
|
||||||
|
: "ecx", "edi", "esi", "mm1", "mm2", "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void atti386_mixBuffersRingMix(Bit16s * buf1, Bit16s *buf2, int len)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"movl %0, %%ecx \n" \
|
||||||
|
"movl %1, %%esi \n" \
|
||||||
|
"movl %2, %%edi \n" \
|
||||||
|
"1: \n" \
|
||||||
|
"movq 0(%%esi), %%mm1 \n" \
|
||||||
|
"movq 0(%%edi), %%mm2 \n" \
|
||||||
|
"movq %%mm1, %%mm3 \n" \
|
||||||
|
"pmulhw %%mm2, %%mm1 \n" \
|
||||||
|
"paddw %%mm3, %%mm1 \n" \
|
||||||
|
"movq %%mm1, 0(%%esi) \n" \
|
||||||
|
"addl $8, %%edi \n" \
|
||||||
|
"addl $8, %%esi \n" \
|
||||||
|
"decl %%ecx \n" \
|
||||||
|
"cmpl $0, %%ecx \n" \
|
||||||
|
"jg 1b \n" \
|
||||||
|
"emms \n" \
|
||||||
|
: : "g"(len), "g"(buf1), "g"(buf2)
|
||||||
|
: "ecx", "edi", "esi", "mm1", "mm2", "mm3", "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void atti386_mixBuffersRing(Bit16s * buf1, Bit16s *buf2, int len)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"movl %0, %%ecx \n" \
|
||||||
|
"movl %1, %%esi \n" \
|
||||||
|
"movl %2, %%edi \n" \
|
||||||
|
"1: \n" \
|
||||||
|
"movq 0(%%esi), %%mm1 \n" \
|
||||||
|
"movq 0(%%edi), %%mm2 \n" \
|
||||||
|
"pmulhw %%mm2, %%mm1 \n" \
|
||||||
|
"movq %%mm1, 0(%%esi) \n" \
|
||||||
|
"addl $8, %%edi \n" \
|
||||||
|
"addl $8, %%esi \n" \
|
||||||
|
"decl %%ecx \n" \
|
||||||
|
"cmpl $0, %%ecx \n" \
|
||||||
|
"jg 1b \n" \
|
||||||
|
"emms \n" \
|
||||||
|
: : "g"(len), "g"(buf1), "g"(buf2)
|
||||||
|
: "ecx", "edi", "esi", "mm1", "mm2", "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void atti386_PartProductOutput(int quadlen, Bit16s leftvol, Bit16s rightvol,
|
||||||
|
Bit16s *partialBuf, Bit16s *p1buf)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"movl %0, %%ecx \n" \
|
||||||
|
"movw %1, %%ax \n" \
|
||||||
|
"shll $16, %%eax \n" \
|
||||||
|
"movw %2, %%ax \n" \
|
||||||
|
"movd %%eax, %%mm1 \n" \
|
||||||
|
"movd %%eax, %%mm2 \n" \
|
||||||
|
"psllq $32, %%mm1 \n" \
|
||||||
|
"por %%mm2, %%mm1 \n" \
|
||||||
|
"movl %3, %%edi \n" \
|
||||||
|
"movl %4, %%esi \n" \
|
||||||
|
"1: \n" \
|
||||||
|
"movw 0(%%esi), %%bx \n" \
|
||||||
|
"addl $2, %%esi \n" \
|
||||||
|
"movw 0(%%esi), %%dx \n" \
|
||||||
|
"addl $2, %%esi \n" \
|
||||||
|
"" \
|
||||||
|
"movw %%dx, %%ax \n" \
|
||||||
|
"shll $16, %%eax \n" \
|
||||||
|
"movw %%dx, %%ax \n" \
|
||||||
|
"movd %%eax, %%mm2 \n" \
|
||||||
|
"psllq $32, %%mm2 \n" \
|
||||||
|
"movw %%bx, %%ax \n" \
|
||||||
|
"shll $16, %%eax \n" \
|
||||||
|
"movw %%bx, %%ax \n" \
|
||||||
|
"movd %%eax, %%mm3 \n" \
|
||||||
|
"por %%mm3, %%mm2 \n" \
|
||||||
|
"" \
|
||||||
|
"pmulhw %%mm1, %%mm2 \n" \
|
||||||
|
"movq %%mm2, 0(%%edi) \n" \
|
||||||
|
"addl $8, %%edi \n" \
|
||||||
|
"" \
|
||||||
|
"decl %%ecx \n" \
|
||||||
|
"cmpl $0, %%ecx \n" \
|
||||||
|
"jg 1b \n" \
|
||||||
|
"emms \n" \
|
||||||
|
: :"g"(quadlen), "g"(leftvol), "g"(rightvol), "g"(partialBuf), "g"(p1buf)
|
||||||
|
: "eax", "ebx", "ecx", "edx", "edi", "esi", "mm1", "mm2", "mm3", "memory");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern bool enabled3DNow;
|
||||||
|
extern bool enabledSSE;
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
struct timbreParam {
|
||||||
|
struct commonParam {
|
||||||
|
char name[10];
|
||||||
|
char pstruct12; // 1&2 0-12 (1-13)
|
||||||
|
char pstruct34; // #3&4 0-12 (1-13)
|
||||||
|
char pmute; // 0-15 (0000-1111)
|
||||||
|
char nosustain; // 0-1(Normal, No sustain)
|
||||||
|
} ALIGN_PACKED common;
|
||||||
|
|
||||||
|
struct partialParam {
|
||||||
|
struct wgParam {
|
||||||
|
char coarse; // 0-96 (C1,C#1-C9)
|
||||||
|
char fine; // 0-100 (-50 - +50)
|
||||||
|
char keyfollow; // 0-16 (-1,-1/2,0,1,1/8,1/4,3/8,1/2,5/8,3/4,7/8,1,5/4,3/2,2.s1,s2)
|
||||||
|
char bender; // 0,1 (ON/OFF)
|
||||||
|
char waveform; // 0-1 (SQU/SAW)
|
||||||
|
char pcmwave; // 0-127 (1-128)
|
||||||
|
char pulsewid; // 0-100
|
||||||
|
char pwvelo; // 0-14 (-7 - +7)
|
||||||
|
} ALIGN_PACKED wg;
|
||||||
|
|
||||||
|
struct envParam {
|
||||||
|
char depth; // 0-10
|
||||||
|
char sensitivity; // 1-100
|
||||||
|
char timekeyfollow; // 0-4
|
||||||
|
char time[4]; // 1-100
|
||||||
|
char level[5]; // 1-100 (-50 - +50)
|
||||||
|
} ALIGN_PACKED env;
|
||||||
|
|
||||||
|
struct lfoParam {
|
||||||
|
char rate; // 0-100
|
||||||
|
char depth; // 0-100
|
||||||
|
char modsense; // 0-100
|
||||||
|
} ALIGN_PACKED lfo;
|
||||||
|
|
||||||
|
struct tvfParam {
|
||||||
|
char cutoff; // 0-100
|
||||||
|
char resonance; // 0-30
|
||||||
|
char keyfollow; // 0-16 (-1,-1/2,1/4,0,1,1/8,1/4,3/8,1/2,5/8,3/2,7/8,1,5/4,3/2,2,s1,s2)
|
||||||
|
char biaspoint; // 0-127 (<1A-<7C >1A-7C)
|
||||||
|
char biaslevel; // 0-14 (-7 - +7)
|
||||||
|
char envdepth; // 0-100
|
||||||
|
char envsense; // 0-100
|
||||||
|
char envdkf; // DEPTH KEY FOLL0W 0-4
|
||||||
|
char envtkf; // TIME KEY FOLLOW 0-4
|
||||||
|
char envtime[5]; // 1-100
|
||||||
|
char envlevel[4]; // 1-100
|
||||||
|
} ALIGN_PACKED tvf;
|
||||||
|
|
||||||
|
struct tvaParam {
|
||||||
|
char level; // 0-100
|
||||||
|
char velosens; // 0-100
|
||||||
|
char biaspoint1; // 0-127 (<1A-<7C >1A-7C)
|
||||||
|
char biaslevel1; // 0-12 (-12 - 0)
|
||||||
|
char biaspoint2; // 0-127 (<1A-<7C >1A-7C)
|
||||||
|
char biaslevel2; // 0-12 (-12 - 0)
|
||||||
|
char envtkf; // TIME KEY FOLLOW 0-4
|
||||||
|
char envvkf; // VELOS KEY FOLL0W 0-4
|
||||||
|
char envtime[5]; // 1-100
|
||||||
|
char envlevel[4]; // 1-100
|
||||||
|
} ALIGN_PACKED tva;
|
||||||
|
|
||||||
|
} ALIGN_PACKED partial[4];
|
||||||
|
//char dummy[20];
|
||||||
|
} ALIGN_PACKED;
|
||||||
|
|
||||||
|
struct memParams {
|
||||||
|
struct patchTemp {
|
||||||
|
char timbreGroup; // TIMBRE GROUP 0-3 (group A, group B, Memory, Rhythm)
|
||||||
|
char timbreNum; // TIMBRE NUMBER 0-63
|
||||||
|
char keyShift; // KEY SHIFT 0-48 (-24 - +24)
|
||||||
|
char fineTune; // FINE TUNE 0-100 (-50 - +50)
|
||||||
|
char benderRange; // BENDER RANGE 0-24
|
||||||
|
char assignMode; // ASSIGN MODE 0-3 (POLY1, POLY2, POLY3, POLY4)
|
||||||
|
char reverbSwitch; // REVERB SWITCH 0-1 (OFF,ON)
|
||||||
|
char dummy; // (DUMMY)
|
||||||
|
char outlevel; // OUTPUT LEVEL 0-100
|
||||||
|
char panpot; // PANPOT 0-14 (R-L)
|
||||||
|
char dummyv[6];
|
||||||
|
} ALIGN_PACKED tmpSettings[8];
|
||||||
|
struct ryhTemp {
|
||||||
|
char timbre; // TIMBRE 0-94 (M1-M64,R1-30,OFF)
|
||||||
|
char outlevel; // OUTPUT LEVEL 0-100
|
||||||
|
char panpot; // PANPOT 0-14 (R-L)
|
||||||
|
char reverbSwitch; // REVERB SWITCH 0-1 (OFF,ON)
|
||||||
|
} ALIGN_PACKED rhySettings[64];
|
||||||
|
|
||||||
|
timbreParam timTemp[8];
|
||||||
|
|
||||||
|
struct patchArea {
|
||||||
|
char timbreGroup; // TIMBRE GROUP 0-3 (group A, group B, Memory, Rhythm)
|
||||||
|
char timbreNum; // TIMBRE NUMBER 0-63
|
||||||
|
char keyShift; // KEY SHIFT 0-48 (-24 - +24)
|
||||||
|
char fineTune; // FINE TUNE 0-100 (-50 - +50)
|
||||||
|
char benderRange; // BENDER RANGE 0-24
|
||||||
|
char assignMode; // ASSIGN MODE 0-3 (POLY1, POLY2, POLY3, POLY4)
|
||||||
|
char reverbSwitch; // REVERB SWITCH 0-1 (OFF,ON)
|
||||||
|
char dummy; // (DUMMY)
|
||||||
|
} ALIGN_PACKED pSettings[128];
|
||||||
|
timbreParam patch[192];
|
||||||
|
struct systemArea {
|
||||||
|
char masterTune; // MASTER TUNE 0-127 432.1-457.6Hz
|
||||||
|
char reverbMode; // REVERB MODE 0-3 (room, hall, plate, tap delay)
|
||||||
|
char reverbTime; // REVERB TIME 0-7 (1-8)
|
||||||
|
char reverbLevel; // REVERB LEVEL 0-7 (1-8)
|
||||||
|
char reserveSettings[9]; // PARTIAL RESERVE (PART 1) 0-32
|
||||||
|
char chanAssign[9]; // MIDI CHANNEL (PART1) 0-16 (1-16,OFF)
|
||||||
|
char masterVol; // MASTER VOLUME 0-100
|
||||||
|
} ALIGN_PACKED system;
|
||||||
|
|
||||||
|
} ALIGN_PACKED;
|
||||||
|
|
||||||
|
struct memBanks {
|
||||||
|
char pTemp[8][sizeof(memParams::patchTemp)];
|
||||||
|
char rTemp[64][sizeof(memParams::ryhTemp)];
|
||||||
|
char tTemp[8][sizeof(timbreParam)];
|
||||||
|
char patchmemory[128][sizeof(memParams::patchArea)];
|
||||||
|
char patchbanks[128][sizeof(timbreParam)];
|
||||||
|
char timbrebanks[64][sizeof(timbreParam)];
|
||||||
|
char systemBank[sizeof(memParams::systemArea)];
|
||||||
|
} ALIGN_PACKED;
|
||||||
|
|
||||||
|
struct memAbsolute {
|
||||||
|
char mt32memory[sizeof(memBanks)];
|
||||||
|
} ALIGN_PACKED;
|
||||||
|
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
|
struct partialFormat {
|
||||||
|
Bit32u addr;
|
||||||
|
Bit16u len;
|
||||||
|
bool loop;
|
||||||
|
float tune;
|
||||||
|
Bit32s ampval;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct partialTable {
|
||||||
|
Bit32u addr;
|
||||||
|
Bit32u len;
|
||||||
|
Bit32u pcmnum;
|
||||||
|
Bit32s ampval;
|
||||||
|
bool loop;
|
||||||
|
Bit32s aggSound; // This variable is for the last 9 PCM samples, which are actually loop combinations
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
union soundaddr {
|
||||||
|
Bit32u pcmabs;
|
||||||
|
struct offsets {
|
||||||
|
#if defined(SCUMM_LITTLE_ENDIAN)
|
||||||
|
Bit16u pcmoffset;
|
||||||
|
Bit16u pcmplace;
|
||||||
|
#else
|
||||||
|
Bit16u pcmplace;
|
||||||
|
Bit16u pcmoffset;
|
||||||
|
#endif
|
||||||
|
} pcmoffs;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct volset {
|
||||||
|
Bit16s leftvol;
|
||||||
|
Bit16s rightvol;
|
||||||
|
Bit16s leftvol2;
|
||||||
|
Bit16s rightvol2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct patchCache {
|
||||||
|
int rawPCM;
|
||||||
|
partialTable convPCM;
|
||||||
|
|
||||||
|
bool playPartial;
|
||||||
|
bool usePartial;
|
||||||
|
bool PCMPartial;
|
||||||
|
char waveform;
|
||||||
|
int pulsewidth;
|
||||||
|
int pwsens;
|
||||||
|
int pitchshift;
|
||||||
|
int fineshift;
|
||||||
|
bool sustain;
|
||||||
|
|
||||||
|
int lfodepth;
|
||||||
|
int lforate;
|
||||||
|
Bit32u lfoperiod;
|
||||||
|
int modsense;
|
||||||
|
|
||||||
|
int keydir;
|
||||||
|
int pitchkeyfollow;
|
||||||
|
int pitchkeydir;
|
||||||
|
|
||||||
|
int filtkeyfollow;
|
||||||
|
|
||||||
|
int tvfbias;
|
||||||
|
int tvfblevel;
|
||||||
|
int tvfdir;
|
||||||
|
|
||||||
|
int ampbias[2];
|
||||||
|
int ampblevel[2];
|
||||||
|
int ampdir[2];
|
||||||
|
|
||||||
|
int ampdepth;
|
||||||
|
int ampenvdir;
|
||||||
|
int amplevel;
|
||||||
|
int tvfdepth;
|
||||||
|
|
||||||
|
int prevsample;
|
||||||
|
|
||||||
|
bool useBender;
|
||||||
|
|
||||||
|
timbreParam::partialParam::envParam pitchEnv;
|
||||||
|
timbreParam::partialParam::tvaParam ampEnv;
|
||||||
|
timbreParam::partialParam::tvfParam filtEnv;
|
||||||
|
|
||||||
|
Bit32s ampsustain;
|
||||||
|
Bit32s pitchsustain;
|
||||||
|
Bit32s filtsustain;
|
||||||
|
|
||||||
|
Bit32u partCount;
|
||||||
|
|
||||||
|
Bit8u padding[64]; //Used to pad the patch cache to 4096 bytes. This replaces an imul with a shl 12
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dpoly {
|
||||||
|
bool isPlaying;
|
||||||
|
bool isDecay;
|
||||||
|
bool isActive;
|
||||||
|
|
||||||
|
bool partActive[4];
|
||||||
|
|
||||||
|
bool isRy;
|
||||||
|
Bit32u *bendptr;
|
||||||
|
Bit32u drumbend;
|
||||||
|
Bit32s *volumeptr;
|
||||||
|
volset *pansetptr;
|
||||||
|
|
||||||
|
int pcmnum;
|
||||||
|
int freq;
|
||||||
|
int freqnum;
|
||||||
|
int vel;
|
||||||
|
|
||||||
|
Bit32u partCount;
|
||||||
|
|
||||||
|
soundaddr pcmoff;
|
||||||
|
Bit32u pcmdelta;
|
||||||
|
|
||||||
|
|
||||||
|
struct partialStatus {
|
||||||
|
// Note played on keyboard
|
||||||
|
int noteval;
|
||||||
|
// Keyfollowed note values
|
||||||
|
int keyedval;
|
||||||
|
|
||||||
|
// Keyfollowed filter values
|
||||||
|
int realval;
|
||||||
|
int filtval;
|
||||||
|
// Keyfollowed filter w/o table
|
||||||
|
int filtnoval;
|
||||||
|
int pulsewidth;
|
||||||
|
|
||||||
|
struct envstatus {
|
||||||
|
Bit32s envpos;
|
||||||
|
Bit32s envstat;
|
||||||
|
Bit32s envbase;
|
||||||
|
Bit32s envdist;
|
||||||
|
Bit32s envsize;
|
||||||
|
|
||||||
|
bool sustaining;
|
||||||
|
bool decaying;
|
||||||
|
bool notdecayed;
|
||||||
|
Bit32u decay;
|
||||||
|
Bit32s prevlevel;
|
||||||
|
|
||||||
|
Bit32s counter;
|
||||||
|
Bit32s count;
|
||||||
|
|
||||||
|
} envs[4];
|
||||||
|
|
||||||
|
Bit32u lfopos;
|
||||||
|
soundaddr partialOff;
|
||||||
|
soundaddr wgOff;
|
||||||
|
|
||||||
|
Bit32u ampEnvCache;
|
||||||
|
Bit32u pitchEnvCache;
|
||||||
|
|
||||||
|
bool isDecayed;
|
||||||
|
bool PCMDone;
|
||||||
|
|
||||||
|
float history[32];
|
||||||
|
|
||||||
|
float pastfilt;
|
||||||
|
bool pitchsustain;
|
||||||
|
bool playPartial;
|
||||||
|
bool usePartial;
|
||||||
|
|
||||||
|
int looppos;
|
||||||
|
int partNum;
|
||||||
|
|
||||||
|
patchCache *tcache;
|
||||||
|
|
||||||
|
void * myPart;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} pStatus[4];
|
||||||
|
|
||||||
|
|
||||||
|
int chan;
|
||||||
|
|
||||||
|
int origpat;
|
||||||
|
int drumnum;
|
||||||
|
|
||||||
|
int age;
|
||||||
|
|
||||||
|
bool pedalhold;
|
||||||
|
bool firstsamp;
|
||||||
|
|
||||||
|
Bit32u P1Mix;
|
||||||
|
Bit32u P2Mix;
|
||||||
|
bool sustain;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
4564
backends/midi/mt32/synth.cpp
Normal file
4564
backends/midi/mt32/synth.cpp
Normal file
File diff suppressed because it is too large
Load Diff
170
backends/midi/mt32/synth.h
Normal file
170
backends/midi/mt32/synth.h
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
/* ScummVM - Scumm Interpreter
|
||||||
|
* Copyright (C) 2004 The ScummVM project
|
||||||
|
* Based on Tristan's conversion of Canadacow's code
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it 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 program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* $Header$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined __CSYNTHMT32_H__
|
||||||
|
#define __CSYNTHMT32_H__
|
||||||
|
|
||||||
|
#ifdef HAVE_X86
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#define USE_MMX 2
|
||||||
|
#define I_ASM
|
||||||
|
#else
|
||||||
|
#define USE_MMX 0
|
||||||
|
#undef I_ASM
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define USE_MMX 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern const char *rom_path;
|
||||||
|
|
||||||
|
#define AMPENV 0
|
||||||
|
#define FILTENV 1
|
||||||
|
#define PITCHENV 2
|
||||||
|
|
||||||
|
// Filter setting
|
||||||
|
#define FILTER_FLOAT 1
|
||||||
|
#define FILTER_64BIT 0
|
||||||
|
#define FILTER_INT 0
|
||||||
|
|
||||||
|
#define FILTERGRAN 512
|
||||||
|
|
||||||
|
// Amplitude of waveform generator
|
||||||
|
#define WGAMP (7168)
|
||||||
|
//#define WGAMP (8192)
|
||||||
|
|
||||||
|
#include "backends/midi/mt32/structures.h"
|
||||||
|
#include "sound/mixer.h"
|
||||||
|
|
||||||
|
// Function that detects the availablity of SSE SIMD instructions
|
||||||
|
// On non-MSVC compilers it automatically returns FALSE as inline assembly is required
|
||||||
|
bool DetectSIMD();
|
||||||
|
// Function that detects the availablity of 3DNow instructions
|
||||||
|
// On non-MSVC compilers it automatically returns FALSE as inline assembly is required
|
||||||
|
bool Detect3DNow();
|
||||||
|
|
||||||
|
struct SynthProperties {
|
||||||
|
// Sample rate to use in mixing
|
||||||
|
int SampleRate;
|
||||||
|
// Flag to activate reverb. True = use reverb, False = no reverb
|
||||||
|
bool UseReverb;
|
||||||
|
// Flag True to use software set reverb settings, Flag False to set reverb settings in
|
||||||
|
// following parameters
|
||||||
|
bool UseDefault;
|
||||||
|
// When not using the default settings, this specifies one of the 4 reverb types
|
||||||
|
// 1 = Room 2 = Hall 3 = Plate 4 = Tap
|
||||||
|
int RevType;
|
||||||
|
// This specifies the delay time, from 0-7 (not sure of the actual MT-32's measurement)
|
||||||
|
int RevTime;
|
||||||
|
// This specifies the reverb level, from 0-7 (not sure of the actual MT-32's measurement)
|
||||||
|
int RevLevel;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef BOOL
|
||||||
|
#define BOOL bool
|
||||||
|
#endif
|
||||||
|
#ifndef TRUE
|
||||||
|
#define TRUE true
|
||||||
|
#endif
|
||||||
|
#ifndef FALSE
|
||||||
|
#define FALSE false
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// This is the specification of the Callback routine used when calling the RecalcWaveforms
|
||||||
|
// function
|
||||||
|
typedef void (*recalcStatusCallback)(int percDone);
|
||||||
|
|
||||||
|
// This external function recreates the base waveform file (waveforms.raw) using a specifed
|
||||||
|
// sampling rate. The callback routine provides interactivity to let the user know what
|
||||||
|
// percentage is complete in regenerating the waveforms. When a NULL pointer is used as the
|
||||||
|
// callback routine, no status is reported.
|
||||||
|
BOOL RecalcWaveforms(char * baseDir, int sampRate, recalcStatusCallback callBack);
|
||||||
|
|
||||||
|
typedef float (*iir_filter_type)(float input,float *hist1_ptr, float *coef_ptr, int revLevel);
|
||||||
|
extern iir_filter_type usefilter;
|
||||||
|
|
||||||
|
extern partialFormat PCM[54];
|
||||||
|
extern Bit16s romfile[262656];
|
||||||
|
extern Bit32s divtable[256];
|
||||||
|
extern Bit32s smalldivtable[256];
|
||||||
|
extern Bit32u wavtabler[64][256];
|
||||||
|
extern Bit32u looptabler[16][16][256];
|
||||||
|
extern Bit16s sintable[65536];
|
||||||
|
extern Bit32s penvtable[16][128];
|
||||||
|
extern Bit32s pulsetable[101];
|
||||||
|
extern Bit32s pulseoffset[101];
|
||||||
|
extern Bit32s sawtable[128][128];
|
||||||
|
extern float filtcoeff[FILTERGRAN][32][16];
|
||||||
|
extern Bit32u lfoptable[101][128];
|
||||||
|
extern Bit32s ampveltable[128][64];
|
||||||
|
extern Bit32s amptable[129];
|
||||||
|
extern Bit16s smallnoise[441];
|
||||||
|
extern Bit32s samplepos;
|
||||||
|
extern Bit16s* waveforms[4][256];
|
||||||
|
extern Bit32u waveformsize[4][256];
|
||||||
|
extern Bit8s LoopPatterns[16][16];
|
||||||
|
extern int drumPan[30][2];
|
||||||
|
extern float ResonFactor[32];
|
||||||
|
extern float ResonInv[32];
|
||||||
|
|
||||||
|
extern Bit32s getPitchEnvelope(dpoly::partialStatus *pStat, dpoly *poly);
|
||||||
|
extern Bit32s getAmpEnvelope(dpoly::partialStatus *pStat, dpoly *poly);
|
||||||
|
extern Bit32s getFiltEnvelope(Bit16s wg, dpoly::partialStatus *pStat, dpoly *poly);
|
||||||
|
|
||||||
|
class CSynthMT32 {
|
||||||
|
private:
|
||||||
|
|
||||||
|
unsigned char initmode;
|
||||||
|
bool isOpen;
|
||||||
|
SynthProperties myProp;
|
||||||
|
|
||||||
|
bool InitTables(const char * baseDir);
|
||||||
|
|
||||||
|
public:
|
||||||
|
CSynthMT32() : isOpen(false) {};
|
||||||
|
|
||||||
|
// Used to initialized the MT-32. The baseDir parameter points to the location in the
|
||||||
|
// filesystem where the ROM and data files are located. The second parameter specifies
|
||||||
|
// properties for the synthesizer, as outlined in the structure above.
|
||||||
|
// Returns TRUE if initialization was sucessful, otherwise returns FALSE.
|
||||||
|
bool ClassicOpen(const char *baseDir, SynthProperties useProp);
|
||||||
|
|
||||||
|
// Closes the MT-32 and deallocates any memory used by the synthesizer
|
||||||
|
void Close(void);
|
||||||
|
|
||||||
|
// Sends a 4-byte MIDI message to the MT-32 for immediate playback
|
||||||
|
void PlayMsg(Bit32u msg);
|
||||||
|
|
||||||
|
// Sends a string of Sysex commands to the MT-32 for immediate interpretation
|
||||||
|
void PlaySysex(Bit8u * sysex, Bit32u len);
|
||||||
|
|
||||||
|
// Save the system state to a sysex file specified by filename
|
||||||
|
int DumpSysex(char *filename);
|
||||||
|
|
||||||
|
// This callback routine is used to have the MT-32 generate samples to the specified
|
||||||
|
// output stream. The length is in whole samples, not bytes. (I.E. in 16-bit stereo,
|
||||||
|
// one sample is 4 bytes)
|
||||||
|
void MT32_CallBack(Bit8u * stream, Bit32u len, int volume);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -12,14 +12,20 @@ MODULE_OBJS := \
|
|||||||
backends/midi/seq.o \
|
backends/midi/seq.o \
|
||||||
backends/midi/alsa.o \
|
backends/midi/alsa.o \
|
||||||
backends/midi/windows.o \
|
backends/midi/windows.o \
|
||||||
backends/midi/ym2612.o
|
backends/midi/ym2612.o \
|
||||||
|
backends/midi/mt32/mt32.o \
|
||||||
|
backends/midi/mt32/partial.o \
|
||||||
|
backends/midi/mt32/synth.o \
|
||||||
|
backends/midi/mt32/freeverb.o
|
||||||
|
|
||||||
|
|
||||||
MODULE_DIRS += \
|
MODULE_DIRS += \
|
||||||
backends \
|
backends \
|
||||||
backends/fs/posix \
|
backends/fs/posix \
|
||||||
backends/fs/morphos \
|
backends/fs/morphos \
|
||||||
backends/fs/windows \
|
backends/fs/windows \
|
||||||
backends/midi
|
backends/midi \
|
||||||
|
backends/midi/mt32
|
||||||
|
|
||||||
# Include common rules
|
# Include common rules
|
||||||
include $(srcdir)/common.rules
|
include $(srcdir)/common.rules
|
||||||
|
@ -599,6 +599,8 @@ MidiDriver *GameDetector::createMidi(int midiDriver) {
|
|||||||
// driver.
|
// driver.
|
||||||
case MD_ADLIB: return NULL;
|
case MD_ADLIB: return NULL;
|
||||||
|
|
||||||
|
case MD_MT32: return MidiDriver_MT32_create(g_engine->_mixer, ConfMan.get("extrapath").c_str());
|
||||||
|
|
||||||
case MD_TOWNS: return MidiDriver_YM2612_create(g_engine->_mixer);
|
case MD_TOWNS: return MidiDriver_YM2612_create(g_engine->_mixer);
|
||||||
|
|
||||||
// Right now PC Speaker and PCjr are handled
|
// Right now PC Speaker and PCjr are handled
|
||||||
|
22
configure
vendored
22
configure
vendored
@ -51,6 +51,7 @@ _nasmpath="$PATH"
|
|||||||
NASMFLAGS=""
|
NASMFLAGS=""
|
||||||
NASM=""
|
NASM=""
|
||||||
_prefix=/usr/local
|
_prefix=/usr/local
|
||||||
|
_have_x86=""
|
||||||
|
|
||||||
_srcdir=`dirname $0`
|
_srcdir=`dirname $0`
|
||||||
|
|
||||||
@ -659,6 +660,26 @@ EOF
|
|||||||
esac
|
esac
|
||||||
rm -f tmp_endianness_check$EXEEXT tmp_endianness_check.cpp
|
rm -f tmp_endianness_check$EXEEXT tmp_endianness_check.cpp
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check whether we can use x86 asm routines
|
||||||
|
#
|
||||||
|
echo_n "Running on x86... "
|
||||||
|
case $_host_cpu in
|
||||||
|
i386|i486|i586|i686)
|
||||||
|
_have_x86=yes
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
_have_x86=no
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if test "$_have_x86" = yes ; then
|
||||||
|
_def_x86='#define HAVE_X86'
|
||||||
|
else
|
||||||
|
_def_x86='#undef HAVE_X86'
|
||||||
|
fi
|
||||||
|
echo "$_have_x86"
|
||||||
|
|
||||||
#
|
#
|
||||||
# Check whether memory alignment is required
|
# Check whether memory alignment is required
|
||||||
#
|
#
|
||||||
@ -1019,6 +1040,7 @@ cat > config.h << EOF
|
|||||||
|
|
||||||
$_def_endianness
|
$_def_endianness
|
||||||
$_def_align
|
$_def_align
|
||||||
|
$_def_x86
|
||||||
|
|
||||||
$_def_linupy
|
$_def_linupy
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ choices of output, depending on your operating system and configuration.
|
|||||||
|
|
||||||
\begin{tabular}[h]{ll}
|
\begin{tabular}[h]{ll}
|
||||||
adlib & Uses internal Adlib Emulation (default)\\
|
adlib & Uses internal Adlib Emulation (default)\\
|
||||||
|
mt32 & Uses internal MT-32 Emulation\\
|
||||||
pcjr & Uses internal PCjr Emulation \\
|
pcjr & Uses internal PCjr Emulation \\
|
||||||
pcspk & Uses internal PC Speaker Emulation\\
|
pcspk & Uses internal PC Speaker Emulation\\
|
||||||
towns & Uses FM-TOWNS YM2612 Emulation\\
|
towns & Uses FM-TOWNS YM2612 Emulation\\
|
||||||
@ -31,6 +32,7 @@ for example:
|
|||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
|
|
||||||
\input {07_01.tex}
|
\input {07_01.tex}
|
||||||
|
\input {07_02a.tex}
|
||||||
\input {07_02.tex}
|
\input {07_02.tex}
|
||||||
\input {07_03.tex}
|
\input {07_03.tex}
|
||||||
\input {07_04.tex}
|
\input {07_04.tex}
|
||||||
|
@ -10,6 +10,6 @@ Some games (such as Sam and Max) only contain MIDI music data. This once
|
|||||||
prevented music for these games from working on platforms that do not support
|
prevented music for these games from working on platforms that do not support
|
||||||
MIDI, or soundcards that do not provide MIDI drivers (e.g, many soundcards will
|
MIDI, or soundcards that do not provide MIDI drivers (e.g, many soundcards will
|
||||||
not play MIDI under Linux). ScummVM can now emulate MIDI mode using sampled
|
not play MIDI under Linux). ScummVM can now emulate MIDI mode using sampled
|
||||||
waves and Adlib emulation using the -eadlib option. However, if you are capable
|
waves and Adlib or MT-32 emulation using the -eadlib or -emt32 options respectively.
|
||||||
of using native MIDI, we recommend using one of the MIDI modes below for best
|
However, if you are capable of using native MIDI, we recommend using one of the
|
||||||
sound.
|
MIDI modes below for best sound.
|
||||||
|
18
doc/07_02a.tex
Normal file
18
doc/07_02a.tex
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
%%% Local Variables:
|
||||||
|
%%% mode: latex
|
||||||
|
%%% TeX-master: "readme"
|
||||||
|
%%% End:
|
||||||
|
|
||||||
|
\subsection{Playing sound with MT-32 emulation}
|
||||||
|
|
||||||
|
Some games which contain MIDI music data also have improved tracks designed
|
||||||
|
for MT-32 sound module. ScummVM can now emulate this card, however you should
|
||||||
|
provide original MT-32 ROMs to make it work. Put the roms in game directory or
|
||||||
|
directory specified by extrapath.
|
||||||
|
|
||||||
|
You don't need to specify --native-mt32 with this driver, as it automatically
|
||||||
|
gets turned on.
|
||||||
|
|
||||||
|
\textbf{NOTE:} You need to have enough processor power to use this emulator as
|
||||||
|
it uses heavy floating-point computations.
|
@ -65,9 +65,12 @@ Thanks!
|
|||||||
\item Special thanks to:\\
|
\item Special thanks to:\\
|
||||||
\begin{tabular}{p{4cm}l}
|
\begin{tabular}{p{4cm}l}
|
||||||
Sander Buskens & For his work on the initial reversing of Monkey2\\
|
Sander Buskens & For his work on the initial reversing of Monkey2\\
|
||||||
|
Canadacow & For his MT-32 emulator\\
|
||||||
Kevin Carnes & For Scumm16, the basis of ScummVM older gfx codec\\
|
Kevin Carnes & For Scumm16, the basis of ScummVM older gfx codec\\
|
||||||
|
Jezar & For his freeverb filter implementation\\
|
||||||
Jim Leiterman & Various info on his FM-TOWNS/Marty SCUMM ports\\
|
Jim Leiterman & Various info on his FM-TOWNS/Marty SCUMM ports\\
|
||||||
Jimmi Thogersen & For ScummRev, and much obscure code/documentation\\
|
Jimmi Thogersen & For ScummRev, and much obscure code/documentation\\
|
||||||
|
Tristan & For his Linux port of MT-32 emulator\\
|
||||||
\end{tabular}
|
\end{tabular}
|
||||||
|
|
||||||
Tony Warriner and everyone at Revolution Software Ltd. for sharing
|
Tony Warriner and everyone at Revolution Software Ltd. for sharing
|
||||||
|
@ -1343,7 +1343,7 @@ void ScummEngine_v90he::scummInit() {
|
|||||||
|
|
||||||
void ScummEngine::setupMusic(int midi) {
|
void ScummEngine::setupMusic(int midi) {
|
||||||
_midiDriver = GameDetector::detectMusicDriver(midi);
|
_midiDriver = GameDetector::detectMusicDriver(midi);
|
||||||
_native_mt32 = ConfMan.getBool("native_mt32");
|
_native_mt32 = (ConfMan.getBool("native_mt32") || (_midiDriver == MD_MT32));
|
||||||
|
|
||||||
#ifndef __GP32__ //ph0x FIXME, "quick dirty hack"
|
#ifndef __GP32__ //ph0x FIXME, "quick dirty hack"
|
||||||
/* Bind the mixer to the system => mixer will be invoked
|
/* Bind the mixer to the system => mixer will be invoked
|
||||||
@ -1393,6 +1393,9 @@ void ScummEngine::setupMusic(int midi) {
|
|||||||
}
|
}
|
||||||
if (midi == MDT_TOWNS)
|
if (midi == MDT_TOWNS)
|
||||||
_imuse->property(IMuse::PROP_DIRECT_PASSTHROUGH, 1);
|
_imuse->property(IMuse::PROP_DIRECT_PASSTHROUGH, 1);
|
||||||
|
if (_midiDriver == MD_MT32) {
|
||||||
|
_imuse->property(IMuse::PROP_DIRECT_PASSTHROUGH, 1);
|
||||||
|
}
|
||||||
_imuse->set_music_volume(ConfMan.getInt("music_volume"));
|
_imuse->set_music_volume(ConfMan.getInt("music_volume"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,8 @@ Specify music output where \fI<mode>\fP can be one of:
|
|||||||
.br
|
.br
|
||||||
\fBadlib\fP Uses internal Adlib Emulation (default)
|
\fBadlib\fP Uses internal Adlib Emulation (default)
|
||||||
.br
|
.br
|
||||||
|
\fBmt32\fP Uses internal MT-32 Emulation
|
||||||
|
.br
|
||||||
\fBwindows\fP Windows MIDI. Uses built-in sequencer.
|
\fBwindows\fP Windows MIDI. Uses built-in sequencer.
|
||||||
.br
|
.br
|
||||||
\fBseq\fP Uses /dev/sequencer for MIDI, *nix users.
|
\fBseq\fP Uses /dev/sequencer for MIDI, *nix users.
|
||||||
|
@ -57,6 +57,7 @@ static const struct MidiDriverDescription midiDrivers[] = {
|
|||||||
{"towns", "FM Towns", MD_TOWNS},
|
{"towns", "FM Towns", MD_TOWNS},
|
||||||
{"pcspk", "PC Speaker", MD_PCSPK},
|
{"pcspk", "PC Speaker", MD_PCSPK},
|
||||||
{"pcjr", "IBM PCjr", MD_PCJR},
|
{"pcjr", "IBM PCjr", MD_PCJR},
|
||||||
|
{"mt32", "MT-32", MD_MT32},
|
||||||
|
|
||||||
#if defined(__PALM_OS__)
|
#if defined(__PALM_OS__)
|
||||||
{"ypa1", "Yamaha Pa1", MD_YPA1},
|
{"ypa1", "Yamaha Pa1", MD_YPA1},
|
||||||
|
@ -47,7 +47,8 @@ enum {
|
|||||||
MD_PCJR = 12,
|
MD_PCJR = 12,
|
||||||
MD_TOWNS = 13,
|
MD_TOWNS = 13,
|
||||||
MD_YPA1 = 14, // PalmOS
|
MD_YPA1 = 14, // PalmOS
|
||||||
MD_ZODIAC = 15 // PalmOS
|
MD_ZODIAC = 15, // PalmOS
|
||||||
|
MD_MT32 = 16
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Convert a string containing a music driver name into MIDI Driver type. */
|
/** Convert a string containing a music driver name into MIDI Driver type. */
|
||||||
@ -177,6 +178,7 @@ extern MidiDriver *MidiDriver_CORE_create();
|
|||||||
extern MidiDriver *MidiDriver_ETUDE_create();
|
extern MidiDriver *MidiDriver_ETUDE_create();
|
||||||
extern MidiDriver *MidiDriver_ALSA_create();
|
extern MidiDriver *MidiDriver_ALSA_create();
|
||||||
extern MidiDriver *MidiDriver_YM2612_create(SoundMixer *mixer);
|
extern MidiDriver *MidiDriver_YM2612_create(SoundMixer *mixer);
|
||||||
|
extern MidiDriver *MidiDriver_MT32_create(SoundMixer *mixer, const char *path);
|
||||||
extern MidiDriver *MidiDriver_YamahaPa1_create();
|
extern MidiDriver *MidiDriver_YamahaPa1_create();
|
||||||
extern MidiDriver *MidiDriver_Zodiac_create();
|
extern MidiDriver *MidiDriver_Zodiac_create();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user