mirror of
https://github.com/thestk/stk
synced 2026-01-12 04:21:52 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f126af4e5 |
@@ -1,17 +0,0 @@
|
||||
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
|
||||
Version 3.1
|
||||
|
||||
By Perry R. Cook, 1995-2000
|
||||
and Gary P. Scavone, 1997-2000.
|
||||
|
||||
Please read the file README.txt for more general STK information.
|
||||
|
||||
STK for Linux is currently using the OSS sound and MIDI API. The free version of OSS will probably work, though it doesn't work with as many soundcards as the commercial version (which costs about $20). The Advanced Linux Sound Architecture (ALSA) drivers seem to perform well, though I've done only minimal testing with them. You'll need to install the OSS compatability library. You can read more about ALSA at http://www.alsa-project.org/. ALSA is open source and holds great promise for audio under Linux.
|
||||
|
||||
STK should compile without much trouble under Linux. Since all Linux distributions typically include the GNU makefile utilities, you should be able to use the default Makefile. Typing "make" will initiate the compilation process.
|
||||
|
||||
NOTE REGARDING PTHREADS:
|
||||
|
||||
The only issue which seems to crop up on different versions of Linux concerns threads. I am using the MIT pthreads API. Under RedHat Linux 4.x, I had to specifically include <pthread/mit/pthread.h> (the default pthread library didn't work). However, under RedHat Linux 5.0 and higher, the default works and the <pthread/mit/> path doesn't exist. I've decided to assume the default works. If you get errors with regard to pthreads when you compile, you'll have to search your system for the MIT pthread distribution and change the appropriate include statements in MIDIIO.cpp, MD2SKINI.cpp, and threads.cpp.
|
||||
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
|
||||
Version 3.1
|
||||
|
||||
By Perry R. Cook, 1995-2000
|
||||
and Gary P. Scavone, 1997-2000.
|
||||
|
||||
Please read the file README.txt for more general STK information.
|
||||
|
||||
DirectX and WindowsNT Issues:
|
||||
-----------------------------
|
||||
|
||||
The newly offered STK realtime sound input capabilities under Windoze are only supported using the DirectSoundCapture API. The latency is pretty horrendous, but what do you expect? Also, there is a good chance you don't have DirectSoundCapture support on your computer. You should download the DirectX 6.0 (or higher) runtime libraries from Microsoft's WWW site (http://www.microsoft.com/directx/download.asp) in order to run the pre-compiled STK executables for Windoze. There is no DirectSoundCapture support for WindowsNT ... you'll have to switch to Windows 2000. If you wish to compile STK under WindowsNT (without realtime audio input support), you'll have to uncomment the __WINMM_API_ flag (and comment out the __WINDS_API flag) in Object.h and recompile the source code.
|
||||
|
||||
Realtime sound output under Windoze is supported using either the DirectSound (dsound.lib) API or the old WinMM (winmm.lib) API. The DirectSound version appears to well out-perform the older API. All new versions of Win95/98/NT come with the DirectSound library, but early versions did not. If you have trouble running the distributed executables (compiled for DirectSound API), then you probably don't have DirectSound installed on your system. You can download the necessary DirectSound stuff from Microsoft's WWW pages (http://www.microsoft.com/directx/download.asp). If all else fails, you should be able to compile using the winmm.lib routines ... more latency, but at least it will work.
|
||||
|
||||
Realtime MIDI input is supported using the winmm.lib API.
|
||||
|
||||
Visual C++ workspaces have been created for the various STK projects. Everything has already been configured for you. The intermediate .obj files will be written to either the "Release" or "Debug" directories, but the executable files will be written to the main project directories (where they need to be for proper execution). If you should somehow lose or hose the VC++ workspace file (STK.dsw), then you will have to do a LOT of configuring to recreate it ... it's probably easier just to download the distribution again from our WWW sites. Anyway, for your benefit and mine, here is a list of things that need to be added to the various "Project Settings":
|
||||
|
||||
1. Under General: Set "Output files:" to <blank> (this will put the executable in the main project directory.
|
||||
|
||||
2. Under C/C++ > Code Generation: Set "Use run-time library:" to Multithreaded.
|
||||
|
||||
3. Under Link > General: Add winmm.lib, dsound.lib, and Wsock32.lib to the end of the Object/library modules list.
|
||||
|
||||
4. Add all the necessary files to the project.
|
||||
|
||||
NOTE: For some of my personal STK files, I've had trouble compiling in VC++ with the "Optimize Speed" optimization setting (in Project Settings -> C/C++ -> Optimizations:). The files compile, but don't work the way they should when executed. These same files, however, have worked when compiled with the "Default" optimization setting. I've heard that there are bugs with some of these optimization settings.
|
||||
|
||||
Remember that items 1-3 above need to be done for each project and for each configuration. There might be an easy way to make global changes, but I couldn't figure it out.
|
||||
|
||||
To use the Tcl/Tk GUIs, you will have to install Tcl/Tk. I got version 8.0 and it works very well (and installed easily). The distribution is available on the WWW and is free.
|
||||
|
||||
In order for socketing to work, it is necessary to have the TCP protocol installed on your computer. This can be done from the "Network" control panel.
|
||||
|
||||
Finally, to use it all -
|
||||
|
||||
|
||||
PLAY SKINI SCOREFILES IN REALTIME:
|
||||
|
||||
syntmono Clarinet -r < scores/streetsf.ski
|
||||
|
||||
|
||||
USE TCL/TK GUIs FOR REALTIME CONTROL:
|
||||
|
||||
1. Open a DOS console window and start syntmono (eg. syntmono Clarinet -r -is).
|
||||
|
||||
2. Double click on a Tcl/Tk file in TCLSpecs (eg. TCLPhys.tcl) from the Windows Explorer to start the GUI. Select the "communications" menu item and "Socket" and make the connection.
|
||||
|
||||
3. Start moving the sliders to control the instrument.
|
||||
|
||||
|
||||
USE REALTIME MIDI INPUT FOR CONTROL:
|
||||
|
||||
1. Open a DOS console window and start syntmono (eg. syntmono Clarinet -r -is).
|
||||
|
||||
2. Open another DOS console window and start MD2SKINI in the following way:
|
||||
|
||||
MD2SKINI -s <optional hostname>
|
||||
|
||||
This assumes you already have MIDI setup correctly for your computer.
|
||||
|
||||
|
||||
WINDOWS NT ONLY:
|
||||
|
||||
Realtime piping seems to work under WindowsNT in much the same way as on Unix platforms. Thus, it is possible to pipe realtime control data to syntmono under WindowsNT as well.
|
||||
|
||||
|
||||
WINDOWS 2000:
|
||||
|
||||
I don't have Windows 2000 and I don't expect to get it anytime soon. Things should work under 2000 at least as well as they do using NT. Since 2000 is supposed to ship with DirectX 7.0, the DirectSoundCapture functionality should work as well.
|
||||
@@ -1,79 +0,0 @@
|
||||
/*******************************************/
|
||||
/* AgogoBell SubClass of Modal4 Instrument*/
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Controls: CONTROL1 = stickHardness */
|
||||
/* CONTROL2 = strikePosition */
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/*******************************************/
|
||||
|
||||
/* Modes measured from my Agogo Bell by FFT: */
|
||||
/* 360, 1470, 2401, 4600 */
|
||||
|
||||
#include "AgogoBel.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
AgogoBel :: AgogoBel() : Modal4()
|
||||
{
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
wave = new RawWvIn(strcat(file,"rawwaves/britestk.raw"), "oneshot");
|
||||
wave->normalize();
|
||||
wave->setRate((MY_FLOAT) 7.0); // hardstick
|
||||
this->setRatioAndReson(0, (MY_FLOAT) 1.00,(MY_FLOAT) 0.999); // Set our
|
||||
this->setRatioAndReson(1, (MY_FLOAT) 4.08,(MY_FLOAT) 0.999); // resonances
|
||||
this->setRatioAndReson(2,(MY_FLOAT) 6.669,(MY_FLOAT) 0.999); // here
|
||||
this->setRatioAndReson(3,(MY_FLOAT) -3725.0, (MY_FLOAT)0.999); // (One fixed)
|
||||
this->setFiltGain(0,(MY_FLOAT) 0.06); // And filter
|
||||
this->setFiltGain(1,(MY_FLOAT) 0.05); // gains too
|
||||
this->setFiltGain(2,(MY_FLOAT) 0.03);
|
||||
this->setFiltGain(3,(MY_FLOAT) 0.02);
|
||||
directGain = (MY_FLOAT) 0.25;
|
||||
}
|
||||
|
||||
AgogoBel :: ~AgogoBel()
|
||||
{
|
||||
delete wave;
|
||||
}
|
||||
|
||||
void AgogoBel :: setStickHardness(MY_FLOAT hardness)
|
||||
{
|
||||
stickHardness = hardness; /* To an approximation, */
|
||||
wave->setRate((MY_FLOAT) 3.0 + ((MY_FLOAT) 8.0 * stickHardness)); /* hardness <-> center */
|
||||
masterGain = (MY_FLOAT) 1.0; /* freq and amplitude */
|
||||
}
|
||||
|
||||
void AgogoBel :: setStrikePosition(MY_FLOAT position)
|
||||
{
|
||||
MY_FLOAT temp,temp2;
|
||||
temp2 = position * PI;
|
||||
strikePosition = position; /* Hack only first */
|
||||
temp = (MY_FLOAT) sin(0.7 * temp2); /* three modes, */
|
||||
this->setFiltGain(0,(MY_FLOAT) 0.08 * temp); /* leave the other */
|
||||
temp = (MY_FLOAT) sin(0.1 + (5.0 * temp2)); /* fixed. Why? */
|
||||
this->setFiltGain(1,(MY_FLOAT) 0.07 * temp); /* So it doesn't */
|
||||
temp = (MY_FLOAT) sin(0.2 + (7.0 * temp2)); /* sound like a */
|
||||
this->setFiltGain(2,(MY_FLOAT) 0.04 * temp); /* sample! */
|
||||
}
|
||||
|
||||
void AgogoBel :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("AgogoBel : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_StickHardness_)
|
||||
this->setStickHardness(value * NORM_7);
|
||||
else if (number == __SK_StrikePosition_)
|
||||
this->setStrikePosition(value * NORM_7);
|
||||
else if (number == __SK_ModFrequency_)
|
||||
vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
|
||||
else if (number == __SK_ModWheel_)
|
||||
vibrGain = (value * NORM_7);
|
||||
else if (number == __SK_AfterTouch_Cont_)
|
||||
this->strike(value * NORM_7);
|
||||
else {
|
||||
printf("AgogoBel : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*******************************************/
|
||||
/* AgogoBell SubClass of Modal4 Instrument*/
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Controls: CONTROL1 = stickHardness */
|
||||
/* CONTROL2 = strikePosition */
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__AgogoBel_h)
|
||||
#define __AgogoBel_h
|
||||
|
||||
#include "Modal4.h"
|
||||
|
||||
class AgogoBel : public Modal4
|
||||
{
|
||||
public:
|
||||
AgogoBel();
|
||||
~AgogoBel();
|
||||
void setStickHardness(MY_FLOAT hardness);
|
||||
void setStrikePosition(MY_FLOAT position);
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
};
|
||||
|
||||
#endif
|
||||
31
STK/BiQuad.h
31
STK/BiQuad.h
@@ -1,31 +0,0 @@
|
||||
/*******************************************/
|
||||
/* BiQuad (2-pole, 2-zero) Filter Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* See books on filters to understand */
|
||||
/* more about how this works. Nothing */
|
||||
/* out of the ordinary in this version. */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__BiQuad_h)
|
||||
#define __BiQuad_h
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
class BiQuad : public Filter
|
||||
{
|
||||
protected:
|
||||
MY_FLOAT poleCoeffs[2];
|
||||
MY_FLOAT zeroCoeffs[2];
|
||||
public:
|
||||
BiQuad();
|
||||
~BiQuad();
|
||||
void clear();
|
||||
void setPoleCoeffs(MY_FLOAT *coeffs);
|
||||
void setZeroCoeffs(MY_FLOAT *coeffs);
|
||||
void setGain(MY_FLOAT aValue);
|
||||
void setFreqAndReson(MY_FLOAT freq, MY_FLOAT reson);
|
||||
void setEqualGainZeroes();
|
||||
MY_FLOAT tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,77 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Linearly Interpolating Delay Line */
|
||||
/* Object by Perry R. Cook 1995-96 */
|
||||
/* This one uses a delay line of maximum */
|
||||
/* length specified on creation, and */
|
||||
/* linearly interpolates fractional */
|
||||
/* length. It is designed to be more */
|
||||
/* efficient if the delay length is not */
|
||||
/* changed very often. */
|
||||
/*******************************************/
|
||||
|
||||
#include "DLineL.h"
|
||||
|
||||
DLineL :: DLineL()
|
||||
{
|
||||
// Default max delay length set to 2047.
|
||||
length = 2048;
|
||||
inputs = (MY_FLOAT *) malloc(length * sizeof(MY_FLOAT));
|
||||
this->clear();
|
||||
inPoint = 0;
|
||||
outPoint = length >> 1;
|
||||
}
|
||||
|
||||
DLineL :: DLineL(long max_length)
|
||||
{
|
||||
length = max_length;
|
||||
inputs = (MY_FLOAT *) malloc(length * sizeof(MY_FLOAT));
|
||||
this->clear();
|
||||
inPoint = 0;
|
||||
outPoint = length >> 1;
|
||||
}
|
||||
|
||||
DLineL :: ~DLineL()
|
||||
{
|
||||
free(inputs);
|
||||
}
|
||||
|
||||
void DLineL :: clear()
|
||||
{
|
||||
long i;
|
||||
for (i=0;i<length;i++) inputs[i] = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0;
|
||||
}
|
||||
|
||||
void DLineL :: setDelay(MY_FLOAT lag)
|
||||
{
|
||||
MY_FLOAT outPointer;
|
||||
|
||||
if (lag > length-1) { // if delay is too big,
|
||||
printf("DLineL: Delay length too big.\n");
|
||||
printf("Setting to maximum length of %ld.\n",length-1);
|
||||
outPointer = inPoint + 1; // force delay to max_length
|
||||
}
|
||||
else
|
||||
outPointer = inPoint - lag; // read chases write
|
||||
while (outPointer<0)
|
||||
outPointer += length; // modulo maximum length
|
||||
outPoint = (long) outPointer; // integer part
|
||||
alpha = outPointer - outPoint; // fractional part
|
||||
omAlpha = (MY_FLOAT) 1.0 - alpha; // 1.0 - fractional part (more efficient)
|
||||
}
|
||||
|
||||
MY_FLOAT DLineL :: tick(MY_FLOAT sample) // Take one, yield one
|
||||
{
|
||||
inputs[inPoint++] = sample; // Input next sample
|
||||
if (inPoint == length) // Check for end condition
|
||||
inPoint -= length;
|
||||
lastOutput = inputs[outPoint++] * omAlpha; // first 1/2 of interpolation
|
||||
if (outPoint<length) { // Check for end condition
|
||||
lastOutput += inputs[outPoint] * alpha; // second 1/2 of interpolation
|
||||
}
|
||||
else { // if at end . . .
|
||||
lastOutput += inputs[0] * alpha; // second 1/2 of interpolation
|
||||
outPoint -= length;
|
||||
}
|
||||
return lastOutput;
|
||||
}
|
||||
34
STK/DLineL.h
34
STK/DLineL.h
@@ -1,34 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Linearly Interpolating Delay Line */
|
||||
/* Object by Perry R. Cook 1995-96 */
|
||||
/* This one uses a delay line of maximum */
|
||||
/* length specified on creation, and */
|
||||
/* linearly interpolates fractional */
|
||||
/* length. It is designed to be more */
|
||||
/* efficient if the delay length is not */
|
||||
/* changed very often. */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__DLineL_h)
|
||||
#define __DLineL_h
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
class DLineL : public Filter
|
||||
{
|
||||
protected:
|
||||
long inPoint;
|
||||
long outPoint;
|
||||
long length;
|
||||
MY_FLOAT alpha;
|
||||
MY_FLOAT omAlpha;
|
||||
public:
|
||||
DLineL();
|
||||
DLineL(long max_length);
|
||||
~DLineL();
|
||||
void clear();
|
||||
void setDelay(MY_FLOAT length);
|
||||
MY_FLOAT tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,70 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Non-Interpolating Delay Line */
|
||||
/* Object by Perry R. Cook 1995-96. */
|
||||
/* Revised by Gary Scavone, 1999. */
|
||||
/* */
|
||||
/* This one uses either a delay line of */
|
||||
/* maximum length specified on creation */
|
||||
/* or a default length of 2048 samples. */
|
||||
/* A non-interpolating delay line is */
|
||||
/* typically used in non-time varying */
|
||||
/* (reverb) applications. */
|
||||
/*******************************************/
|
||||
|
||||
#include "DLineN.h"
|
||||
|
||||
DLineN :: DLineN()
|
||||
{
|
||||
// Default max delay length set to 2047.
|
||||
length = 2048;
|
||||
inputs = (MY_FLOAT *) malloc(length * sizeof(MY_FLOAT));
|
||||
this->clear();
|
||||
inPoint = 0;
|
||||
outPoint = length >> 1;
|
||||
}
|
||||
|
||||
DLineN :: DLineN(long max_length)
|
||||
{
|
||||
// Writing before reading allows delays from 0 to length-1.
|
||||
// Thus, if we want to allow a delay of max_length, we need
|
||||
// a delay-line of length = max_length+1.
|
||||
length = max_length+1;
|
||||
inputs = (MY_FLOAT *) malloc(length * sizeof(MY_FLOAT));
|
||||
this->clear();
|
||||
inPoint = 0;
|
||||
outPoint = length >> 1;
|
||||
}
|
||||
|
||||
DLineN :: ~DLineN()
|
||||
{
|
||||
free(inputs);
|
||||
}
|
||||
|
||||
void DLineN :: clear()
|
||||
{
|
||||
long i;
|
||||
for (i=0;i<length;i++) inputs[i] = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0;
|
||||
}
|
||||
|
||||
void DLineN :: setDelay(MY_FLOAT lag)
|
||||
{
|
||||
if (lag > length-1) { // if delay is too big,
|
||||
printf("DLineN: Delay length too big ... setting to maximum length of %ld.\n",length-1);
|
||||
outPoint = inPoint + 1; // force delay to max_length
|
||||
}
|
||||
else
|
||||
outPoint = inPoint - (long) lag; // read chases write
|
||||
while (outPoint<0) outPoint += length; // modulo maximum length
|
||||
}
|
||||
|
||||
MY_FLOAT DLineN :: tick(MY_FLOAT sample) // Take one, yield one
|
||||
{
|
||||
inputs[inPoint++] = sample; // Input next sample
|
||||
if (inPoint == length) // Check for end condition
|
||||
inPoint -= length;
|
||||
lastOutput = inputs[outPoint++]; // Read out next value
|
||||
if (outPoint>=length) // Check for end condition
|
||||
outPoint -= length;
|
||||
return lastOutput;
|
||||
}
|
||||
35
STK/DLineN.h
35
STK/DLineN.h
@@ -1,35 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Non-Interpolating Delay Line */
|
||||
/* Object by Perry R. Cook 1995-96. */
|
||||
/* Revised by Gary Scavone, 1999. */
|
||||
/* */
|
||||
/* This one uses either a delay line of */
|
||||
/* maximum length specified on creation */
|
||||
/* or a default length of 2048 samples. */
|
||||
/* A non-interpolating delay line is */
|
||||
/* typically used in non-time varying */
|
||||
/* (reverb) applications. */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__DLineN_h)
|
||||
#define __DLineN_h
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
class DLineN : public Filter
|
||||
{
|
||||
protected:
|
||||
long inPoint;
|
||||
long outPoint;
|
||||
long length;
|
||||
public:
|
||||
DLineN();
|
||||
DLineN(long max_length);
|
||||
~DLineN();
|
||||
void clear();
|
||||
void setDelay(MY_FLOAT length);
|
||||
MY_FLOAT tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
582
STK/MIDIIO.cpp
582
STK/MIDIIO.cpp
@@ -1,582 +0,0 @@
|
||||
/******************************************/
|
||||
/* MIDIIO.cpp */
|
||||
/* Realtime MIDI I/O Object for STK, */
|
||||
/* by Gary P. Scavone, 1998. */
|
||||
/* Based in part on code by Perry */
|
||||
/* Cook (SGI), Paul Leonard (Linux), */
|
||||
/* the RoseGarden team (Linux), and */
|
||||
/* Bill Putnam (Win95/NT). */
|
||||
/* */
|
||||
/* At the moment, this object only */
|
||||
/* handles MIDI Input, though MIDI */
|
||||
/* Output code can go here when someone */
|
||||
/* decides they need it (and writes it). */
|
||||
/* */
|
||||
/* This object opens a MIDI Input device */
|
||||
/* and parses MIDI messages into a MIDI */
|
||||
/* buffer. Time stamp info is converted */
|
||||
/* to deltaTime. MIDI data is stored as */
|
||||
/* MY_FLOAT to conform with SKINI. */
|
||||
/******************************************/
|
||||
|
||||
#include "MIDIIO.h"
|
||||
|
||||
#if defined(__STK_REALTIME_)
|
||||
|
||||
#define MIDI_BUFFER_SIZE 1024
|
||||
int writeOffset;
|
||||
int readOffset;
|
||||
|
||||
#if defined(__OS_IRIX_)
|
||||
|
||||
/*************************************/
|
||||
/* SGI MIDI INPUT */
|
||||
/*************************************/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <dmedia/midi.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
|
||||
MDport inport;
|
||||
|
||||
MDevent *midiBuffer;
|
||||
|
||||
pthread_t midi_input_thread;
|
||||
|
||||
void *midiInputThread(void *)
|
||||
{
|
||||
MDevent newMessage;
|
||||
int status;
|
||||
|
||||
while (1) {
|
||||
mdReceive(inport, &newMessage, 1);
|
||||
status = (newMessage.msg[0] & MD_STATUSMASK);
|
||||
|
||||
// Ignore all system messages
|
||||
//if (!((status & 0xff) == 0xfe || (status & 0xff) == 0xf8)) {
|
||||
if (status != 0xf0) {
|
||||
midiBuffer[writeOffset] = newMessage;
|
||||
writeOffset++;
|
||||
|
||||
if( writeOffset >= MIDI_BUFFER_SIZE )
|
||||
writeOffset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MIDIIO :: MIDIIO()
|
||||
{
|
||||
int nports;
|
||||
|
||||
nports = mdInit();
|
||||
printf("%d MIDI devices available\n", nports);
|
||||
inport = mdOpenInPort(NULL);
|
||||
if (inport == NULL) {
|
||||
fprintf(stderr,"Cannot open MIDI device.\n");
|
||||
printf("Exiting MIDIIO Process.\n");
|
||||
exit(0);
|
||||
}
|
||||
mdSetStampMode(inport, MD_NOSTAMP);
|
||||
|
||||
// Set up the circular buffer for the Midi Input Messages
|
||||
midiBuffer = new MDevent[MIDI_BUFFER_SIZE];
|
||||
readOffset = 0;
|
||||
writeOffset = 0;
|
||||
|
||||
if (pthread_create(&midi_input_thread, NULL, midiInputThread, NULL)) {
|
||||
fprintf(stderr, "unable to create MIDI input thread ... aborting.\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
MIDIIO :: ~MIDIIO()
|
||||
{
|
||||
pthread_cancel(midi_input_thread);
|
||||
mdClosePort(inport);
|
||||
delete [] midiBuffer;
|
||||
}
|
||||
|
||||
int MIDIIO :: nextMessage()
|
||||
{
|
||||
int status;
|
||||
int byte1;
|
||||
int byte2;
|
||||
MDevent lastEvent;
|
||||
static unsigned long long lastTimeStamp = 0;
|
||||
|
||||
if ( readOffset == writeOffset ) return 0;
|
||||
|
||||
lastEvent = midiBuffer[readOffset];
|
||||
|
||||
readOffset++;
|
||||
if ( readOffset >= MIDI_BUFFER_SIZE ) readOffset = 0;
|
||||
|
||||
status = (lastEvent.msg[0] & MD_STATUSMASK);
|
||||
byte1 = lastEvent.msg[1];
|
||||
byte2 = lastEvent.msg[2];
|
||||
channel = (lastEvent.msg[0] & MD_CHANNELMASK);
|
||||
|
||||
if ((status == MD_PROGRAMCHANGE) ||
|
||||
(status == MD_CHANNELPRESSURE))
|
||||
{
|
||||
messageType = status;
|
||||
byteTwo = (float) byte1;
|
||||
deltaTime = (MY_FLOAT) ((lastEvent.stamp - lastTimeStamp) * 0.000000001);
|
||||
lastTimeStamp = lastEvent.stamp;
|
||||
}
|
||||
else if ((status == MD_NOTEON) || (status == MD_NOTEOFF) ||
|
||||
(status == MD_CONTROLCHANGE) || (status == MD_POLYKEYPRESSURE))
|
||||
{
|
||||
messageType = status;
|
||||
byteTwo = (float) byte1;
|
||||
byteThree = (float) byte2;
|
||||
deltaTime = (MY_FLOAT) ((lastEvent.stamp - lastTimeStamp) * 0.000000001);
|
||||
lastTimeStamp = lastEvent.stamp;
|
||||
}
|
||||
else if (status == MD_PITCHBENDCHANGE)
|
||||
{
|
||||
messageType = status;
|
||||
byteTwo = (float) byte1 * NORM_7;
|
||||
byteTwo += (float) byte2;
|
||||
deltaTime = (MY_FLOAT) ((lastEvent.stamp - lastTimeStamp) * 0.000000001);
|
||||
lastTimeStamp = lastEvent.stamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
messageType = -1;
|
||||
}
|
||||
|
||||
return messageType;
|
||||
}
|
||||
|
||||
|
||||
#elif defined(__OSS_API_)
|
||||
|
||||
/*************************************/
|
||||
/* OSS MIDI INPUT */
|
||||
/*************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/soundcard.h>
|
||||
#include <pthread.h>
|
||||
//#include <pthread/mit/pthread.h>
|
||||
|
||||
int _seqfd;
|
||||
|
||||
typedef unsigned char byte;
|
||||
|
||||
typedef struct {
|
||||
byte data[4];
|
||||
unsigned long time;
|
||||
} MIDIMESSAGE;
|
||||
|
||||
MIDIMESSAGE *midiBuffer;
|
||||
|
||||
/* System Messages */
|
||||
#define MIDI_SYSTEM_MSG ((byte)0xF0)
|
||||
#define MessageType(MSG) (byte)((MSG) & ((byte)0xF0))
|
||||
|
||||
#define SEQUENCER_PATH "/dev/sequencer"
|
||||
|
||||
/* MIDI time code at 100 ticks per second. */
|
||||
#define OSS_MIDI_CLOCK_RATE 100
|
||||
|
||||
pthread_t midi_input_thread;
|
||||
|
||||
void *midiInputThread(void *)
|
||||
{
|
||||
byte NumArgs = 0;
|
||||
byte ArgsLeft = 0;
|
||||
unsigned long lastTime = 0;
|
||||
unsigned long newTime = 0;
|
||||
byte InBytes[4];
|
||||
static MIDIMESSAGE newMessage;
|
||||
int n;
|
||||
|
||||
while (1) {
|
||||
if ((n = read(_seqfd, &InBytes, sizeof(InBytes))) == -1) {
|
||||
fprintf(stderr,"Error reading " SEQUENCER_PATH "\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (n == 4) { /* ignore reads returning less than 4 bytes */
|
||||
switch ( InBytes[0] )
|
||||
{
|
||||
case SEQ_WAIT:
|
||||
/* MIDI clock ticks ... the first MIDI message deltaTime is calculated
|
||||
* with respect to the start of the MIDI clock.
|
||||
*/
|
||||
newTime = ((InBytes[3]<<16)|(InBytes[2]<<8)| InBytes[1]);
|
||||
break;
|
||||
|
||||
case SEQ_ECHO:
|
||||
/* no echo events yet defined */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"ECHO EVENT\n");
|
||||
#endif
|
||||
break;
|
||||
|
||||
case SEQ_MIDIPUTC:
|
||||
/* Determination of a full MIDI message from the input MIDI stream is based
|
||||
here on the observation that MIDI status bytes and subsequent data bytes
|
||||
are NOT returned in the same read() call. Rather, they are spread out
|
||||
over multiple read() returns, with only a single value per return. So,
|
||||
if we find a status byte, we then determine the number of expected
|
||||
operands and process that number of subsequent read()s to determine the
|
||||
complete MIDI message.
|
||||
*/
|
||||
if (InBytes[1] & 0x80) { /* Status Byte */
|
||||
if (MessageType(InBytes[1]) == MIDI_SYSTEM_MSG)
|
||||
{
|
||||
NumArgs = 0; /* no timing info */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "SYSTEM MESSAGE\n");
|
||||
#endif
|
||||
}
|
||||
else if (MessageType(InBytes[1]) == MIDI_PGM_CHANGE ||
|
||||
MessageType(InBytes[1]) == MIDI_CHN_PRESSURE)
|
||||
{
|
||||
NumArgs = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
NumArgs = 2;
|
||||
}
|
||||
newMessage.data[0] = InBytes[1];
|
||||
ArgsLeft = NumArgs;
|
||||
newMessage.data[1] = 0;
|
||||
newMessage.data[2] = 0;
|
||||
}
|
||||
|
||||
if (ArgsLeft && !(InBytes[1] & 0x80)) { /* not a status byte */
|
||||
if (ArgsLeft == NumArgs)
|
||||
newMessage.data[1] = InBytes[1];
|
||||
else
|
||||
{
|
||||
newMessage.data[2] = InBytes[1];
|
||||
}
|
||||
|
||||
--ArgsLeft;
|
||||
|
||||
/* If MIDI message complete, then setup for running status mode
|
||||
(another event of the same type without status byte).
|
||||
*/
|
||||
if ( !ArgsLeft ) {
|
||||
if (MessageType(newMessage.data[0]) == (int) MIDI_PGM_CHANGE ||
|
||||
MessageType(newMessage.data[0]) == (int) MIDI_CHN_PRESSURE)
|
||||
{
|
||||
ArgsLeft = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ArgsLeft = 2;
|
||||
}
|
||||
newMessage.time = newTime - lastTime;
|
||||
lastTime = newTime;
|
||||
|
||||
// Put newMessage in the circular buffer
|
||||
midiBuffer[writeOffset] = newMessage;
|
||||
writeOffset++;
|
||||
|
||||
if( writeOffset >= MIDI_BUFFER_SIZE )
|
||||
writeOffset = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MIDIIO :: MIDIIO()
|
||||
{
|
||||
int err = 0;
|
||||
_seqfd = 0;
|
||||
|
||||
#ifdef NONBLOCKING_MIDI
|
||||
if((_seqfd = open(SEQUENCER_PATH, O_RDONLY+O_NONBLOCK, 0)) == -1) {
|
||||
#else
|
||||
if((_seqfd = open(SEQUENCER_PATH, O_RDONLY, 0)) == -1) {
|
||||
#endif
|
||||
fprintf(stderr,"Cannot open " SEQUENCER_PATH ". \n");
|
||||
printf("Exiting MIDIIO Process.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Set up the circular buffer for the Midi Input Messages
|
||||
midiBuffer = new MIDIMESSAGE[MIDI_BUFFER_SIZE];
|
||||
readOffset = 0;
|
||||
writeOffset = 0;
|
||||
|
||||
err = pthread_create(&midi_input_thread, NULL, midiInputThread, NULL);
|
||||
if (err)
|
||||
{
|
||||
fprintf(stderr, "Unable to create MIDI input thread.\n");
|
||||
printf("Exiting MIDIIO Process.\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
MIDIIO :: ~MIDIIO()
|
||||
{
|
||||
pthread_cancel(midi_input_thread);
|
||||
if (_seqfd != 0) close(_seqfd);
|
||||
delete [] midiBuffer;
|
||||
}
|
||||
|
||||
int MIDIIO::nextMessage()
|
||||
{
|
||||
MIDIMESSAGE lastEvent;
|
||||
|
||||
if ( readOffset == writeOffset ) return 0;
|
||||
|
||||
lastEvent = midiBuffer[readOffset];
|
||||
|
||||
readOffset++;
|
||||
if ( readOffset >= MIDI_BUFFER_SIZE ) readOffset = 0;
|
||||
|
||||
messageType = (int) (lastEvent.data[0] & 0xf0);
|
||||
channel = (int) (lastEvent.data[0] & 0x0f);
|
||||
byteTwo = (float) lastEvent.data[1];
|
||||
if (messageType == (int) MIDI_PITCH_BEND)
|
||||
byteTwo = (float) lastEvent.data[2] + (byteTwo * NORM_7);
|
||||
else
|
||||
byteThree = (float) lastEvent.data[2];
|
||||
deltaTime = (float) lastEvent.time / OSS_MIDI_CLOCK_RATE;
|
||||
|
||||
return messageType;
|
||||
}
|
||||
|
||||
|
||||
#elif defined(__OS_Win_)
|
||||
|
||||
/*************************************/
|
||||
/* Windoze MIDI INPUT */
|
||||
/*************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "MIDIIO.h"
|
||||
|
||||
#define MIDI_NOTEON 0x90
|
||||
#define MIDI_NOTEOFF 0x80
|
||||
#define MIDI_POLYKEYPRESSURE 0xA0
|
||||
#define MIDI_CHANNELPRESSURE 0xD0
|
||||
#define MIDI_PROGRAMCHANGE 0xC0
|
||||
#define MIDI_CONTROLCHANGE 0xB0
|
||||
#define MIDI_PITCHBEND 0xE0
|
||||
|
||||
typedef struct {
|
||||
DWORD data;
|
||||
DWORD time;
|
||||
} MIDIMESSAGE;
|
||||
|
||||
MIDIMESSAGE *midiBuffer;
|
||||
|
||||
static void CALLBACK midiInputCallback( HMIDIOUT hmin, UINT inputStatus,
|
||||
DWORD instancePtr, DWORD midiMessage, DWORD timestamp)
|
||||
{
|
||||
MIDIMESSAGE newMessage;
|
||||
|
||||
switch (inputStatus) {
|
||||
case MIM_OPEN:
|
||||
#ifdef TESTING_MIDI_IN
|
||||
printf("MIM_OPEN\n");
|
||||
#endif
|
||||
break;
|
||||
|
||||
case MIM_CLOSE:
|
||||
#ifdef TESTING_MIDI_IN
|
||||
printf("MIM_CLOSE\n");
|
||||
#endif
|
||||
break;
|
||||
|
||||
case MIM_DATA:
|
||||
#ifdef TESTING_MIDI_IN
|
||||
printf("MIM_DATA\n");
|
||||
#endif
|
||||
// Ignore Active Sensing messages
|
||||
if ((midiMessage & 0xff) == 0xfe || (midiMessage & 0xff) == 0xf8) {
|
||||
break;
|
||||
}
|
||||
newMessage.data = midiMessage;
|
||||
newMessage.time = timestamp;
|
||||
|
||||
// Put newMessage in the circular buffer
|
||||
midiBuffer[writeOffset] = newMessage;
|
||||
writeOffset++;
|
||||
|
||||
if( writeOffset >= MIDI_BUFFER_SIZE )
|
||||
writeOffset = 0;
|
||||
break;
|
||||
|
||||
case MIM_ERROR:
|
||||
fprintf(stderr,"Invalid MIDI message received!\n");
|
||||
#ifdef TESTING_MIDI_IN
|
||||
printf("MIM_ERROR\n");
|
||||
#endif
|
||||
break;
|
||||
|
||||
case MIM_LONGDATA:
|
||||
/* System exclusive buffer is returned */
|
||||
break;
|
||||
|
||||
case MIM_LONGERROR:
|
||||
#ifdef TESTING_MIDI_IN
|
||||
printf("MIM_LONGERROR\n");
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
HMIDIIN hMidiIn ; // Handle to Midi Output Device
|
||||
|
||||
MIDIIO :: MIDIIO()
|
||||
{
|
||||
MMRESULT result;
|
||||
UINT uDeviceID;
|
||||
MIDIINCAPS deviceCaps;
|
||||
UINT i;
|
||||
char inputString[128];
|
||||
|
||||
uDeviceID = midiInGetNumDevs();
|
||||
printf("%i MIDI Input Devices Available.\n",uDeviceID);
|
||||
if (uDeviceID == 0) {
|
||||
printf("Exiting MIDIIO Process.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for (i=0; i<uDeviceID; i++) {
|
||||
result = midiInGetDevCaps(i, &deviceCaps, sizeof(MIDIINCAPS));
|
||||
printf("MIDI Device %d is %s.\n", i, deviceCaps.szPname);
|
||||
}
|
||||
|
||||
if (uDeviceID > 1) {
|
||||
printf("\nType the MIDI Device to open: ");
|
||||
fgets(inputString, 128, stdin);
|
||||
uDeviceID = (UINT) atoi(inputString);
|
||||
}
|
||||
else uDeviceID -= 1;
|
||||
|
||||
// Open the port and return any errors
|
||||
result = midiInOpen(&hMidiIn, uDeviceID, (DWORD)&midiInputCallback, (DWORD)NULL, CALLBACK_FUNCTION);
|
||||
if (result != MMSYSERR_NOERROR) {
|
||||
fprintf(stderr,"Cannot open MIDI Input Device %d!\n", uDeviceID);
|
||||
printf("Exiting MIDIIO Process.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Set up the circular buffer for the Midi Input Messages
|
||||
midiBuffer = new MIDIMESSAGE[MIDI_BUFFER_SIZE];
|
||||
readOffset = 0;
|
||||
writeOffset = 0;
|
||||
|
||||
midiInStart( hMidiIn );
|
||||
}
|
||||
|
||||
MIDIIO :: ~MIDIIO()
|
||||
{
|
||||
midiInReset( hMidiIn );
|
||||
midiInStop( hMidiIn );
|
||||
midiInClose( hMidiIn );
|
||||
delete [] midiBuffer;
|
||||
}
|
||||
|
||||
int MIDIIO :: nextMessage()
|
||||
{
|
||||
int status;
|
||||
int byte1;
|
||||
int byte2;
|
||||
MIDIMESSAGE lastEvent;
|
||||
static DWORD lastTime = 0;
|
||||
static DWORD newTime = 0;
|
||||
|
||||
if ( readOffset == writeOffset ) return 0;
|
||||
|
||||
lastEvent = midiBuffer[readOffset];
|
||||
|
||||
readOffset++;
|
||||
if ( readOffset >= MIDI_BUFFER_SIZE ) readOffset = 0;
|
||||
|
||||
status = (int) (lastEvent.data & 0xff);
|
||||
byte1 = (int) (lastEvent.data & 0xff00) >> 8;
|
||||
byte2 = (int) (lastEvent.data & 0xff0000) >> 16;
|
||||
channel = (int) (status & 0x0f);
|
||||
status &= 0xf0; // Clear lower byte of status
|
||||
newTime = lastEvent.time;
|
||||
deltaTime = (float) (newTime - lastTime) * 0.001;
|
||||
lastTime = newTime;
|
||||
|
||||
if ((status == MIDI_PROGRAMCHANGE) ||
|
||||
(status == MIDI_CHANNELPRESSURE))
|
||||
{
|
||||
messageType = status;
|
||||
byteTwo = (float) byte1;
|
||||
}
|
||||
else if ((status == MIDI_NOTEON) || (status == MIDI_NOTEOFF) ||
|
||||
(status == MIDI_CONTROLCHANGE) || (status == MIDI_POLYKEYPRESSURE))
|
||||
{
|
||||
messageType = status;
|
||||
byteTwo = (float) byte1;
|
||||
byteThree = (float) byte2;
|
||||
}
|
||||
else if (status == MIDI_PITCHBEND)
|
||||
{
|
||||
messageType = status;
|
||||
byteTwo = (float) (byte1 * NORM_7);
|
||||
byteTwo += (float) byte2;
|
||||
}
|
||||
else
|
||||
{
|
||||
messageType = -1;
|
||||
}
|
||||
|
||||
return messageType;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void MIDIIO :: printMessage()
|
||||
{
|
||||
printf("type = %d, channel = %d, byte2 = %f, byte3 = %f\n",
|
||||
this->getType(), this->getChannel(), this->getByteTwo(),
|
||||
this->getByteThree());
|
||||
}
|
||||
|
||||
int MIDIIO :: getType()
|
||||
{
|
||||
return messageType;
|
||||
}
|
||||
|
||||
int MIDIIO :: getChannel()
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
|
||||
MY_FLOAT MIDIIO :: getByteTwo()
|
||||
{
|
||||
return byteTwo;
|
||||
}
|
||||
|
||||
MY_FLOAT MIDIIO :: getByteThree()
|
||||
{
|
||||
return byteThree;
|
||||
}
|
||||
|
||||
MY_FLOAT MIDIIO :: getDeltaTime()
|
||||
{
|
||||
return deltaTime;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
56
STK/MIDIIO.h
56
STK/MIDIIO.h
@@ -1,56 +0,0 @@
|
||||
/******************************************/
|
||||
/* MIDIIO.h */
|
||||
/* Realtime MIDI I/O Object for STK, */
|
||||
/* by Gary P. Scavone, 1998. */
|
||||
/* Based in part on code by Perry */
|
||||
/* Cook (SGI), Paul Leonard (Linux), */
|
||||
/* the RoseGarden team (Linux), and */
|
||||
/* Bill Putnam (Win95/NT). */
|
||||
/* */
|
||||
/* At the moment, this object only */
|
||||
/* handles MIDI Input, though MIDI */
|
||||
/* Output code can go here when someone */
|
||||
/* decides they need it (and writes it). */
|
||||
/* */
|
||||
/* This object opens a MIDI Input device */
|
||||
/* and parses MIDI data. Time stamp */
|
||||
/* info is converted to deltaTime. */
|
||||
/* MIDI data is stored as MY_FLOAT to */
|
||||
/* conform with SKINI. */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__MIDIIO_h)
|
||||
#define __MIDIIO_h
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
class MIDIIO : public Object
|
||||
{
|
||||
protected:
|
||||
int messageType;
|
||||
int channel;
|
||||
float byteTwo;
|
||||
float byteThree;
|
||||
MY_FLOAT deltaTime;
|
||||
public:
|
||||
MIDIIO();
|
||||
~MIDIIO();
|
||||
void printMessage();
|
||||
int nextMessage();
|
||||
int getType();
|
||||
int getChannel();
|
||||
MY_FLOAT getByteTwo();
|
||||
MY_FLOAT getByteThree();
|
||||
MY_FLOAT getDeltaTime();
|
||||
};
|
||||
|
||||
#if defined(__OS_Win_)
|
||||
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
static void CALLBACK midiInputCallback( HMIDIOUT hmin, UINT inputStatus,
|
||||
DWORD instancePtr, DWORD midiMessage, DWORD timestamp);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
116
STK/Marimba.cpp
116
STK/Marimba.cpp
@@ -1,116 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Marimba SubClass of Modal4 Instrument, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Controls: CONTROL1 = stickHardness */
|
||||
/* CONTROL2 = strikePosition*/
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/*******************************************/
|
||||
|
||||
#include "Marimba.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
Marimba :: Marimba() : Modal4()
|
||||
{
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
wave = new RawWvIn(strcat(file,"rawwaves/marmstk1.raw"),"oneshot");
|
||||
wave->normalize();
|
||||
wave->setRate((MY_FLOAT) 0.5); /* normal stick */
|
||||
this->setRatioAndReson(0, (MY_FLOAT) 1.00,(MY_FLOAT) 0.9996); /* Set all 132.0 */
|
||||
this->setRatioAndReson(1, (MY_FLOAT) 3.99,(MY_FLOAT) 0.9994); /* of our 523.0 */
|
||||
this->setRatioAndReson(2,(MY_FLOAT) 10.65,(MY_FLOAT) 0.9994); /* default 1405.0 */
|
||||
this->setRatioAndReson(3,-(MY_FLOAT) 2443.0,(MY_FLOAT) 0.999); /* resonances 2443.0 */
|
||||
this->setFiltGain(0,(MY_FLOAT) 0.04); /* and */
|
||||
this->setFiltGain(1,(MY_FLOAT) 0.01); /* gains */
|
||||
this->setFiltGain(2,(MY_FLOAT) 0.01); /* for each */
|
||||
this->setFiltGain(3,(MY_FLOAT) 0.008); /* resonance */
|
||||
directGain = (MY_FLOAT) 0.1;
|
||||
multiStrike = 0;
|
||||
}
|
||||
|
||||
Marimba :: ~Marimba()
|
||||
{
|
||||
delete wave;
|
||||
}
|
||||
|
||||
void Marimba :: setStickHardness(MY_FLOAT hardness)
|
||||
{
|
||||
stickHardness = hardness;
|
||||
wave->setRate((MY_FLOAT) (0.25 * (MY_FLOAT) pow(4.0,stickHardness)));
|
||||
masterGain = (MY_FLOAT) 0.1 + ((MY_FLOAT) 1.8 * stickHardness);
|
||||
}
|
||||
|
||||
void Marimba :: setStrikePosition(MY_FLOAT position)
|
||||
{
|
||||
MY_FLOAT temp,temp2;
|
||||
temp2 = position * PI;
|
||||
strikePosition = position; /* Hack only first three modes */
|
||||
temp = (MY_FLOAT) sin(temp2);
|
||||
this->setFiltGain(0,(MY_FLOAT) 0.12 * temp); /* 1st mode function of pos. */
|
||||
temp = (MY_FLOAT) sin(0.05 + (3.9 * temp2));
|
||||
this->setFiltGain(1,(MY_FLOAT) -0.03 * temp); /* 2nd mode function of pos. */
|
||||
temp = (MY_FLOAT) sin(-0.05 + (11 * temp2));
|
||||
this->setFiltGain(2,(MY_FLOAT) 0.11 * temp); /* 3rd mode function of pos. */
|
||||
}
|
||||
|
||||
void Marimba :: setModulationSpeed(MY_FLOAT mSpeed)
|
||||
{
|
||||
/* don't bother here, marimba decay so fast, mod doesn't make sense */
|
||||
}
|
||||
|
||||
void Marimba :: setModulationDepth(MY_FLOAT mDepth)
|
||||
{
|
||||
}
|
||||
|
||||
void Marimba :: strike(MY_FLOAT amplitude)
|
||||
{
|
||||
int temp;
|
||||
temp = rand() >> 10;
|
||||
if (temp < 2) {
|
||||
multiStrike = 1;
|
||||
#if defined(_debug_)
|
||||
printf("striking twice here!!\n");
|
||||
#endif
|
||||
}
|
||||
else if (temp < 1) {
|
||||
multiStrike = 2;
|
||||
#if defined(_debug_)
|
||||
printf("striking three times here!!!\n");
|
||||
#endif
|
||||
}
|
||||
else multiStrike = 0;
|
||||
Modal4::strike(amplitude);
|
||||
}
|
||||
|
||||
void Marimba :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("Marimba : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_StickHardness_)
|
||||
this->setStickHardness(value * NORM_7);
|
||||
else if (number == __SK_StrikePosition_)
|
||||
this->setStrikePosition(value * NORM_7);
|
||||
else if (number == __SK_ModFrequency_)
|
||||
vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
|
||||
else if (number == __SK_ModWheel_)
|
||||
vibrGain = (value * NORM_7);
|
||||
else if (number == __SK_AfterTouch_Cont_)
|
||||
this->strike(value * NORM_7);
|
||||
else {
|
||||
printf("Marimba : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
MY_FLOAT Marimba :: tick()
|
||||
{
|
||||
if (multiStrike>0)
|
||||
if (wave->isFinished()) {
|
||||
wave->reset();
|
||||
multiStrike -= 1;
|
||||
}
|
||||
return Modal4::tick();
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Marimba SubClass of Modal4 Instrument, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Controls: CONTROL1 = stickHardness */
|
||||
/* CONTROL2 = strikePosition*/
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__Marimba_h)
|
||||
#define __Marimba_h
|
||||
|
||||
#include "Modal4.h"
|
||||
|
||||
class Marimba : public Modal4
|
||||
{
|
||||
private:
|
||||
int multiStrike;
|
||||
public:
|
||||
Marimba();
|
||||
~Marimba();
|
||||
void setStickHardness(MY_FLOAT hardness);
|
||||
void setStrikePosition(MY_FLOAT position);
|
||||
void setModulationSpeed(MY_FLOAT mSpeed);
|
||||
void setModulationDepth(MY_FLOAT mDepth);
|
||||
virtual void strike(MY_FLOAT amplitude);
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
virtual MY_FLOAT tick();
|
||||
};
|
||||
|
||||
#endif
|
||||
178
STK/MatWvIn.cpp
178
STK/MatWvIn.cpp
@@ -1,178 +0,0 @@
|
||||
/*******************************************/
|
||||
/* MatWvIn Input Class, */
|
||||
/* by Gary P. Scavone, 1999 */
|
||||
/* */
|
||||
/* This object inherits from WvIn and is */
|
||||
/* used to open Matlab MAT-file data */
|
||||
/* (doubles) files for playback. In */
|
||||
/* order for this class to work, the */
|
||||
/* MAT-file must contain a single array */
|
||||
/* (matrix) of double-precision floating */
|
||||
/* point values (can be multi-channel). */
|
||||
/* It does not work for any other data */
|
||||
/* formats. */
|
||||
/* */
|
||||
/* MAT-file data is either big- or */
|
||||
/* little-endian, which can be determined */
|
||||
/* from the header. */
|
||||
/*******************************************/
|
||||
|
||||
#include "MatWvIn.h"
|
||||
#include "swapstuf.h"
|
||||
|
||||
MatWvIn :: MatWvIn(char *fileName, char *mode)
|
||||
{
|
||||
extern double SwapDouble(double);
|
||||
|
||||
// Open the file and get header info
|
||||
FILE *fd;
|
||||
fd = fopen(fileName,"rb");
|
||||
if (!fd) {
|
||||
printf("Couldn't open or find MAT-file %s !!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Make sure this is a version 5 MAT-file format and find its endian-ness
|
||||
char head[4];
|
||||
fseek(fd,0,SEEK_SET);
|
||||
fread(&head,4,1,fd); // If any of the first 4 characters of the header = 0,
|
||||
if (strstr(head,"0")) { // then this is a Version 4 MAT-file.
|
||||
printf("This looks like a Version 4 MAT-file. I don't support\n");
|
||||
printf("that at the moment, but you can add the code to MatWvIn if\n");
|
||||
printf("you really need it.\n");
|
||||
exit(0);
|
||||
}
|
||||
char mi[2];
|
||||
int swap = 0;
|
||||
fseek(fd,126,SEEK_SET); // Locate "M" and "I" characters in header
|
||||
fread(&mi,2,1,fd);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
if (!strncmp(mi,"MI",2)) {
|
||||
swap = 1;
|
||||
} else if (strncmp(mi,"IM",2)) {
|
||||
printf("This doesn't appear to be a MAT-file %s !!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
#else
|
||||
if (!strncmp(mi,"IM",2)) {
|
||||
swap = 1;
|
||||
} else if (strncmp(mi,"MI",2)) {
|
||||
printf("This doesn't appear to be a MAT-file %s !!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check the data element type
|
||||
INT32 datatype;
|
||||
fread(&datatype,4,1,fd);
|
||||
if (swap) datatype = SwapINT32(datatype);
|
||||
if (datatype != 14) {
|
||||
printf("I'm expecting a single array (or matrix) data element.\n");
|
||||
printf("This doesn't appear to be the case with your data. Sorry!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Check the array data type
|
||||
INT32 tmp;
|
||||
INT32 size;
|
||||
fseek(fd,168,SEEK_SET);
|
||||
fread(&tmp,4,1,fd);
|
||||
if (swap) tmp = SwapINT32(tmp);
|
||||
if (tmp == 1) { // array name > 4 characters
|
||||
fread(&tmp,4,1,fd); // get array name length
|
||||
if (swap) tmp = SwapINT32(tmp);
|
||||
size = (INT32) ceil((float)tmp/8);
|
||||
fseek(fd,size*8,SEEK_CUR); // jump over array name
|
||||
}
|
||||
else { // array name <= 4 characters, compressed data element
|
||||
fseek(fd,4,SEEK_CUR);
|
||||
}
|
||||
fread(&tmp,4,1,fd);
|
||||
if (swap) tmp = SwapINT32(tmp);
|
||||
if (tmp != 9) {
|
||||
printf("I'm expecting the array data to be in double precision\n");
|
||||
printf("floating-point format. This doesn't appear to be the case\n");
|
||||
printf("with your data. Sorry!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Get number of rows from the header
|
||||
INT32 rows;
|
||||
fseek(fd,160,SEEK_SET);
|
||||
fread(&rows,4,1,fd); // rows
|
||||
if (swap) rows = SwapINT32(rows);
|
||||
|
||||
// Get number of columns from the header
|
||||
INT32 columns;
|
||||
fread(&columns,4,1,fd); // columns
|
||||
if (swap) columns = SwapINT32(columns);
|
||||
|
||||
// Make channels = smaller of rows or columns
|
||||
if (rows < columns) {
|
||||
channels = rows;
|
||||
length = columns;
|
||||
}
|
||||
else {
|
||||
channels = columns;
|
||||
length = rows;
|
||||
}
|
||||
data = (MY_FLOAT *) new MY_FLOAT[(length+1)*channels];
|
||||
|
||||
// Move read pointer to the data in the file
|
||||
INT32 headsize;
|
||||
fseek(fd,132,SEEK_SET);
|
||||
fread(&headsize,4,1,fd); // file size from 132nd byte
|
||||
if (swap) headsize = SwapINT32(headsize);
|
||||
headsize -= length * 8 * channels;
|
||||
fseek(fd,headsize,SEEK_CUR);
|
||||
|
||||
// Read samples into data[]
|
||||
long i = 0;
|
||||
double temp;
|
||||
if (channels == rows) {
|
||||
while (fread(&temp,8,1,fd)) {
|
||||
if (swap) temp = SwapDouble(temp);
|
||||
data[i++] = (MY_FLOAT) temp;
|
||||
}
|
||||
} else {
|
||||
long j = 0;
|
||||
while (fread(&temp,8,1,fd)) {
|
||||
if (swap) temp = SwapDouble(temp);
|
||||
data[channels*i+j] = (MY_FLOAT) temp;
|
||||
i++;
|
||||
if (!(i<length)) {
|
||||
i = 0;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fd);
|
||||
|
||||
// Setup for looping or one-shot playback
|
||||
if (!strcmp(mode,"looping")) {
|
||||
looping = 1;
|
||||
for (int j=0; j<channels; j++)
|
||||
data[length*channels+j] = data[j]; // extra sample for interpolation
|
||||
}
|
||||
else if (!strcmp(mode,"oneshot")) {
|
||||
looping = 0;
|
||||
for (int j=0; j<channels; j++)
|
||||
data[length*channels+j] = data[(length-1)*channels+j]; // extra sample for interpolation
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,"ERROR: Unsupported MatWvIn mode: %s\n",mode);
|
||||
free(data);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
rate = (MY_FLOAT) 1.0;
|
||||
interpolate = 0;
|
||||
time = (MY_FLOAT) 0.0;
|
||||
phaseOffset = (MY_FLOAT) 0.0;
|
||||
finished = 0;
|
||||
lastOutput = (MY_FLOAT *) calloc(channels, sizeof(MY_FLOAT));
|
||||
}
|
||||
|
||||
MatWvIn :: ~MatWvIn()
|
||||
{
|
||||
}
|
||||
189
STK/Modal4.cpp
189
STK/Modal4.cpp
@@ -1,189 +0,0 @@
|
||||
/*******************************************/
|
||||
/* 4 Resonance Modal Synthesis Instrument */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This instrument contains an excitation */
|
||||
/* wavetable, an envelope, and four reso- */
|
||||
/* nances (Non-Sweeping BiQuad Filters). */
|
||||
/*******************************************/
|
||||
|
||||
#include "Modal4.h"
|
||||
|
||||
Modal4 :: Modal4()
|
||||
{
|
||||
envelope = new Envelope;
|
||||
// We don't make the excitation wave here yet,
|
||||
// because we don't know what it's going to be.
|
||||
filters[0] = new BiQuad;
|
||||
filters[1] = new BiQuad;
|
||||
filters[2] = new BiQuad;
|
||||
filters[3] = new BiQuad;
|
||||
onepole = new OnePole;
|
||||
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
vibr = new RawWvIn(strcat(file,"rawwaves/sinewave.raw"),"looping");
|
||||
vibr->normalize();
|
||||
vibr->setFreq((MY_FLOAT) 6.0);
|
||||
vibrGain = (MY_FLOAT) 0.05;
|
||||
|
||||
directGain = (MY_FLOAT) 0.0;
|
||||
masterGain = (MY_FLOAT) 1.0;
|
||||
baseFreq = (MY_FLOAT) 440.0;
|
||||
this->setRatioAndReson(0,(MY_FLOAT) 1.00,(MY_FLOAT) 0.9997); /* Set some */
|
||||
this->setRatioAndReson(1,(MY_FLOAT) 1.30,(MY_FLOAT) 0.9997); /* silly */
|
||||
this->setRatioAndReson(2,(MY_FLOAT) 1.77,(MY_FLOAT) 0.9997); /* default */
|
||||
this->setRatioAndReson(3,(MY_FLOAT) 2.37,(MY_FLOAT) 0.9997); /* values here */
|
||||
this->setFiltGain(0,(MY_FLOAT) 0.01);
|
||||
this->setFiltGain(1,(MY_FLOAT) 0.01);
|
||||
this->setFiltGain(2,(MY_FLOAT) 0.01);
|
||||
this->setFiltGain(3,(MY_FLOAT) 0.01);
|
||||
this->clear();
|
||||
filters[0]->setEqualGainZeroes();
|
||||
filters[1]->setEqualGainZeroes();
|
||||
filters[2]->setEqualGainZeroes();
|
||||
filters[3]->setEqualGainZeroes();
|
||||
stickHardness = (MY_FLOAT) 0.5;
|
||||
strikePosition = (MY_FLOAT) 0.561;
|
||||
}
|
||||
|
||||
Modal4 :: ~Modal4()
|
||||
{
|
||||
delete envelope;
|
||||
delete filters[0];
|
||||
delete filters[1];
|
||||
delete filters[2];
|
||||
delete filters[3];
|
||||
delete onepole;
|
||||
delete vibr;
|
||||
}
|
||||
|
||||
void Modal4 :: clear()
|
||||
{
|
||||
onepole->clear();
|
||||
filters[0]->clear();
|
||||
filters[1]->clear();
|
||||
filters[2]->clear();
|
||||
filters[3]->clear();
|
||||
}
|
||||
|
||||
void Modal4 :: setFreq(MY_FLOAT frequency)
|
||||
{
|
||||
baseFreq = frequency;
|
||||
this->setRatioAndReson(0,ratios[0],resons[0]);
|
||||
this->setRatioAndReson(1,ratios[1],resons[1]);
|
||||
this->setRatioAndReson(2,ratios[2],resons[2]);
|
||||
this->setRatioAndReson(3,ratios[3],resons[3]);
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void Modal4 :: setRatioAndReson(int whichOne, MY_FLOAT ratio,MY_FLOAT reson)
|
||||
{
|
||||
MY_FLOAT temp;
|
||||
if (ratio*baseFreq < SRATE_OVER_TWO) {
|
||||
ratios[whichOne] = ratio;
|
||||
}
|
||||
else {
|
||||
temp = ratio;
|
||||
while (temp*baseFreq > SRATE_OVER_TWO) temp *= (MY_FLOAT) 0.5;
|
||||
ratios[whichOne] = temp;
|
||||
#if defined(_debug_)
|
||||
printf("Modal4 : Aliasing would occur here, correcting.\n");
|
||||
#endif
|
||||
}
|
||||
resons[whichOne] = reson;
|
||||
if (ratio<0)
|
||||
temp = -ratio;
|
||||
else
|
||||
temp = ratio*baseFreq;
|
||||
filters[whichOne]->setFreqAndReson(temp,reson);
|
||||
}
|
||||
|
||||
void Modal4 :: setMasterGain(MY_FLOAT aGain)
|
||||
{
|
||||
masterGain = aGain;
|
||||
}
|
||||
|
||||
void Modal4 :: setDirectGain(MY_FLOAT aGain)
|
||||
{
|
||||
directGain = aGain;
|
||||
}
|
||||
|
||||
void Modal4 :: setFiltGain(int whichOne, MY_FLOAT gain)
|
||||
{
|
||||
filters[whichOne]->setGain(gain);
|
||||
}
|
||||
|
||||
void Modal4 :: strike(MY_FLOAT amplitude)
|
||||
{
|
||||
int i;
|
||||
MY_FLOAT temp;
|
||||
envelope->setRate((MY_FLOAT) 1.0);
|
||||
envelope->setTarget(amplitude);
|
||||
onepole->setPole((MY_FLOAT) 1.0 - amplitude);
|
||||
envelope->tick();
|
||||
wave->reset();
|
||||
for (i=0;i<4;i++) {
|
||||
if (ratios[i] < 0)
|
||||
temp = -ratios[i];
|
||||
else
|
||||
temp = ratios[i] * baseFreq;
|
||||
filters[i]->setFreqAndReson(temp,resons[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Modal4 :: noteOn(MY_FLOAT freq, MY_FLOAT amp)
|
||||
{
|
||||
this->strike(amp);
|
||||
this->setFreq(freq);
|
||||
#if defined(_debug_)
|
||||
printf("Modal4 : NoteOn: Freq=%lf Amp=%lf\n",freq,amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Modal4 :: noteOff(MY_FLOAT amp) /* This calls damp, but inverts the */
|
||||
{ /* meaning of amplitude. */
|
||||
this->damp((MY_FLOAT) 1.0 - (amp * (MY_FLOAT) 0.03)); /* (high amplitude means fast damping) */
|
||||
#if defined(_debug_)
|
||||
printf("Modal4 : NoteOff: Amp=%lf\n",amp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Modal4 :: damp(MY_FLOAT amplitude)
|
||||
{
|
||||
int i;
|
||||
MY_FLOAT temp;
|
||||
for (i=0;i<4;i++) {
|
||||
if (ratios[i] < 0)
|
||||
temp = -ratios[i];
|
||||
else
|
||||
temp = ratios[i] * baseFreq;
|
||||
filters[i]->setFreqAndReson(temp,resons[i]*amplitude);
|
||||
}
|
||||
}
|
||||
|
||||
void Modal4 :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
}
|
||||
|
||||
MY_FLOAT Modal4 :: tick()
|
||||
{
|
||||
MY_FLOAT temp,temp2;
|
||||
temp = masterGain * onepole->tick(wave->tick() * envelope->tick());
|
||||
temp2 = filters[0]->tick(temp);
|
||||
temp2 += filters[1]->tick(temp);
|
||||
temp2 += filters[2]->tick(temp);
|
||||
temp2 += filters[3]->tick(temp);
|
||||
temp2 = temp2 - (temp2 * directGain);
|
||||
temp2 += directGain * temp;
|
||||
|
||||
if (vibrGain != 0.0) {
|
||||
temp = (MY_FLOAT) 1.0 + (vibr->tick() * vibrGain); /* Calculate AM */
|
||||
temp2 = temp * temp2; /* and apply to master out */
|
||||
}
|
||||
|
||||
lastOutput = temp2 * (MY_FLOAT) 2.0;
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
51
STK/Modal4.h
51
STK/Modal4.h
@@ -1,51 +0,0 @@
|
||||
/*******************************************/
|
||||
/* 4 Resonance Modal Synthesis Instrument */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* This instrument contains an excitation */
|
||||
/* wavetable, an envelope, and four reso- */
|
||||
/* nances (Non-Sweeping BiQuad Filters). */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__Modal4_h)
|
||||
#define __Modal4_h
|
||||
|
||||
#include "Instrmnt.h"
|
||||
#include "Envelope.h"
|
||||
#include "RawWvIn.h"
|
||||
#include "BiQuad.h"
|
||||
#include "OnePole.h"
|
||||
|
||||
class Modal4 : public Instrmnt
|
||||
{
|
||||
protected:
|
||||
Envelope *envelope;
|
||||
RawWvIn *wave;
|
||||
BiQuad *filters[4];
|
||||
OnePole *onepole;
|
||||
RawWvIn *vibr;
|
||||
MY_FLOAT vibrGain;
|
||||
MY_FLOAT masterGain;
|
||||
MY_FLOAT directGain;
|
||||
MY_FLOAT stickHardness;
|
||||
MY_FLOAT strikePosition;
|
||||
MY_FLOAT baseFreq;
|
||||
MY_FLOAT ratios[4];
|
||||
MY_FLOAT resons[4];
|
||||
public:
|
||||
Modal4();
|
||||
virtual ~Modal4();
|
||||
void clear();
|
||||
virtual void setFreq(MY_FLOAT frequency);
|
||||
void setRatioAndReson(int whichOne, MY_FLOAT ratio, MY_FLOAT reson);
|
||||
void setMasterGain(MY_FLOAT aGain);
|
||||
void setDirectGain(MY_FLOAT aGain);
|
||||
void setFiltGain(int whichOne, MY_FLOAT gain);
|
||||
virtual void strike(MY_FLOAT amplitude);
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
virtual void noteOff(MY_FLOAT amp);
|
||||
void damp(MY_FLOAT amplitude);
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
virtual MY_FLOAT tick();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,23 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Object Class, by Perry R. Cook, 1995-96*/
|
||||
/* This is mostly here for compatibility */
|
||||
/* with Objective C. We'll also stick */
|
||||
/* global defines here, so everyone will */
|
||||
/* see them. */
|
||||
/*******************************************/
|
||||
|
||||
#include "Object.h"
|
||||
// #include "byteswap.c"
|
||||
|
||||
/* This is just here for compatibility and convenience,
|
||||
so there's no need to do any real calculations.
|
||||
I do set up some redefinable variables here. */
|
||||
|
||||
Object :: Object()
|
||||
{
|
||||
}
|
||||
|
||||
Object :: ~Object()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
/*******************************************/
|
||||
/* One Pole Filter Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* The parameter gain is an additional */
|
||||
/* gain parameter applied to the filter */
|
||||
/* on top of the normalization that takes */
|
||||
/* place automatically. So the net max */
|
||||
/* gain through the system equals the */
|
||||
/* value of gain. sgain is the combina- */
|
||||
/* tion of gain and the normalization */
|
||||
/* parameter, so if you set the poleCoeff */
|
||||
/* to alpha, sgain is always set to */
|
||||
/* gain * (1.0 - fabs(alpha)). */
|
||||
/*******************************************/
|
||||
|
||||
#include "OnePole.h"
|
||||
|
||||
OnePole :: OnePole() : Filter()
|
||||
{
|
||||
poleCoeff = (MY_FLOAT) 0.9;
|
||||
gain = (MY_FLOAT) 1.0;
|
||||
sgain = (MY_FLOAT) 0.1;
|
||||
outputs = (MY_FLOAT *) malloc(sizeof(MY_FLOAT));
|
||||
outputs[0] = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
OnePole :: ~OnePole()
|
||||
{
|
||||
free(outputs);
|
||||
}
|
||||
|
||||
void OnePole :: clear()
|
||||
{
|
||||
outputs[0] = (MY_FLOAT) 0.0;
|
||||
lastOutput = (MY_FLOAT) 0.0;
|
||||
}
|
||||
|
||||
void OnePole :: setPole(MY_FLOAT aValue)
|
||||
{
|
||||
poleCoeff = aValue;
|
||||
if (poleCoeff > 0.0) // Normalize gain to 1.0 max
|
||||
sgain = gain * ((MY_FLOAT) 1.0 - poleCoeff);
|
||||
else
|
||||
sgain = gain * ((MY_FLOAT) 1.0 + poleCoeff);
|
||||
}
|
||||
|
||||
void OnePole :: setGain(MY_FLOAT aValue)
|
||||
{
|
||||
gain = aValue;
|
||||
if (poleCoeff > 0.0)
|
||||
sgain = gain * ((MY_FLOAT) 1.0 - poleCoeff); // Normalize gain to 1.0 max
|
||||
else
|
||||
sgain = gain * ((MY_FLOAT) 1.0 + poleCoeff);
|
||||
}
|
||||
|
||||
MY_FLOAT OnePole :: tick(MY_FLOAT sample) // Perform Filter Operation
|
||||
{
|
||||
outputs[0] = (sgain * sample) + (poleCoeff * outputs[0]);
|
||||
lastOutput = outputs[0];
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/*******************************************/
|
||||
/* One Pole Filter Class, */
|
||||
/* by Perry R. Cook, 1995-96 */
|
||||
/* The parameter gain is an additional */
|
||||
/* gain parameter applied to the filter */
|
||||
/* on top of the normalization that takes */
|
||||
/* place automatically. So the net max */
|
||||
/* gain through the system equals the */
|
||||
/* value of gain. sgain is the combina- */
|
||||
/* tion of gain and the normalization */
|
||||
/* parameter, so if you set the poleCoeff */
|
||||
/* to alpha, sgain is always set to */
|
||||
/* gain * (1.0 - fabs(alpha)). */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__OnePole_h)
|
||||
#define __OnePole_h
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
class OnePole : public Filter
|
||||
{
|
||||
protected:
|
||||
MY_FLOAT poleCoeff;
|
||||
MY_FLOAT sgain;
|
||||
public:
|
||||
OnePole();
|
||||
~OnePole();
|
||||
void clear();
|
||||
void setPole(MY_FLOAT aValue);
|
||||
void setGain(MY_FLOAT aValue);
|
||||
MY_FLOAT tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,965 +0,0 @@
|
||||
/******************************************/
|
||||
/* RTSoundIO.cpp */
|
||||
/* Realtime Sound I/O Object for STK, */
|
||||
/* by Gary P. Scavone, 1998-1999. */
|
||||
/* */
|
||||
/* The sound output sections of this */
|
||||
/* object were based in part on code */
|
||||
/* by Doug Scott (SGI), Tim Stilson */
|
||||
/* (Linux), Bill Putnam (Win Wav), and */
|
||||
/* R. Marsanyi (DirectSound). */
|
||||
/* */
|
||||
/* This object provides a standard API */
|
||||
/* across all platforms for STK realtime */
|
||||
/* audio input/output. The sound output */
|
||||
/* code is fairly robust. Audio input, */
|
||||
/* however, is more dependent on the */
|
||||
/* capabilities of the particular OS and */
|
||||
/* the soundcard being used. For the */
|
||||
/* moment, I'll try to provide 1 and 2 */
|
||||
/* channel support. */
|
||||
/* */
|
||||
/* 16-bit integer audio input/output */
|
||||
/* data is being assumed. */
|
||||
/******************************************/
|
||||
|
||||
#include "RTSoundIO.h"
|
||||
|
||||
#if (defined(__STK_REALTIME_) && defined(__OS_IRIX_))
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
RTSoundIO :: RTSoundIO(MY_FLOAT srate, int channels, char *mode)
|
||||
{
|
||||
ALconfig audio_port_config;
|
||||
int lookaheadbuffers = 8; // number of lookahead buffers
|
||||
long pvbuf[4];
|
||||
int nbuf, totalBufSize;
|
||||
|
||||
/* Check the number of channels */
|
||||
if (channels > 2) {
|
||||
fprintf(stderr,"RTSoundIO: Unsupported # of audio i/o channels: %d\n", channels);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Create ALconfig structure */
|
||||
audio_port_config = ALnewconfig();
|
||||
if (!audio_port_config) {
|
||||
fprintf(stderr,"Couldn't create ALconfig:%s\n", alGetErrorString(oserror()));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Configure channels */
|
||||
if(ALsetchannels(audio_port_config, channels) < 0) {
|
||||
fprintf(stderr,"Cannot configure channels: %s\n", alGetErrorString(oserror()));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Size the output queue */
|
||||
nbuf = (channels == 2) ? lookaheadbuffers : lookaheadbuffers/2;
|
||||
totalBufSize = RT_BUFFER_SIZE * nbuf;
|
||||
if(ALsetqueuesize(audio_port_config, totalBufSize) < 0) {
|
||||
fprintf(stderr,"Cannot configure output queue size: %s\n", alGetErrorString(oserror()));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (!strcmp(mode,"play")) { // playback only
|
||||
|
||||
/* Open the output audio port */
|
||||
audio_port_out = ALopenport("STK output port", "w", audio_port_config);
|
||||
if(!audio_port_out) {
|
||||
fprintf(stderr,"Cannot initialize output audio port: %s\n", alGetErrorString(oserror()));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Set sample rate parameters */
|
||||
pvbuf[0] = AL_OUTPUT_RATE;
|
||||
pvbuf[1] = (long) srate;
|
||||
ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 2); /* set output SR */
|
||||
|
||||
/* Tell port to accept refill at buffers - 1 */
|
||||
ALsetfillpoint(audio_port_out,RT_BUFFER_SIZE * (lookaheadbuffers - 1));
|
||||
audio_port_in = 0;
|
||||
}
|
||||
else if (!strcmp(mode,"record")) { // record only
|
||||
|
||||
/* Open the input audio port */
|
||||
audio_port_in = ALopenport("STK input port", "r", audio_port_config);
|
||||
if(!audio_port_in) {
|
||||
fprintf(stderr,"Cannot initialize input audio port: %s\n", alGetErrorString(oserror()));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Set sample rate parameters */
|
||||
pvbuf[0] = AL_OUTPUT_RATE;
|
||||
pvbuf[1] = (long) srate;
|
||||
ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 2); /* set input SR */
|
||||
|
||||
/* tell port to accept refill at buffers - 1 */
|
||||
ALsetfillpoint(audio_port_in,RT_BUFFER_SIZE * (lookaheadbuffers - 1));
|
||||
audio_port_out = 0;
|
||||
}
|
||||
else if (!strcmp(mode,"duplex")) { // duplex mode
|
||||
|
||||
/* Open the output audio port */
|
||||
audio_port_out = ALopenport("STK output port", "w", audio_port_config);
|
||||
if(!audio_port_out) {
|
||||
fprintf(stderr,"Cannot initialize output audio port: %s\n", alGetErrorString(oserror()));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Open the input audio port */
|
||||
audio_port_in = ALopenport("STK input port", "r", audio_port_config);
|
||||
if(!audio_port_in) {
|
||||
fprintf(stderr,"Cannot initialize input audio port: %s\n", alGetErrorString(oserror()));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Set sample rate parameters */
|
||||
pvbuf[0] = AL_OUTPUT_RATE;
|
||||
pvbuf[1] = (long) srate;
|
||||
pvbuf[2] = AL_INPUT_RATE;
|
||||
pvbuf[3] = (long) srate;
|
||||
ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 4); /* set output SR */
|
||||
/* tell port to accept refill at buffers - 1 */
|
||||
ALsetfillpoint(audio_port_out,RT_BUFFER_SIZE * (lookaheadbuffers - 1));
|
||||
ALsetfillpoint(audio_port_in,RT_BUFFER_SIZE * (lookaheadbuffers - 1));
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,"Unsupported RTSoundIO mode: %s\n",mode);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
ALfreeconfig(audio_port_config);
|
||||
audio_port_config = 0;
|
||||
}
|
||||
|
||||
RTSoundIO :: ~RTSoundIO()
|
||||
{
|
||||
if(audio_port_out) ALcloseport(audio_port_out);
|
||||
audio_port_out=0;
|
||||
|
||||
if(audio_port_in) ALcloseport(audio_port_in);
|
||||
audio_port_in=0;
|
||||
}
|
||||
|
||||
int RTSoundIO :: playBuffer(short *buf, int bufsize)
|
||||
{
|
||||
ALwritesamps(audio_port_out, buf, bufsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RTSoundIO :: recordBuffer(short *buf, int bufsize)
|
||||
{
|
||||
ALreadsamps(audio_port_in, buf, bufsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Linux OSS Sound API here */
|
||||
|
||||
#elif (defined(__STK_REALTIME_) && defined(__OSS_API_))
|
||||
|
||||
#define ABS(x) ((x < 0) ? (-x) : (x))
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/soundcard.h>
|
||||
|
||||
RTSoundIO :: RTSoundIO(MY_FLOAT srate, int channels, char *mode)
|
||||
{
|
||||
int lookaheadbuffers = 8; // number of lookahead buffers
|
||||
int nbuf;
|
||||
|
||||
char DEVICE_NAME[100];
|
||||
int format;
|
||||
int stereo; /* 0=mono, 1=stereo */
|
||||
int stereoset;
|
||||
int speed;
|
||||
int BUFFER_SIZE_LOG;
|
||||
int fragsize;
|
||||
|
||||
BUFFER_SIZE_LOG = (int)(log10((double)RT_BUFFER_SIZE)/log10(2.0));
|
||||
|
||||
/* Check the number of channels */
|
||||
if (channels > 2) {
|
||||
fprintf(stderr,"RTSoundIO: Unsupported # of audio i/o channels: %d\n", channels);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (channels == 2) stereo = 1;
|
||||
else stereo = 0;
|
||||
|
||||
strcpy(DEVICE_NAME,"/dev/dsp");
|
||||
|
||||
if (!strcmp(mode,"play")) { // playback only
|
||||
if ((audio_fd = open(DEVICE_NAME, O_WRONLY, 0)) == -1)
|
||||
{ /* Opening device failed */
|
||||
fprintf(stderr,"Cannot open audio device: %s\n",DEVICE_NAME);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(mode,"record")) { // record only
|
||||
if ((audio_fd = open(DEVICE_NAME, O_RDONLY, 0)) == -1)
|
||||
{ /* Opening device failed */
|
||||
fprintf(stderr,"Cannot open audio device: %s\n",DEVICE_NAME);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(mode,"duplex")) { // duplex mode
|
||||
if ((audio_fd = open(DEVICE_NAME, O_RDWR, 0)) == -1)
|
||||
{ /* Opening device failed */
|
||||
fprintf(stderr,"Cannot open audio device: %s\n",DEVICE_NAME);
|
||||
exit(0);
|
||||
}
|
||||
int caps;
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_GETCAPS, &caps))
|
||||
{
|
||||
close(audio_fd);
|
||||
fprintf(stderr,"Error getting device capabilities: %s\n",DEVICE_NAME);
|
||||
exit(0);
|
||||
}
|
||||
if (!(caps & DSP_CAP_DUPLEX))
|
||||
{
|
||||
close(audio_fd);
|
||||
fprintf(stderr,"Audio device does not support duplex mode: %s\n",DEVICE_NAME);
|
||||
exit(0);
|
||||
}
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_SETDUPLEX, 0))
|
||||
{
|
||||
close(audio_fd);
|
||||
fprintf(stderr,"Error setting duplex mode: %s\n",DEVICE_NAME);
|
||||
exit(0);
|
||||
}
|
||||
int cursrc, srcbit = SOUND_MASK_MIC;
|
||||
ioctl(audio_fd, MIXER_READ(SOUND_MIXER_RECSRC),&cursrc);
|
||||
srcbit = (srcbit & cursrc);
|
||||
ioctl(audio_fd,MIXER_WRITE(SOUND_MIXER_RECSRC),&srcbit);
|
||||
|
||||
// The following opens a direct analog line from the mic to the output
|
||||
//srcbit = 99;
|
||||
//ioctl(audio_fd,MIXER_WRITE(SOUND_MIXER_IMIX),&srcbit);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,"Unsupported RTSoundIO mode: %s\n",mode);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Size the output queue */
|
||||
nbuf = (channels == 2) ? lookaheadbuffers : lookaheadbuffers/2;
|
||||
|
||||
fragsize = (nbuf << 16) + BUFFER_SIZE_LOG;
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &fragsize))
|
||||
{
|
||||
close(audio_fd);
|
||||
fprintf(stderr,"Error setting audio buffer size!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
format = AFMT_S16_LE;
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format)==-1)
|
||||
{ /* Fatal error */
|
||||
close(audio_fd);
|
||||
fprintf(stderr,"SNDCTL_DSP_SETFMT error\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (format != AFMT_S16_LE)
|
||||
{
|
||||
close(audio_fd);
|
||||
fprintf(stderr,"Audio device doesn't support 16-bit signed LE format\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
stereoset = stereo;
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereoset)==-1)
|
||||
{ /* Fatal error */
|
||||
close(audio_fd);
|
||||
fprintf(stderr,"SNDCTL_DSP_STEREO\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (stereoset != stereo)
|
||||
{
|
||||
close(audio_fd);
|
||||
fprintf(stderr,"The audio device did not set correct stereo mode: %s\n",DEVICE_NAME);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
speed = (int)srate;
|
||||
if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &speed)==-1)
|
||||
{ /* Fatal error */
|
||||
close(audio_fd);
|
||||
fprintf(stderr,"SNDCTL_DSP_SPEED\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (ABS(speed - srate)>100)
|
||||
{
|
||||
close(audio_fd);
|
||||
fprintf(stderr,"The device doesn't support the requested speed.\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
RTSoundIO :: ~RTSoundIO()
|
||||
{
|
||||
if(audio_fd) close(audio_fd);
|
||||
audio_fd=0;
|
||||
}
|
||||
|
||||
int RTSoundIO :: playBuffer(short *buf, int bufsize)
|
||||
{
|
||||
/* The OSS write() routine takes the buffer size in bytes, thus the
|
||||
multiplication by two.
|
||||
*/
|
||||
int len;
|
||||
|
||||
if ((len = write(audio_fd, buf, 2*bufsize)) == -1)
|
||||
{
|
||||
fprintf(stderr,"Audio write error!\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RTSoundIO :: recordBuffer(short *buf, int bufsize)
|
||||
{
|
||||
/* The OSS read() routine takes the buffer size in bytes, thus the
|
||||
multiplication by two.
|
||||
*/
|
||||
int len;
|
||||
|
||||
if ((len = read(audio_fd, buf, 2*bufsize)) == -1)
|
||||
{
|
||||
fprintf(stderr,"Audio read error!\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#elif (defined(__STK_REALTIME_) && defined(__WINDS_API_) )
|
||||
/*
|
||||
* AUDIO OUTPUT:
|
||||
*
|
||||
* There are two ways (or more) to go about handling sound output
|
||||
* under DirectSound. For minimum latency, one should write new
|
||||
* buffers in front of the read pointer (Method 1). The other
|
||||
* method is to always write new buffers of data behind the read
|
||||
* pointer (Method 2). Method 2 is very safe but inherently
|
||||
* produces a delay equivalent to the entire sound buffer (plus
|
||||
* any other delays that Microsloth provides). Even using
|
||||
* Method 1, however, Microsloth requires that you leave about
|
||||
* 15 ms of buffer between the read and write pointers. I've tried
|
||||
* both methods and neither results in performance that can compare
|
||||
* to either Linux or SGI sound output. In order to minimize
|
||||
* latency, however, I'll go with Method 1 and leave Method 2
|
||||
* commented out below.
|
||||
*
|
||||
* If the primary sound buffer exists in hardware, I will write
|
||||
* directly to it. If the primary sound buffer is emulated in
|
||||
* software, this is not possible and we must use a secondary buffer.
|
||||
*
|
||||
* AUDIO INPUT:
|
||||
*
|
||||
* I didn't spend a lot of time doing the audio input code. I
|
||||
* basically got it working, heard that it had noticeable delay,
|
||||
* but didn't try screwing around to minimize that delay. I provide
|
||||
* a single variable (at the beginning of the Capture initialization)
|
||||
* which controls the size of the DirectSound Capture buffer, which
|
||||
* in turn controls the latency.
|
||||
*
|
||||
* The DirectSoundCapture API is only available with DirectX versions
|
||||
* 5.0 and higher. If you don't have such capabilities (ex. WinNT),
|
||||
* then use the WinMM API code (uncomment the __WINMM_API_ define
|
||||
* statement in Object.h and comment out the __WINDS_API_ flag). This
|
||||
* will allow you to still compile STK, but without the audio input
|
||||
* capabilities.
|
||||
*/
|
||||
|
||||
#define DS_WRITE_METHOD 1
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
RTSoundIO :: RTSoundIO(MY_FLOAT srate, int channels, char *mode)
|
||||
{
|
||||
HRESULT result;
|
||||
WAVEFORMATEX wfFormat;
|
||||
BYTE *pAudioPtr;
|
||||
DWORD dwDataLen;
|
||||
|
||||
// Initialize the DirectSound object and buffer pointers to NULL
|
||||
lpDirectSound = NULL;
|
||||
lpDSBuffer = NULL;
|
||||
lpDSCapture = NULL;
|
||||
lpDSCBuffer = NULL;
|
||||
|
||||
// Define the wave format structure (16-bit PCM, srate, channels)
|
||||
ZeroMemory(&wfFormat, sizeof(WAVEFORMATEX));
|
||||
wfFormat.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfFormat.nChannels = channels;
|
||||
wfFormat.nSamplesPerSec = (unsigned long) srate;
|
||||
wfFormat.wBitsPerSample = 8 * sizeof(short);
|
||||
wfFormat.nBlockAlign = wfFormat.nChannels * wfFormat.wBitsPerSample / 8;
|
||||
wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
|
||||
|
||||
if ( (!strcmp(mode,"play")) || (!strcmp(mode,"duplex")) ) {
|
||||
DSBUFFERDESC dsbdesc;
|
||||
HWND hWnd;
|
||||
|
||||
// If using Method 1:
|
||||
// Define a maximum distance that the write pointer is
|
||||
// allowed to lead safePos. The size of this zone is
|
||||
// fairly critical to the behavior of this scheme. The
|
||||
// value below is set for a 15 millisecond region.
|
||||
zoneSize = (DWORD) (0.015 * srate * sizeof(short)); // bytes
|
||||
|
||||
// Create the DS object
|
||||
if ((result = DirectSoundCreate(NULL, &lpDirectSound, NULL)) != DS_OK) {
|
||||
fprintf(stderr,"RTSoundIO: Cannot open default sound output device!!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Get DS device capabilites
|
||||
DSCAPS dscaps;
|
||||
ZeroMemory(&dscaps, sizeof(DSCAPS));
|
||||
dscaps.dwSize = sizeof(DSCAPS);
|
||||
if ((result = lpDirectSound->GetCaps(&dscaps)) != DS_OK) {
|
||||
fprintf(stderr,"RTSoundIO: Cannot get DS device capabilities!!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Determine whether primary buffer exists in hardware or software
|
||||
if (dscaps.dwFlags & DSCAPS_EMULDRIVER) { // Write to secondary buffer
|
||||
|
||||
// Number of buffers of size RT_BUFFER_SIZE to make secondary
|
||||
// DS buffer. A larger secondary buffer does NOT produce more
|
||||
// output delay when the write pointer is kept in front of the
|
||||
// read pointer (Method 1). However, if you use Method 2, this
|
||||
// variable will be more critical and you'll probably want to
|
||||
// make it smaller.
|
||||
int nBufs = 12;
|
||||
|
||||
// Set coooperative level
|
||||
hWnd = GetForegroundWindow();
|
||||
if ((result = lpDirectSound->SetCooperativeLevel(hWnd, DSSCL_EXCLUSIVE)) != DS_OK) {
|
||||
fprintf(stderr,"RTSoundIO: Couldn't set EXCLUSIVE cooperative level!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Even though we will write to the secondary buffer, we need
|
||||
// to access the primary buffer to set the correct output format.
|
||||
// The default is 8-bit, 22 kHz!
|
||||
LPDIRECTSOUNDBUFFER lpdsbPrimary;
|
||||
|
||||
// Setup the DS primary buffer description.
|
||||
ZeroMemory(&dsbdesc, sizeof(DSBUFFERDESC));
|
||||
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
|
||||
dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
|
||||
|
||||
// Obtain the primary buffer
|
||||
if ((result = lpDirectSound->CreateSoundBuffer(&dsbdesc,
|
||||
&lpdsbPrimary, NULL)) != DS_OK) {
|
||||
fprintf(stderr,"RTSoundIO: Cannot get the primary DS buffer address!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Set the primary DS buffer sound format.
|
||||
if ((result = lpdsbPrimary->SetFormat(&wfFormat)) != DS_OK) {
|
||||
fprintf(stderr,"RTSoundIO: Cannot set the primary DS buffer to proper sound format!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Setup the secondary DS buffer description.
|
||||
dwDSBufSize = RT_BUFFER_SIZE * sizeof(short) * nBufs;
|
||||
ZeroMemory(&dsbdesc, sizeof(DSBUFFERDESC));
|
||||
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
|
||||
dsbdesc.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2;
|
||||
dsbdesc.dwBufferBytes = dwDSBufSize;
|
||||
dsbdesc.lpwfxFormat = &wfFormat;
|
||||
|
||||
// Try to create the secondary DS buffer.
|
||||
if ((result = lpDirectSound->CreateSoundBuffer(&dsbdesc, &lpDSBuffer, NULL)) != DS_OK) {
|
||||
fprintf(stderr,"RTSoundIO: Couldn't create the DS sound buffer!\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
else { // Write to primary buffer
|
||||
|
||||
// Setup the DS primary buffer description.
|
||||
ZeroMemory(&dsbdesc, sizeof(DSBUFFERDESC));
|
||||
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
|
||||
dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_STICKYFOCUS;
|
||||
// Buffer size is determined by sound hardware
|
||||
dsbdesc.dwBufferBytes = 0;
|
||||
dsbdesc.lpwfxFormat = NULL; // Must be NULL for primary buffer.
|
||||
|
||||
// Obtain write-primary coooperative level.
|
||||
hWnd = GetForegroundWindow();
|
||||
if ((result = lpDirectSound->SetCooperativeLevel(hWnd, DSSCL_WRITEPRIMARY)) != DS_OK) {
|
||||
fprintf(stderr,"RTSoundIO: Couldn't set WRITEPRIMARY cooperative level!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Try to create the primary DS buffer.
|
||||
if ((result = lpDirectSound->CreateSoundBuffer(&dsbdesc, &lpDSBuffer, NULL)) != DS_OK) {
|
||||
fprintf(stderr,"RTSoundIO: Couldn't create the DS sound buffer!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Set primary DS buffer to desired format.
|
||||
if ((result = lpDSBuffer->SetFormat(&wfFormat)) != DS_OK) {
|
||||
fprintf(stderr,"RTSoundIO: Couldn't set correct format!\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
// Get the buffer size
|
||||
DSBCAPS dsbcaps;
|
||||
dsbcaps.dwSize = sizeof(DSBCAPS);
|
||||
lpDSBuffer->GetCaps(&dsbcaps);
|
||||
dwDSBufSize = dsbcaps.dwBufferBytes;
|
||||
|
||||
// Lock the DS buffer
|
||||
if ((result = lpDSBuffer->Lock(0, dwDSBufSize, (LPLPVOID) &pAudioPtr, &dwDataLen, NULL, NULL, 0)) != DS_OK) {
|
||||
fprintf(stderr,"RTSoundIO: Couldn't lock DS sound buffer!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Zero the DS buffer
|
||||
ZeroMemory(pAudioPtr, dwDataLen);
|
||||
|
||||
// Unlock the DS buffer
|
||||
if ((result = lpDSBuffer->Unlock(pAudioPtr, dwDataLen, NULL, 0)) != DS_OK) {
|
||||
fprintf(stderr,"RTSoundIO: Couldn't unlock DS sound buffer!\n");
|
||||
exit(0);
|
||||
}
|
||||
} // end of play/duplex initialization
|
||||
|
||||
if ( (!strcmp(mode,"record")) || (!strcmp(mode,"duplex")) ) {
|
||||
// DirectSound Capture capabilities require DirectX 5.0 or higher
|
||||
|
||||
// The following variable controls the size of the DS Capture
|
||||
// buffer, which in turns controls the latency in the capture
|
||||
// process. When dscbufscale = 1, the buffer is equivalent to
|
||||
// one second of audio. A dscbufscale = 0.5 halves this value.
|
||||
// Likewise, a dscbufscale = 2 doubles this value. It seems to
|
||||
// work OK with dscbufscale = 0.5, but there is a periodic
|
||||
// "clicking" which sometimes occurs. You can go lower, but
|
||||
// the "clicking" gets worse. Good luck! Yet another reason
|
||||
// why not to use Windoze.
|
||||
float dscbufscale = 0.5;
|
||||
|
||||
// Create the DS Capture object
|
||||
if ((result = DirectSoundCaptureCreate(NULL, &lpDSCapture, NULL)) != DS_OK) {
|
||||
fprintf(stderr,"RTSoundIO: Couldn't open DirectSoundCapture Object!\n");
|
||||
fprintf(stderr,"RTSoundIO: Requires DirectX 5 or later.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Setup the DS Capture buffer description
|
||||
DSCBUFFERDESC dscbdesc;
|
||||
ZeroMemory(&dscbdesc, sizeof(DSCBUFFERDESC));
|
||||
dscbdesc.dwSize = sizeof(DSCBUFFERDESC);
|
||||
dscbdesc.dwFlags = 0;
|
||||
// Control size of DS Capture buffer here
|
||||
dwDSCBufSize = (DWORD)(wfFormat.nAvgBytesPerSec*dscbufscale);
|
||||
dscbdesc.dwBufferBytes = dwDSCBufSize;
|
||||
dscbdesc.dwReserved = 0;
|
||||
dscbdesc.lpwfxFormat = &wfFormat;
|
||||
|
||||
// Create the DS Capture buffer
|
||||
if ((result = lpDSCapture->CreateCaptureBuffer(&dscbdesc, &lpDSCBuffer, NULL)) != DS_OK) {
|
||||
fprintf(stderr,"RTSoundIO: Couldn't create DirectSoundCapture buffer!\n");
|
||||
if (result == DSERR_BADFORMAT) {
|
||||
fprintf(stderr,"RTSoundIO: The input device could not support the desired\n");
|
||||
fprintf(stderr,"sample rate (%f), bits per sample (16),\n", srate);
|
||||
fprintf(stderr,"and/or number of channels (%d).\n", channels);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Lock the DS Capture buffer
|
||||
if ((result = lpDSCBuffer->Lock(0, dwDSCBufSize, (LPLPVOID) &pAudioPtr, &dwDataLen, NULL, NULL, 0)) != DS_OK) {
|
||||
fprintf(stderr,"RTSoundIO: Couldn't lock DS Capture sound buffer!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Zero the DS Capture buffer
|
||||
ZeroMemory(pAudioPtr, dwDataLen);
|
||||
|
||||
// Unlock the DS Capture buffer
|
||||
if ((result = lpDSCBuffer->Unlock(pAudioPtr, dwDataLen, NULL, 0)) != DS_OK) {
|
||||
fprintf(stderr,"RTSoundIO: Couldn't unlock DS Capture sound buffer!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Start the DS Capture buffer input
|
||||
if ((result = lpDSCBuffer->Start(DSCBSTART_LOOPING) != DS_OK)) {
|
||||
fprintf(stderr,"RTSoundIO: Couldn't start DS Capture sound input!\n");
|
||||
exit(0);
|
||||
}
|
||||
} // end of record/duplex initialization
|
||||
|
||||
if ( (!strcmp(mode,"play")) || (!strcmp(mode,"duplex")) ) {
|
||||
// Start the DS buffer playback
|
||||
if ((result = lpDSBuffer->Play(0, 0, DSBPLAY_LOOPING ) != DS_OK)) {
|
||||
fprintf(stderr,"RTSoundIO: Couldn't play DS sound buffer!\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RTSoundIO :: ~RTSoundIO()
|
||||
{
|
||||
// Cleanup the DS buffers
|
||||
if (lpDSBuffer) {
|
||||
lpDSBuffer->Stop();
|
||||
lpDSBuffer->Release();
|
||||
lpDSBuffer = NULL;
|
||||
}
|
||||
if (lpDSCBuffer) {
|
||||
lpDSCBuffer->Stop();
|
||||
lpDSCBuffer->Release();
|
||||
lpDSCBuffer = NULL;
|
||||
}
|
||||
|
||||
// Cleanup the DS objects
|
||||
if (lpDirectSound) {
|
||||
lpDirectSound->Release();
|
||||
lpDirectSound = NULL;
|
||||
}
|
||||
if (lpDSCapture) {
|
||||
lpDSCapture->Release();
|
||||
lpDSCapture = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int RTSoundIO :: playBuffer(short *buf, int bufsize)
|
||||
{
|
||||
HRESULT hr;
|
||||
LPVOID lpbuf1 = NULL;
|
||||
LPVOID lpbuf2 = NULL;
|
||||
DWORD dwsize1 = 0;
|
||||
DWORD dwsize2 = 0;
|
||||
DWORD playPos, safePos;
|
||||
static UINT nextWritePos = 0;
|
||||
|
||||
// Find out where the read and "safe write" pointers are.
|
||||
hr = lpDSBuffer->GetCurrentPosition(&playPos, &safePos);
|
||||
if (hr != DS_OK) return -1;
|
||||
|
||||
// METHOD 1: Keep write pointer in front of read pointer.
|
||||
//
|
||||
// Microsloth says that the safePos is about 15 ms ahead of
|
||||
// playPos. I think this figure is somewhat hardware related,
|
||||
// especially if you are writing to the primary buffer. With
|
||||
// my shit-blaster 16, I found the safePos to be about 10 ms
|
||||
// ahead of playPos. If you really need to reduce delay, you
|
||||
// can try moving your "safePos" closer to the play pointer.
|
||||
// You'll be treading on dangerous ground, but then again,
|
||||
// you're obviously using Windoze so you're already familiar
|
||||
// with such uncertainty! I've been able to lop off 2-5 ms
|
||||
// in some circumstances.
|
||||
//static DWORD backup = (DWORD) (0.005 * SRATE * sizeof(short));
|
||||
//safePos = (safePos + dwDSBufSize - backup) % dwDSBufSize;
|
||||
|
||||
// Assume that the next write position is always in front
|
||||
// of safePos. If not, the write pointer must have wrapped.
|
||||
// NOTE: If safePos somehow gets ahead of the write pointer,
|
||||
// then an underrun has occurred and there's not much we can
|
||||
// do anyway.
|
||||
DWORD deltaPos;
|
||||
if( safePos > nextWritePos )
|
||||
deltaPos = nextWritePos + dwDSBufSize - safePos;
|
||||
else
|
||||
deltaPos = nextWritePos - safePos;
|
||||
|
||||
// Check whether the write pointer is in the allowed region.
|
||||
while ( deltaPos > zoneSize ) {
|
||||
// If we are here, then we must wait until the write pointer
|
||||
// is in the allowed region. For this, we can either
|
||||
// continuously check the pointer positions until they are
|
||||
// OK or we can use the Sleep() function to pause operations
|
||||
// for a certain amount of time. Use of the Sleep() function
|
||||
// would seem to be the better choice, however, there are
|
||||
// reports that Sleep() often "sleeps" for much longer than
|
||||
// requested. I'll let you choose which method to use.
|
||||
static int sleep = 1; // 1 = sleep, 0 = don't sleep
|
||||
|
||||
if (sleep) {
|
||||
// Sleep until safePos catches up. Calculate number of
|
||||
// milliseconds to wait as:
|
||||
// time = distance * (milliseconds/second) * fudgefactor /
|
||||
// ((bytes/sample) * (samples/second))
|
||||
// A "fudgefactor" less than 1 is used because it was found
|
||||
// that sleeping too long was MUCH worse than sleeping for
|
||||
// several shorter periods.
|
||||
DWORD millis = (DWORD) ((deltaPos * 200.0) / ( sizeof(short) * SRATE));
|
||||
|
||||
// Sleep for that long
|
||||
Sleep( millis );
|
||||
}
|
||||
|
||||
// Wake up, find out where we are now
|
||||
hr = lpDSBuffer->GetCurrentPosition( &playPos, &safePos );
|
||||
if( hr != DS_OK ) return -1;
|
||||
|
||||
// Backup safePos? (See above)
|
||||
//safePos = (safePos + dwDSBufSize - backup) % dwDSBufSize;
|
||||
|
||||
if( safePos > nextWritePos )
|
||||
deltaPos = nextWritePos + dwDSBufSize - safePos;
|
||||
else
|
||||
deltaPos = nextWritePos - safePos;
|
||||
}
|
||||
// End of Method 1
|
||||
|
||||
/*
|
||||
// METHOD 2: Keep write region behind of play pointer.
|
||||
if( playPos < nextWritePos ) playPos += dwDSBufSize; // unwrap offset
|
||||
DWORD endWrite = nextWritePos + bufsize * sizeof(short);
|
||||
|
||||
// Check whether the write region is behind the play pointer.
|
||||
while ( playPos < endWrite ) {
|
||||
// If we are here, then we must wait until the play pointer
|
||||
// gets beyond the write region. For this, we can either
|
||||
// continuously check the pointer positions until they are
|
||||
// OK or we can use the Sleep() function to pause operations
|
||||
// for a certain amount of time. Use of the Sleep() function
|
||||
// would seem to be the better choice, however, there are
|
||||
// reports that Sleep() often "sleeps" for much longer than
|
||||
// requested. I'll let you choose which method to use.
|
||||
static int sleep = 1; // 1 = sleep, 0 = don't sleep
|
||||
|
||||
if (sleep) {
|
||||
// Sleep until safePos catches up. Calculate number of
|
||||
// milliseconds to wait as:
|
||||
// time = distance * (milliseconds/second) * fudgefactor /
|
||||
// ((bytes/sample) * (samples/second))
|
||||
// A "fudgefactor" less than 1 is used because it was found
|
||||
// that sleeping too long was MUCH worse than sleeping for
|
||||
// several shorter periods.
|
||||
DWORD millis = (DWORD) (((endWrite - playPos) * 200.0) / ( sizeof(short) * SRATE));
|
||||
|
||||
// Sleep for that long
|
||||
Sleep( millis );
|
||||
}
|
||||
|
||||
// Wake up, find out where we are now
|
||||
hr = lpDSBuffer->GetCurrentPosition( &playPos, &safePos );
|
||||
if( hr != DS_OK ) return -1;
|
||||
if( playPos < nextWritePos ) playPos += dwDSBufSize; // unwrap offset
|
||||
}
|
||||
// End of Method 2.
|
||||
*/
|
||||
|
||||
// Lock free space in the DS
|
||||
hr = lpDSBuffer->Lock (nextWritePos, bufsize * sizeof(short), &lpbuf1, &dwsize1, &lpbuf2, &dwsize2, 0);
|
||||
if (hr == DS_OK) {
|
||||
// Copy the buffer into the DS
|
||||
CopyMemory(lpbuf1, buf, dwsize1);
|
||||
if(NULL != lpbuf2) CopyMemory(lpbuf2, buf+dwsize1, dwsize2);
|
||||
|
||||
// Update our buffer offset and unlock sound buffer
|
||||
nextWritePos = (nextWritePos + dwsize1 + dwsize2) % dwDSBufSize;
|
||||
lpDSBuffer->Unlock (lpbuf1, dwsize1, lpbuf2, dwsize2);
|
||||
return 0;
|
||||
}
|
||||
else return -1;
|
||||
}
|
||||
|
||||
int RTSoundIO :: recordBuffer(short *buf, int bufsize)
|
||||
{
|
||||
HRESULT hr;
|
||||
LPVOID lpbuf1 = NULL;
|
||||
LPVOID lpbuf2 = NULL;
|
||||
DWORD dwsize1 = 0;
|
||||
DWORD dwsize2 = 0;
|
||||
DWORD capPos, safePos;
|
||||
static UINT nextReadPos = 0;
|
||||
|
||||
// Find out where the write and "safe read" pointers are.
|
||||
hr = lpDSCBuffer->GetCurrentPosition(&capPos, &safePos);
|
||||
if (hr != DS_OK) return -1;
|
||||
//printf("capPos = %d, safePos = %d\n", capPos, safePos);
|
||||
|
||||
if( safePos < nextReadPos ) safePos += dwDSCBufSize; // unwrap offset
|
||||
DWORD endRead = nextReadPos + bufsize * sizeof(short);
|
||||
//printf("endRead = %d\n", endRead);
|
||||
|
||||
// Check whether the read region is behind the capture pointer.
|
||||
while ( safePos < endRead ) {
|
||||
// If we are here, then we must wait until the read pointer
|
||||
// gets beyond the write region. For this, we can either
|
||||
// continuously check the pointer positions until they are
|
||||
// OK or we can use the Sleep() function to pause operations
|
||||
// for a certain amount of time. Use of the Sleep() function
|
||||
// would seem to be the better choice, however, there are
|
||||
// reports that Sleep() often "sleeps" for much longer than
|
||||
// requested. I'll let you choose which method to use.
|
||||
static int sleep = 1; // 1 = sleep, 0 = don't sleep
|
||||
|
||||
if (sleep) {
|
||||
// Sleep until safePos catches up. Calculate number of
|
||||
// milliseconds to wait as:
|
||||
// time = distance * (milliseconds/second) * fudgefactor /
|
||||
// ((bytes/sample) * (samples/second))
|
||||
// A "fudgefactor" less than 1 is used because it was found
|
||||
// that sleeping too long was MUCH worse than sleeping for
|
||||
// several shorter periods.
|
||||
DWORD millis = (DWORD) (((endRead - safePos) * 200.0) / ( sizeof(short) * SRATE));
|
||||
|
||||
// Sleep for that long
|
||||
Sleep( millis );
|
||||
}
|
||||
|
||||
// Wake up, find out where we are now
|
||||
hr = lpDSCBuffer->GetCurrentPosition( &capPos, &safePos );
|
||||
if( hr != DS_OK ) return -1;
|
||||
//printf("capPos = %d, safePos = %d\n", capPos, safePos);
|
||||
if( safePos < nextReadPos ) safePos += dwDSCBufSize; // unwrap offset
|
||||
}
|
||||
//printf("how about here?\n");
|
||||
// Lock free space in the DS Capture buffer
|
||||
hr = lpDSCBuffer->Lock(nextReadPos, bufsize * sizeof(short), &lpbuf1, &dwsize1, &lpbuf2, &dwsize2, 0);
|
||||
if (hr == DS_OK) {
|
||||
// Copy the DS Capture data to the buffer
|
||||
CopyMemory(buf, lpbuf1, dwsize1);
|
||||
if(NULL != lpbuf2) CopyMemory(buf+dwsize1, lpbuf2, dwsize2);
|
||||
|
||||
// Update our buffer offset and unlock sound buffer
|
||||
nextReadPos = (nextReadPos + dwsize1 + dwsize2) % dwDSCBufSize;
|
||||
lpDSCBuffer->Unlock (lpbuf1, dwsize1, lpbuf2, dwsize2);
|
||||
return 0;
|
||||
}
|
||||
else return -1;
|
||||
}
|
||||
|
||||
#elif (defined(__STK_REALTIME_) && defined(__WINMM_API_) )
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define FRAMETIME (long) (1000.0 * RT_BUFFER_SIZE / SRATE)
|
||||
|
||||
RTSoundIO :: RTSoundIO(MY_FLOAT srate, int channels, char *mode)
|
||||
{
|
||||
MMRESULT result;
|
||||
WAVEFORMATEX wfx;
|
||||
int bufferSize = RT_BUFFER_SIZE;
|
||||
|
||||
audioPort = NULL;
|
||||
|
||||
if ( (!strcmp(mode,"record")) || (!strcmp(mode,"duplex")) ) {
|
||||
fprintf(stderr,"Sorry ... no audio input support under WinMM API!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
wfx.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx.nChannels = channels;
|
||||
wfx.nSamplesPerSec = (unsigned long) srate;
|
||||
wfx.nBlockAlign = sizeof(short) * channels;
|
||||
wfx.nAvgBytesPerSec = (unsigned long) srate * wfx.nBlockAlign;
|
||||
wfx.wBitsPerSample = 8 * sizeof(short);
|
||||
wfx.cbSize = 0;
|
||||
|
||||
/* Open a Wave Out device using the wave mapper to guide us */
|
||||
result = waveOutOpen(&audioPort,WAVE_MAPPER,&wfx,(DWORD)NULL,(DWORD)NULL,CALLBACK_NULL);
|
||||
if (result != MMSYSERR_NOERROR) {
|
||||
fprintf(stderr,"RTSoundIO: Cannot open audio port (WinMM API)!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for( outBufNum = 0; outBufNum < (UINT)NUM_OUT_BUFFERS; outBufNum++ )
|
||||
{
|
||||
/* set up a couple of wave headers */
|
||||
whOut[outBufNum].lpData = (LPSTR)calloc(channels*bufferSize, sizeof(short));
|
||||
if (whOut[outBufNum].lpData == NULL){
|
||||
waveOutClose( audioPort );
|
||||
fprintf(stderr,"RTSoundIO: Error initializing audio buffers (WinMM API)!\n");
|
||||
exit(0);
|
||||
}
|
||||
whOut[outBufNum].dwBufferLength = channels*bufferSize*sizeof(short);
|
||||
whOut[outBufNum].dwBytesRecorded = 0;
|
||||
whOut[outBufNum].dwUser = 1;
|
||||
//whOut[outBufNum].dwFlags = 0;
|
||||
whOut[outBufNum].dwFlags = WHDR_DONE;
|
||||
whOut[outBufNum].dwLoops = 0;
|
||||
whOut[outBufNum].lpNext = NULL;
|
||||
whOut[outBufNum].reserved = 0;
|
||||
}
|
||||
|
||||
/* Write the first buffer out to get things going */
|
||||
outBufNum = 0;
|
||||
result = waveOutPrepareHeader(audioPort, &whOut[outBufNum],sizeof(WAVEHDR));
|
||||
result = waveOutWrite(audioPort, &whOut[outBufNum], sizeof(WAVEHDR));
|
||||
|
||||
/* Keep track of time so that we know how long we can sleep */
|
||||
lastWriteTime = timeGetTime();
|
||||
}
|
||||
|
||||
RTSoundIO :: ~RTSoundIO()
|
||||
{
|
||||
MMRESULT result;
|
||||
long timeToGo;
|
||||
|
||||
/* Close Audio Port */
|
||||
if (audioPort != NULL) {
|
||||
result = waveOutReset(audioPort);
|
||||
for( outBufNum = 0; outBufNum < (UINT)NUM_OUT_BUFFERS; outBufNum++ )
|
||||
{
|
||||
/* Loop until the next waveheader indicates that we are done */
|
||||
while( !(whOut[outBufNum].dwFlags & WHDR_DONE) )
|
||||
{
|
||||
//printf(".");
|
||||
timeToGo = (long) (FRAMETIME - (timeGetTime()-lastWriteTime));
|
||||
if( timeToGo > 0 ) Sleep( (long) timeToGo );
|
||||
}
|
||||
/* Unprepare the header */
|
||||
result = waveOutUnprepareHeader(audioPort, &whOut[outBufNum],sizeof(WAVEHDR));
|
||||
if (whOut[outBufNum].lpData != NULL) {
|
||||
free(whOut[outBufNum].lpData);
|
||||
whOut[outBufNum].lpData = NULL;
|
||||
}
|
||||
}
|
||||
result = waveOutClose(audioPort);
|
||||
}
|
||||
}
|
||||
|
||||
int RTSoundIO :: playBuffer(short *buf, int bufsize)
|
||||
{
|
||||
MMRESULT result;
|
||||
long timeToGo;
|
||||
|
||||
outBufNum++;
|
||||
if( outBufNum >= (UINT)NUM_OUT_BUFFERS ) outBufNum = 0;
|
||||
|
||||
/* Loop until the next waveheader indicates that we are done */
|
||||
while( !(whOut[outBufNum].dwFlags & WHDR_DONE) )
|
||||
{
|
||||
//printf(".");
|
||||
timeToGo = (long) (FRAMETIME - (timeGetTime()-lastWriteTime));
|
||||
//timeToGo = (long) (FRAMETIME * 0.5);
|
||||
if( timeToGo > 0 ) Sleep( (long) timeToGo );
|
||||
}
|
||||
result = waveOutUnprepareHeader(audioPort, &whOut[outBufNum], sizeof(WAVEHDR));
|
||||
|
||||
memcpy( whOut[outBufNum].lpData, buf, bufsize*sizeof(short));
|
||||
result = waveOutPrepareHeader(audioPort, &whOut[outBufNum], sizeof(WAVEHDR));
|
||||
result = waveOutWrite(audioPort, &whOut[outBufNum], sizeof(WAVEHDR));
|
||||
lastWriteTime = timeGetTime();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RTSoundIO :: recordBuffer(short *buf, int bufsize)
|
||||
{
|
||||
// There is no current support for audio input under the WinMM API ... sorry!
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,71 +0,0 @@
|
||||
/******************************************/
|
||||
/* RTSoundIO.cpp */
|
||||
/* Realtime Sound I/O Object for STK, */
|
||||
/* by Gary P. Scavone, 1998-1999. */
|
||||
/* */
|
||||
/* The sound output sections of this */
|
||||
/* object were based in part on code */
|
||||
/* by Doug Scott (SGI), Tim Stilson */
|
||||
/* (Linux), Bill Putnam (Win Wav), and */
|
||||
/* R. Marsanyi (DirectSound). */
|
||||
/* */
|
||||
/* This object provides a standard API */
|
||||
/* across all platforms for STK realtime */
|
||||
/* audio input/output. The sound output */
|
||||
/* code is fairly robust. Audio input, */
|
||||
/* however, is more dependent on the */
|
||||
/* capabilities of the particular OS and */
|
||||
/* the soundcard being used. For the */
|
||||
/* moment, I'll try to provide 1 or 2 */
|
||||
/* channel support. */
|
||||
/* */
|
||||
/* 16-bit integer audio input/output */
|
||||
/* data is being assumed. */
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__RTSOUNDIO_h)
|
||||
#define __RTSOUNDIO_h
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
#if defined(__OS_IRIX_)
|
||||
#include <dmedia/audio.h>
|
||||
#elif defined(__WINDS_API_)
|
||||
#include <windows.h>
|
||||
#include <dsound.h>
|
||||
#elif defined(__WINMM_API_)
|
||||
#include <windows.h>
|
||||
#include <MMSystem.h>
|
||||
#define NUM_OUT_BUFFERS 6
|
||||
#endif
|
||||
|
||||
class RTSoundIO : public Object
|
||||
{
|
||||
protected:
|
||||
#if (defined(__STK_REALTIME_) && defined(__OS_IRIX_))
|
||||
ALport audio_port_in;
|
||||
ALport audio_port_out;
|
||||
#elif (defined(__STK_REALTIME_) && defined(__OSS_API_))
|
||||
int audio_fd;
|
||||
#elif (defined(__STK_REALTIME_) && defined(__WINDS_API_) )
|
||||
LPDIRECTSOUND lpDirectSound;
|
||||
LPDIRECTSOUNDBUFFER lpDSBuffer;
|
||||
DWORD dwDSBufSize;
|
||||
DWORD zoneSize;
|
||||
LPDIRECTSOUNDCAPTURE lpDSCapture;
|
||||
LPDIRECTSOUNDCAPTUREBUFFER lpDSCBuffer;
|
||||
DWORD dwDSCBufSize;
|
||||
#elif (defined(__STK_REALTIME_) && defined(__WINMM_API_) )
|
||||
HWAVEOUT audioPort;
|
||||
WAVEHDR whOut[NUM_OUT_BUFFERS];
|
||||
UINT outBufNum;
|
||||
DWORD lastWriteTime;
|
||||
#endif
|
||||
public:
|
||||
RTSoundIO(MY_FLOAT srate, int channels, char *mode);
|
||||
~RTSoundIO();
|
||||
int playBuffer(short *buf, int bufsize);
|
||||
int recordBuffer(short *buf, int bufsize);
|
||||
};
|
||||
|
||||
#endif
|
||||
126
STK/RTWvIn.cpp
126
STK/RTWvIn.cpp
@@ -1,126 +0,0 @@
|
||||
/*******************************************/
|
||||
/* RTWvIn Input Class, */
|
||||
/* by Gary P. Scavone, 1999 */
|
||||
/* */
|
||||
/* This object inherits from WvIn and is */
|
||||
/* used to read in realtime 16-bit data */
|
||||
/* from a computer's audio port. */
|
||||
/* */
|
||||
/* NOTE: This object is NOT intended for */
|
||||
/* use in achieving simultaneous realtime */
|
||||
/* audio input/output (together with */
|
||||
/* RTWvOut). Under certain circumstances */
|
||||
/* such a scheme is possible, though you */
|
||||
/* should definitely know what you are */
|
||||
/* doing before trying. For safer "full- */
|
||||
/* duplex" operation, use the RTDuplex */
|
||||
/* class. */
|
||||
/*******************************************/
|
||||
|
||||
#include "RTWvIn.h"
|
||||
|
||||
RTWvIn :: RTWvIn(MY_FLOAT srate, short chans)
|
||||
{
|
||||
soundIO = new RTSoundIO(srate, chans, "record");
|
||||
channels = chans;
|
||||
length = RT_BUFFER_SIZE/channels;
|
||||
data = 0;
|
||||
rtdata = (short *) new short[RT_BUFFER_SIZE+channels];
|
||||
|
||||
this->getMoreData();
|
||||
|
||||
rate = (MY_FLOAT) srate / SRATE;
|
||||
if (fmod(rate, 1.0) > 0.0) interpolate = 1;
|
||||
else interpolate = 0;
|
||||
looping = 0;
|
||||
time = (MY_FLOAT) 0.0;
|
||||
phaseOffset = (MY_FLOAT) 0.0;
|
||||
finished = 0;
|
||||
lastOutput = (MY_FLOAT *) calloc(channels, sizeof(MY_FLOAT));
|
||||
gain = 0.00003052;
|
||||
#if (defined(__STK_REALTIME_) && defined(__OS_IRIX_))
|
||||
// This is necessary under IRIX because it scales the input by 0.5
|
||||
// when using single-channel input.
|
||||
if (channels == 1) gain *= 2;
|
||||
#endif
|
||||
}
|
||||
|
||||
RTWvIn :: ~RTWvIn()
|
||||
{
|
||||
delete soundIO;
|
||||
if (rtdata) {
|
||||
delete [ ] rtdata;
|
||||
rtdata = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RTWvIn :: normalize()
|
||||
{
|
||||
/* Do nothing ... cannot normalize realtime input */
|
||||
}
|
||||
|
||||
void RTWvIn :: normalize(MY_FLOAT newPeak)
|
||||
{
|
||||
/* Do nothing ... cannot normalize realtime input */
|
||||
}
|
||||
|
||||
void RTWvIn :: addPhaseOffset(MY_FLOAT anAngle)
|
||||
{
|
||||
/* No phaseOffset for realtime input */
|
||||
phaseOffset = 0.0;
|
||||
}
|
||||
|
||||
void RTWvIn :: setLooping(int aLoopStatus)
|
||||
{
|
||||
/* Cannot loop realtime input */
|
||||
looping = 0;
|
||||
}
|
||||
|
||||
void RTWvIn :: getMoreData()
|
||||
{
|
||||
soundIO->recordBuffer(rtdata,RT_BUFFER_SIZE);
|
||||
long temp = RT_BUFFER_SIZE;
|
||||
for (int i=0;i<channels;i++) {
|
||||
rtdata[temp] = rtdata[temp-channels];
|
||||
temp++;
|
||||
}
|
||||
}
|
||||
|
||||
int RTWvIn :: informTick()
|
||||
{
|
||||
static long temp;
|
||||
static MY_FLOAT alpha;
|
||||
|
||||
temp = (long) time; /* Integer part of time address */
|
||||
|
||||
if (interpolate) {
|
||||
alpha = time - (MY_FLOAT) temp; /* Fractional part of time address */
|
||||
temp *= channels;
|
||||
for (int i=0;i<channels;i++) {
|
||||
/* Do linear interpolation */
|
||||
lastOutput[i] = (MY_FLOAT) rtdata[temp];
|
||||
lastOutput[i] = lastOutput[i] +
|
||||
(alpha * ((MY_FLOAT) rtdata[temp+channels] - lastOutput[i]));
|
||||
lastOutput[i] *= gain;
|
||||
temp++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
temp *= channels;
|
||||
for (int i=0;i<channels;i++) {
|
||||
lastOutput[i] = rtdata[temp++];
|
||||
lastOutput[i] *= gain;
|
||||
}
|
||||
}
|
||||
|
||||
time += rate; /* Increment time */
|
||||
if (time >= length) {
|
||||
this->getMoreData();
|
||||
}
|
||||
while (time >= length) /* Check for end of sound */
|
||||
time -= length; /* loop back to beginning */
|
||||
while (time < 0.0) /* Check for end of sound */
|
||||
time += length; /* loop back to beginning */
|
||||
|
||||
return finished;
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Real-Time Wave File Output Class, */
|
||||
/* by Perry R. Cook, 1996 */
|
||||
/* revised by Gary P. Scavone, 1999 */
|
||||
/* */
|
||||
/* This object opens a realtime soundout */
|
||||
/* device, and pokes buffers of samples */
|
||||
/* into it. */
|
||||
/*******************************************/
|
||||
|
||||
#include "RTWvOut.h"
|
||||
|
||||
#if defined(__STK_REALTIME_)
|
||||
|
||||
RTWvOut :: RTWvOut(MY_FLOAT srate, int chans)
|
||||
{
|
||||
// We'll let RTSoundIO deal with channel and srate limitations.
|
||||
channels = chans;
|
||||
soundIO = new RTSoundIO(srate, channels, "play");
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
RTWvOut :: ~RTWvOut()
|
||||
{
|
||||
soundIO->playBuffer(data,counter);
|
||||
counter = 0;
|
||||
while (counter<RT_BUFFER_SIZE) {
|
||||
data[counter++] = 0;
|
||||
}
|
||||
soundIO->playBuffer(data,counter);
|
||||
soundIO->playBuffer(data,counter); // Are these extra writes necessary?
|
||||
soundIO->playBuffer(data,counter);
|
||||
delete soundIO;
|
||||
}
|
||||
|
||||
void RTWvOut :: tick(MY_FLOAT sample)
|
||||
{
|
||||
for (int i=0;i<channels;i++)
|
||||
data[counter++] = (short) (sample * 32000.0);
|
||||
|
||||
if (counter >= RT_BUFFER_SIZE) {
|
||||
soundIO->playBuffer(data,counter);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RTWvOut :: mtick(MY_MULTI samples)
|
||||
{
|
||||
for (int i=0;i<channels;i++)
|
||||
data[counter++] = (short) (*samples++ * 32000.0);
|
||||
|
||||
if (counter >= RT_BUFFER_SIZE) {
|
||||
soundIO->playBuffer(data,counter);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,79 +0,0 @@
|
||||
/*******************************************/
|
||||
/* RawWvIn Input Class, */
|
||||
/* by Gary P. Scavone, 1999 */
|
||||
/* */
|
||||
/* This object inherits from WvIn and is */
|
||||
/* used to open raw 16-bit data (signed */
|
||||
/* integer) files for playback. */
|
||||
/* */
|
||||
/* STK RawWave files are assumed to be */
|
||||
/* monaural and big-endian. */
|
||||
/*******************************************/
|
||||
|
||||
#include "RawWvIn.h"
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#include "swapstuf.h"
|
||||
#endif
|
||||
|
||||
RawWvIn :: RawWvIn(char *fileName, char *mode)
|
||||
{
|
||||
// Use the system call "stat" to determine the file length
|
||||
struct stat filestat;
|
||||
if (stat(fileName, &filestat) == -1)
|
||||
{ /* Opening file failed */
|
||||
fprintf(stderr,"Cannot access or find rawwave file: %s !!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
length = (long) filestat.st_size / 2; // length in 2-byte samples
|
||||
|
||||
// Open the file and read samples into data[]
|
||||
FILE *fd;
|
||||
fd = fopen(fileName,"rb");
|
||||
if (!fd) {
|
||||
printf("Couldn't open or find rawwave file %s !!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
channels = 1; // All STK rawwave files are mono
|
||||
data = (MY_FLOAT *) new MY_FLOAT[(length+1)*channels];
|
||||
|
||||
long i = 0;
|
||||
INT16 temp;
|
||||
fseek(fd,0,SEEK_SET); // Only here to bypass bug in Linux glibc 2.1x (RedHat 6.0)
|
||||
while (fread(&temp,2,1,fd)) {
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
temp = SwapINT16 (temp);
|
||||
#endif
|
||||
data[i++] = (MY_FLOAT) temp;
|
||||
}
|
||||
fclose(fd);
|
||||
|
||||
// Setup for looping or one-shot playback
|
||||
if (!strcmp(mode,"looping")) {
|
||||
looping = 1;
|
||||
data[length] = data[0]; // extra sample for interpolation
|
||||
}
|
||||
else if (!strcmp(mode,"oneshot")) {
|
||||
looping = 0;
|
||||
data[length] = data[length-1]; // extra sample for interpolation
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,"ERROR: Unsupported RawWvIn mode: %s\n",mode);
|
||||
free(data);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
time = (MY_FLOAT) 0.0;
|
||||
phaseOffset = (MY_FLOAT) 0.0;
|
||||
rate = (MY_FLOAT) 1.0;
|
||||
interpolate = 0;
|
||||
finished = 0;
|
||||
lastOutput = (MY_FLOAT *) calloc(channels, sizeof(MY_FLOAT));
|
||||
}
|
||||
|
||||
RawWvIn :: ~RawWvIn()
|
||||
{
|
||||
}
|
||||
102
STK/SndWvIn.cpp
102
STK/SndWvIn.cpp
@@ -1,102 +0,0 @@
|
||||
/*******************************************/
|
||||
/* SndWvIn Input Class, */
|
||||
/* by Gary P. Scavone, 1999 */
|
||||
/* */
|
||||
/* This object inherits from WvIn and is */
|
||||
/* used to open NeXT/Sun .snd 16-bit data */
|
||||
/* (signed integer) files for playback. */
|
||||
/* */
|
||||
/* .snd files are always big-endian. */
|
||||
/*******************************************/
|
||||
|
||||
#include "SndWvIn.h"
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#include "swapstuf.h"
|
||||
#endif
|
||||
|
||||
SndWvIn :: SndWvIn(char *fileName, char *mode)
|
||||
{
|
||||
// Open the file and get header info
|
||||
FILE *fd;
|
||||
fd = fopen(fileName,"rb");
|
||||
if (!fd) {
|
||||
printf("Couldn't open or find .snd file %s !!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Make sure this is a .snd format file
|
||||
char magic[4];
|
||||
fseek(fd,0,SEEK_SET); // Locate magic number in header
|
||||
fread(magic,4,1,fd);
|
||||
if (strncmp(magic,".snd",4)) {
|
||||
printf("This doesn't appear to be a .snd file %s !!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Get number of channels from the header
|
||||
INT32 int32temp;
|
||||
fseek(fd,20,SEEK_SET);
|
||||
fread(&int32temp,4,1,fd);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
int32temp = SwapINT32(int32temp);
|
||||
#endif
|
||||
channels = int32temp;
|
||||
|
||||
// Get length of data from the header
|
||||
fseek(fd,8,SEEK_SET);
|
||||
fread(&int32temp,4,1,fd);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
int32temp = SwapINT32(int32temp);
|
||||
#endif
|
||||
length = int32temp / 2 / channels; // channel length in 2-byte samples
|
||||
data = (MY_FLOAT *) new MY_FLOAT[(length+1)*channels];
|
||||
|
||||
// Read samples into data[]
|
||||
INT16 temp;
|
||||
long i = 0;
|
||||
fseek(fd,40,SEEK_SET);
|
||||
while (fread(&temp,2,1,fd)) {
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
temp = SwapINT16 (temp);
|
||||
#endif
|
||||
data[i++] = (MY_FLOAT) temp;
|
||||
}
|
||||
|
||||
// Get file sample rate from the header and set the default rate
|
||||
fseek(fd,16,SEEK_SET);
|
||||
fread(&int32temp,4,1,fd);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
int32temp = SwapINT32(int32temp);
|
||||
#endif
|
||||
rate = (MY_FLOAT) (int32temp/SRATE);
|
||||
fclose(fd);
|
||||
|
||||
// Setup for looping or one-shot playback
|
||||
if (!strcmp(mode,"looping")) {
|
||||
looping = 1;
|
||||
for (int j=0; j<channels; j++)
|
||||
data[length*channels+j] = data[j]; // extra sample for interpolation
|
||||
}
|
||||
else if (!strcmp(mode,"oneshot")) {
|
||||
looping = 0;
|
||||
for (int j=0; j<channels; j++)
|
||||
data[length*channels+j] = data[(length-1)*channels+j]; // extra sample for interpolation
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,"ERROR: Unsupported SndWvIn mode: %s\n",mode);
|
||||
free(data);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (fmod(rate, 1.0) > 0.0) interpolate = 1;
|
||||
else interpolate = 0;
|
||||
time = (MY_FLOAT) 0.0;
|
||||
phaseOffset = (MY_FLOAT) 0.0;
|
||||
finished = 0;
|
||||
lastOutput = (MY_FLOAT *) calloc(channels, sizeof(MY_FLOAT));
|
||||
}
|
||||
|
||||
SndWvIn :: ~SndWvIn()
|
||||
{
|
||||
}
|
||||
133
STK/SndWvOut.cpp
133
STK/SndWvOut.cpp
@@ -1,133 +0,0 @@
|
||||
/*******************************************/
|
||||
/* NeXT Soundfile Output Class */
|
||||
/* by Perry R. Cook, 1996 */
|
||||
/* revised by Gary P. Scavone, 1999 */
|
||||
/* */
|
||||
/* This one opens a NeXT .snd file, and */
|
||||
/* even knows how to byte-swap! */
|
||||
/*******************************************/
|
||||
|
||||
#include "SndWvOut.h"
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#include "swapstuf.h"
|
||||
#endif
|
||||
|
||||
/******** NeXT Soundfile Header Struct *******/
|
||||
struct headerform {
|
||||
char pref[4];
|
||||
INT32 hdr_length;
|
||||
INT32 file_length;
|
||||
INT32 mode;
|
||||
INT32 samp_rate;
|
||||
INT32 num_channels;
|
||||
char comment[16];
|
||||
};
|
||||
|
||||
FILE *openNeXTFile(int chans,char *fileName) {
|
||||
struct headerform hdr = {".sn",40,0,3,(INT32) SRATE,1,"Created by STK"};
|
||||
char tempName[128];
|
||||
FILE *fd;
|
||||
|
||||
hdr.pref[3] = 'd';
|
||||
|
||||
strcpy(tempName,fileName);
|
||||
if (strstr(tempName,".snd") == NULL) strcat(tempName,".snd");
|
||||
hdr.num_channels = chans;
|
||||
fd = fopen(tempName,"wb");
|
||||
if (!fd) {
|
||||
printf("Couldn't create soundfile %s !!!!!!!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
hdr.hdr_length = SwapINT32 (hdr.hdr_length);
|
||||
hdr.file_length = SwapINT32 (hdr.file_length);
|
||||
hdr.mode = SwapINT32 (hdr.mode);
|
||||
hdr.samp_rate = SwapINT32 (hdr.samp_rate);
|
||||
hdr.num_channels = SwapINT32 (hdr.num_channels);
|
||||
#endif
|
||||
printf("\nCreating soundfile %s\n\n", tempName);
|
||||
fwrite(&hdr,4,10,fd);
|
||||
return fd;
|
||||
}
|
||||
|
||||
SndWvOut :: SndWvOut(char *fileName)
|
||||
{
|
||||
channels = 1;
|
||||
fd = openNeXTFile(channels,fileName);
|
||||
counter = 0;
|
||||
totalCount = 0;
|
||||
}
|
||||
|
||||
SndWvOut :: SndWvOut(int chans, char *fileName)
|
||||
{
|
||||
if (chans > 24) {
|
||||
fprintf(stderr,"SndWvOut: Unsupported # of channels: %d\n", chans);
|
||||
exit(0);
|
||||
}
|
||||
channels = chans;
|
||||
fd = openNeXTFile(channels,fileName);
|
||||
counter = 0;
|
||||
totalCount = 0;
|
||||
}
|
||||
|
||||
SndWvOut :: ~SndWvOut()
|
||||
{
|
||||
double temp;
|
||||
|
||||
fwrite(data,2,counter,fd);
|
||||
fseek(fd,8,SEEK_SET);
|
||||
temp = (double) totalCount * ONE_OVER_SRATE;
|
||||
printf("%f Seconds Computed\n",temp);
|
||||
totalCount *= 2*channels;
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
totalCount = SwapINT32 (totalCount);
|
||||
#endif
|
||||
fwrite(&totalCount,4,1,fd);
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
long SndWvOut :: getCounter()
|
||||
{
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
MY_FLOAT SndWvOut :: getTime()
|
||||
{
|
||||
return (MY_FLOAT) totalCount * ONE_OVER_SRATE;
|
||||
}
|
||||
|
||||
void SndWvOut :: tick(MY_FLOAT sample)
|
||||
{
|
||||
INT16 isample;
|
||||
|
||||
isample = (INT16) (sample * 32000.0);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
isample = SwapINT16 (isample);
|
||||
#endif
|
||||
for (int i=0;i<channels;i++)
|
||||
data[counter++] = isample;
|
||||
|
||||
totalCount++;
|
||||
if (counter == SND_BUFFER_SIZE) {
|
||||
fwrite(data,2,SND_BUFFER_SIZE,fd);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SndWvOut :: mtick(MY_MULTI samples)
|
||||
{
|
||||
for (int i=0;i<channels;i++) {
|
||||
data[counter] = (INT16) (*samples++ * 32000.0);
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
data[counter] = SwapINT16 (data[counter]);
|
||||
#endif
|
||||
counter++;
|
||||
}
|
||||
|
||||
totalCount++;
|
||||
if (counter == SND_BUFFER_SIZE) {
|
||||
fwrite(data,2,SND_BUFFER_SIZE,fd);
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*******************************************/
|
||||
/* NeXT Soundfile Output Class */
|
||||
/* by Perry R. Cook, 1996 */
|
||||
/* revised by Gary P. Scavone, 1999 */
|
||||
/* */
|
||||
/* This one opens a NeXT .snd file, and */
|
||||
/* even knows how to byte-swap! */
|
||||
/*******************************************/
|
||||
|
||||
#include "Object.h"
|
||||
#include "WvOut.h"
|
||||
|
||||
#if !defined(__SndWvOut_h)
|
||||
#define __SndWvOut_h
|
||||
|
||||
#define SND_BUFFER_SIZE 1024
|
||||
|
||||
class SndWvOut : public WvOut
|
||||
{
|
||||
protected:
|
||||
FILE *fd;
|
||||
INT16 data[SND_BUFFER_SIZE];
|
||||
long counter;
|
||||
long totalCount;
|
||||
int channels;
|
||||
public:
|
||||
SndWvOut(char *fileName);
|
||||
SndWvOut(int chans, char *fileName);
|
||||
~SndWvOut();
|
||||
long getCounter();
|
||||
MY_FLOAT getTime();
|
||||
void tick(MY_FLOAT sample);
|
||||
void mtick(MY_MULTI samples);
|
||||
};
|
||||
|
||||
#endif // defined(__SndWvOut_h)
|
||||
@@ -1,80 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Vibraphone SubClass of Modal4 */
|
||||
/* Instrument, by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Controls: CONTROL1 = stickHardness */
|
||||
/* CONTROL2 = strikePosition*/
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/*******************************************/
|
||||
|
||||
#include "Vibraphn.h"
|
||||
#include "SKINI11.msg"
|
||||
|
||||
Vibraphn :: Vibraphn() : Modal4()
|
||||
{
|
||||
// Concatenate the STK RAWWAVE_PATH to the rawwave file
|
||||
char file[128];
|
||||
strcpy(file, RAWWAVE_PATH);
|
||||
wave = new RawWvIn(strcat(file,"rawwaves/marmstk1.raw"),"oneshot");
|
||||
wave->normalize();
|
||||
wave->setRate((MY_FLOAT) 13.33);
|
||||
vibr->setFreq((MY_FLOAT) 4.0);
|
||||
onepole->setPole((MY_FLOAT) 0.2);
|
||||
this->setRatioAndReson(0, (MY_FLOAT) 1.0,(MY_FLOAT) 0.99995); // Set
|
||||
this->setRatioAndReson(1, (MY_FLOAT) 2.01,(MY_FLOAT) 0.99991); // our
|
||||
this->setRatioAndReson(2, (MY_FLOAT) 3.9,(MY_FLOAT) 0.99992); // resonance
|
||||
this->setRatioAndReson(3,(MY_FLOAT) 14.37,(MY_FLOAT) 0.99990); // values here
|
||||
this->setFiltGain(0,(MY_FLOAT) 0.025);
|
||||
this->setFiltGain(1,(MY_FLOAT) 0.015);
|
||||
this->setFiltGain(2,(MY_FLOAT) 0.015);
|
||||
this->setFiltGain(3,(MY_FLOAT) 0.015);
|
||||
masterGain = (MY_FLOAT) 1.0;
|
||||
directGain = (MY_FLOAT) 0.0;
|
||||
vibrGain = (MY_FLOAT) 0.2;
|
||||
}
|
||||
|
||||
Vibraphn :: ~Vibraphn()
|
||||
{
|
||||
delete wave;
|
||||
}
|
||||
|
||||
void Vibraphn :: setStickHardness(MY_FLOAT hardness)
|
||||
{
|
||||
wave->setRate((MY_FLOAT) 2.0 + ((MY_FLOAT) 22.66 * hardness));
|
||||
masterGain = (MY_FLOAT) 0.2 + (hardness * (MY_FLOAT) 1.6);
|
||||
}
|
||||
|
||||
void Vibraphn :: setStrikePosition(MY_FLOAT position)
|
||||
{
|
||||
MY_FLOAT temp,temp2;
|
||||
temp2 = position * PI;
|
||||
strikePosition = position; /* Hack only first three modes */
|
||||
temp = (MY_FLOAT) sin(strikePosition * PI);
|
||||
this->setFiltGain(0,(MY_FLOAT) 0.025 * temp);
|
||||
temp = (MY_FLOAT) sin(0.1 + (2.01 * temp2));
|
||||
this->setFiltGain(1,(MY_FLOAT) 0.015 * temp);
|
||||
temp = (MY_FLOAT) sin(3.95 * temp2);
|
||||
this->setFiltGain(2,(MY_FLOAT) 0.015 * temp);
|
||||
}
|
||||
|
||||
void Vibraphn :: controlChange(int number, MY_FLOAT value)
|
||||
{
|
||||
#if defined(_debug_)
|
||||
printf("Vibraphn : ControlChange: Number=%i Value=%f\n",number,value);
|
||||
#endif
|
||||
if (number == __SK_StickHardness_)
|
||||
this->setStickHardness(value * NORM_7);
|
||||
else if (number == __SK_StrikePosition_)
|
||||
this->setStrikePosition(value * NORM_7);
|
||||
else if (number == __SK_ModFrequency_)
|
||||
vibr->setFreq((value * NORM_7 * (MY_FLOAT) 12.0));
|
||||
else if (number == __SK_ModWheel_)
|
||||
vibrGain = (value * NORM_7);
|
||||
else if (number == __SK_AfterTouch_Cont_)
|
||||
this->strike(value * NORM_7);
|
||||
else {
|
||||
printf("Vibraphn : Undefined Control Number!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/*******************************************/
|
||||
/* Vibraphone SubClass of Modal4 */
|
||||
/* Instrument, by Perry R. Cook, 1995-96 */
|
||||
/* */
|
||||
/* Controls: CONTROL1 = stickHardness */
|
||||
/* CONTROL2 = strikePosition*/
|
||||
/* CONTROL3 = vibFreq */
|
||||
/* MOD_WHEEL= vibAmt */
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__Vibraphn_h)
|
||||
#define __Vibraphn_h
|
||||
|
||||
#include "Modal4.h"
|
||||
|
||||
class Vibraphn : public Modal4
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
Vibraphn();
|
||||
~Vibraphn();
|
||||
void setStickHardness(MY_FLOAT hardness);
|
||||
void setStrikePosition(MY_FLOAT position);
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
};
|
||||
|
||||
#endif
|
||||
103
STK/WavWvIn.cpp
103
STK/WavWvIn.cpp
@@ -1,103 +0,0 @@
|
||||
/*******************************************/
|
||||
/* WavWvIn Input Class, */
|
||||
/* by Gary P. Scavone, 1999 */
|
||||
/* */
|
||||
/* This object inherits from WvIn and is */
|
||||
/* used to open DOS/Windows .wav 16-bit */
|
||||
/* data (signed integer) files for */
|
||||
/* playback. */
|
||||
/* */
|
||||
/* .wav files are always little-endian. */
|
||||
/*******************************************/
|
||||
|
||||
#include "WavWvIn.h"
|
||||
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
#include "swapstuf.h"
|
||||
#endif
|
||||
|
||||
WavWvIn :: WavWvIn(char *fileName, char *mode)
|
||||
{
|
||||
// Open the file and get header info
|
||||
FILE *fd;
|
||||
fd = fopen(fileName,"rb");
|
||||
if (!fd) {
|
||||
printf("Couldn't open or find .wav file %s !!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Make sure this is a .wav format file
|
||||
char wave[4];
|
||||
fseek(fd,8,SEEK_SET); // Locate wave id
|
||||
fread(&wave,4,1,fd);
|
||||
if (strncmp(wave,"WAVE",4)) {
|
||||
printf("This doesn't appear to be a .wav file %s !!!\n",fileName);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Get number of channels from the header
|
||||
INT16 temp;
|
||||
fseek(fd,22,SEEK_SET); // Locate channels in header
|
||||
fread(&temp,2,1,fd);
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
temp = SwapINT16(temp);
|
||||
#endif
|
||||
channels = temp;
|
||||
|
||||
// Get length of data from the header
|
||||
INT32 bytes;
|
||||
fseek(fd,40,SEEK_SET); // Locate data length in header
|
||||
fread(&bytes,4,1,fd);
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
bytes = SwapINT32(bytes);
|
||||
#endif
|
||||
length = bytes / 2 / channels; // length in 2-byte samples
|
||||
data = (MY_FLOAT *) new MY_FLOAT[(length+1)*channels];
|
||||
|
||||
// Read samples into data[]
|
||||
long i = 0;
|
||||
while (fread(&temp,2,1,fd)) {
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
temp = SwapINT16 (temp);
|
||||
#endif
|
||||
data[i++] = (MY_FLOAT) temp;
|
||||
}
|
||||
|
||||
// Get file sample rate from the header and set the default rate
|
||||
INT32 srate;
|
||||
fseek(fd,24,SEEK_SET); // Locate sample rate in header
|
||||
fread(&srate,4,1,fd);
|
||||
#ifndef __LITTLE_ENDIAN__
|
||||
srate = SwapINT32(srate);
|
||||
#endif
|
||||
rate = (MY_FLOAT) (srate/SRATE); // set default rate based on file sampling rate
|
||||
fclose(fd);
|
||||
|
||||
// Setup for looping or one-shot playback
|
||||
if (!strcmp(mode,"looping")) {
|
||||
looping = 1;
|
||||
for (int j=0; j<channels; j++)
|
||||
data[length*channels+j] = data[j]; // extra sample for interpolation
|
||||
}
|
||||
else if (!strcmp(mode,"oneshot")) {
|
||||
looping = 0;
|
||||
for (int j=0; j<channels; j++)
|
||||
data[length*channels+j] = data[(length-1)*channels+j]; // extra sample for interpolation
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,"ERROR: Unsupported WavWvIn mode: %s\n",mode);
|
||||
free(data);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (fmod(rate, 1.0) > 0.0) interpolate = 1;
|
||||
else interpolate = 0;
|
||||
time = (MY_FLOAT) 0.0;
|
||||
phaseOffset = (MY_FLOAT) 0.0;
|
||||
finished = 0;
|
||||
lastOutput = (MY_FLOAT *) calloc(channels, sizeof(MY_FLOAT));
|
||||
}
|
||||
|
||||
WavWvIn :: ~WavWvIn()
|
||||
{
|
||||
}
|
||||
222
STK/WvIn.cpp
222
STK/WvIn.cpp
@@ -1,222 +0,0 @@
|
||||
/********************************************/
|
||||
/* Data Input Base Class */
|
||||
/* by Gary P. Scavone, 1999 */
|
||||
/* */
|
||||
/* This class can handle multi-channel */
|
||||
/* input. Multi-channel input is */
|
||||
/* interleaved in the vector "data". */
|
||||
/* Actual data input occurs in the */
|
||||
/* subclasses of WvIn. */
|
||||
/********************************************/
|
||||
|
||||
#include "WvIn.h"
|
||||
#include <stdio.h>
|
||||
|
||||
WvIn :: WvIn()
|
||||
{
|
||||
}
|
||||
|
||||
WvIn :: ~WvIn()
|
||||
{
|
||||
if (data) {
|
||||
delete [ ] data;
|
||||
data = 0;
|
||||
}
|
||||
if (lastOutput) {
|
||||
free(lastOutput);
|
||||
lastOutput = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void WvIn :: reset()
|
||||
{
|
||||
finished = 0;
|
||||
time = (MY_FLOAT) 0.0;
|
||||
for (int i=0;i<channels;i++) {
|
||||
lastOutput[i] = (MY_FLOAT) 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void WvIn :: normalize()
|
||||
{
|
||||
this->normalize((MY_FLOAT) 1.0);
|
||||
}
|
||||
|
||||
// Normalize all channels equally by the greatest magnitude in all of data
|
||||
void WvIn :: normalize(MY_FLOAT newPeak)
|
||||
{
|
||||
long i;
|
||||
MY_FLOAT max = (MY_FLOAT) 0.0;
|
||||
|
||||
for (i=0;i<channels*length;i++) {
|
||||
if (fabs(data[i]) > max)
|
||||
max = (MY_FLOAT) fabs((double) data[i]);
|
||||
}
|
||||
if (max > 0.0) {
|
||||
max = (MY_FLOAT) 1.0 / max;
|
||||
max *= newPeak;
|
||||
for (i=0;i<=channels*length;i++)
|
||||
data[i] *= max;
|
||||
}
|
||||
}
|
||||
|
||||
void WvIn :: setRate(MY_FLOAT aRate)
|
||||
{
|
||||
rate = aRate;
|
||||
if (fmod(rate, 1.0) > 0.0) interpolate = 1;
|
||||
else interpolate = 0;
|
||||
}
|
||||
|
||||
void WvIn :: setFreq(MY_FLOAT aFreq)
|
||||
{
|
||||
rate = length * (MY_FLOAT) ONE_OVER_SRATE * aFreq;
|
||||
if (fmod(rate, 1.0) > 0.0) interpolate = 1;
|
||||
else interpolate = 0;
|
||||
}
|
||||
|
||||
void WvIn :: addTime(MY_FLOAT aTime) /* Add an absolute time */
|
||||
{ /* in samples */
|
||||
time += aTime;
|
||||
}
|
||||
|
||||
void WvIn :: addPhase(MY_FLOAT anAngle) /* Add a time in cycles */
|
||||
{ /* Cycles here means */
|
||||
time += length * anAngle; /* 1.0 = length */
|
||||
}
|
||||
|
||||
void WvIn :: addPhaseOffset(MY_FLOAT anAngle)
|
||||
{ /* Add a phase offset */
|
||||
phaseOffset = length * anAngle; /* in cycles, where */
|
||||
} /* 1.0 = length */
|
||||
|
||||
void WvIn :: setInterpolate(int anInterpStatus)
|
||||
{
|
||||
interpolate = anInterpStatus;
|
||||
}
|
||||
|
||||
void WvIn :: setLooping(int aLoopStatus)
|
||||
{
|
||||
time = (MY_FLOAT) 0.0;
|
||||
looping = aLoopStatus;
|
||||
|
||||
if (looping) {
|
||||
for (int i=0;i<channels;i++)
|
||||
data[length*channels+i] = data[i];
|
||||
}
|
||||
else {
|
||||
for (int i=0;i<channels;i++)
|
||||
data[length*channels+i] = data[(length-1)*channels+i];
|
||||
}
|
||||
}
|
||||
|
||||
long WvIn :: getLength()
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
int WvIn :: isFinished()
|
||||
{
|
||||
return finished;
|
||||
}
|
||||
|
||||
MY_FLOAT WvIn :: tick()
|
||||
{
|
||||
this->informTick();
|
||||
if (channels > 1) {
|
||||
MY_FLOAT tempout = 0.0;
|
||||
for (int i=0;i<channels;i++)
|
||||
tempout += lastOutput[i];
|
||||
tempout /= channels;
|
||||
return tempout;
|
||||
}
|
||||
else
|
||||
return *lastOutput;
|
||||
}
|
||||
|
||||
MY_MULTI WvIn :: mtick()
|
||||
{
|
||||
this->informTick();
|
||||
return lastOutput;
|
||||
}
|
||||
|
||||
int WvIn :: informTick()
|
||||
{
|
||||
static MY_FLOAT temp_time, alpha;
|
||||
static long temp;
|
||||
|
||||
if (!finished) {
|
||||
|
||||
temp_time = time;
|
||||
|
||||
if (phaseOffset != 0.0) {
|
||||
temp_time += phaseOffset; /* Add phase offset */
|
||||
if (looping) {
|
||||
while (temp_time >= length) /* Check for end of sound */
|
||||
temp_time -= length; /* loop back to beginning */
|
||||
while (temp_time < 0.0) /* Check for end of sound */
|
||||
temp_time += length; /* loop back to beginning */
|
||||
}
|
||||
else {
|
||||
if (temp_time >= length) /* Check for end of sound */
|
||||
temp_time = length - (MY_FLOAT) 1; /* stick at end */
|
||||
else if (temp_time < 0.0) /* check for end of sound */
|
||||
temp_time = (MY_FLOAT) 0.0; /* stick at beginning */
|
||||
}
|
||||
}
|
||||
|
||||
temp = (long) temp_time; /* Integer part of time address */
|
||||
|
||||
if (interpolate) {
|
||||
alpha = temp_time - (MY_FLOAT) temp; /* fractional part of time address */
|
||||
temp *= channels;
|
||||
for (int i=0;i<channels;i++) {
|
||||
/* Do linear interpolation */
|
||||
lastOutput[i] = data[temp];
|
||||
lastOutput[i] = lastOutput[i] +
|
||||
(alpha*(data[temp+channels] - lastOutput[i]));
|
||||
temp++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
temp *= channels;
|
||||
for (int i=0;i<channels;i++)
|
||||
lastOutput[i] = data[temp++];
|
||||
}
|
||||
|
||||
time += rate; /* Increment time */
|
||||
if (looping) {
|
||||
while (time >= length) /* Check for end of sound */
|
||||
time -= length; /* loop back to beginning */
|
||||
while (time < 0.0) /* Check for end of sound */
|
||||
time += length; /* loop back to beginning */
|
||||
}
|
||||
else { /* OneShot */
|
||||
if (time >= length) { /* Check for end of sound */
|
||||
time = length-(MY_FLOAT) 1; /* stick at end */
|
||||
finished = 1; /* Information for one-shot use */
|
||||
}
|
||||
else if (time < 0.0) /* Check for end of sound */
|
||||
time = (MY_FLOAT) 0.0; /* stick at beginning */
|
||||
}
|
||||
}
|
||||
|
||||
return finished;
|
||||
}
|
||||
|
||||
MY_FLOAT WvIn :: lastOut()
|
||||
{
|
||||
if (channels > 1) {
|
||||
MY_FLOAT tempout = 0.0;
|
||||
for (int i=0;i<channels;i++)
|
||||
tempout += lastOutput[i];
|
||||
tempout /= channels;
|
||||
return tempout;
|
||||
}
|
||||
else
|
||||
return *lastOutput;
|
||||
}
|
||||
|
||||
MY_MULTI WvIn :: mlastOut()
|
||||
{
|
||||
return lastOutput;
|
||||
}
|
||||
51
STK/WvIn.h
51
STK/WvIn.h
@@ -1,51 +0,0 @@
|
||||
/********************************************/
|
||||
/* Data Input Class, */
|
||||
/* by Gary P. Scavone, 1999 */
|
||||
/* */
|
||||
/* This class can handle multi-channel */
|
||||
/* data, which is assumed to be interwoven */
|
||||
/* in the data vector. Actual data input */
|
||||
/* occurs in the subclasses of WvIn. */
|
||||
/********************************************/
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
#if !defined(__WvIn_h)
|
||||
#define __WvIn_h
|
||||
|
||||
class WvIn : public Object
|
||||
{
|
||||
protected:
|
||||
long length;
|
||||
int channels;
|
||||
int looping;
|
||||
int finished;
|
||||
int interpolate;
|
||||
MY_FLOAT *data;
|
||||
MY_FLOAT time;
|
||||
MY_FLOAT rate;
|
||||
MY_FLOAT phaseOffset;
|
||||
MY_FLOAT *lastOutput;
|
||||
public:
|
||||
WvIn();
|
||||
virtual ~WvIn();
|
||||
void reset();
|
||||
void normalize();
|
||||
void normalize(MY_FLOAT newPeak);
|
||||
void setRate(MY_FLOAT aRate);
|
||||
void setFreq(MY_FLOAT aFreq);
|
||||
void addTime(MY_FLOAT aTime);
|
||||
void addPhase(MY_FLOAT anAngle);
|
||||
void addPhaseOffset(MY_FLOAT anAngle);
|
||||
void setInterpolate(int anInterpStatus);
|
||||
void setLooping(int aLoopStatus);
|
||||
long getLength();
|
||||
int isFinished();
|
||||
MY_FLOAT tick();
|
||||
MY_MULTI mtick();
|
||||
virtual int informTick();
|
||||
MY_FLOAT lastOut();
|
||||
MY_MULTI mlastOut();
|
||||
};
|
||||
|
||||
#endif // defined(__WvIn_h)
|
||||
@@ -1,27 +0,0 @@
|
||||
/********************************************/
|
||||
/* WvOut Abstract Class, */
|
||||
/* by Tim Stilson, 1996 */
|
||||
/* revised by Gary P. Scavone, 1999 */
|
||||
/* */
|
||||
/* This class can handle multi-channel */
|
||||
/* data via the mtick() method. */
|
||||
/********************************************/
|
||||
|
||||
#include "WvOut.h"
|
||||
#include <stdio.h>
|
||||
|
||||
WvOut :: WvOut()
|
||||
{
|
||||
}
|
||||
|
||||
WvOut :: ~WvOut()
|
||||
{
|
||||
}
|
||||
|
||||
void WvOut :: tick(MY_FLOAT sample)
|
||||
{
|
||||
}
|
||||
|
||||
void WvOut :: mtick(MY_MULTI samples)
|
||||
{
|
||||
}
|
||||
27
STK/WvOut.h
27
STK/WvOut.h
@@ -1,27 +0,0 @@
|
||||
/********************************************/
|
||||
/* WvOut Abstract Class, */
|
||||
/* by Tim Stilson, 1996 */
|
||||
/* revised by Gary P. Scavone, 1999 */
|
||||
/* */
|
||||
/* This class can handle multi-channel */
|
||||
/* data via the mtick() method. */
|
||||
/********************************************/
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
#if !defined(__WvOut_h)
|
||||
#define __WvOut_h
|
||||
|
||||
|
||||
|
||||
class WvOut : public Object
|
||||
{
|
||||
public:
|
||||
WvOut();
|
||||
virtual ~WvOut();
|
||||
virtual void tick(MY_FLOAT sample);
|
||||
virtual void mtick(MY_MULTI samples);
|
||||
};
|
||||
|
||||
|
||||
#endif // defined(__WvOut_h)
|
||||
@@ -1,42 +0,0 @@
|
||||
#include "swapstuf.h"
|
||||
|
||||
INT32 SwapINT32(INT32 inf)
|
||||
{
|
||||
INT32 o;
|
||||
unsigned char *inp,*outp;
|
||||
inp=(unsigned char *)&inf;
|
||||
outp=(unsigned char *)&o;
|
||||
outp[0]=inp[3]; outp[1]=inp[2]; outp[2]=inp[1]; outp[3]=inp[0];
|
||||
return(o);
|
||||
}
|
||||
|
||||
INT16 SwapINT16(INT16 inf)
|
||||
{
|
||||
INT16 o;
|
||||
unsigned char *inp,*outp;
|
||||
inp=(unsigned char *)&inf;
|
||||
outp=(unsigned char *)&o;
|
||||
outp[0]=inp[1]; outp[1]=inp[0];
|
||||
return(o);
|
||||
}
|
||||
|
||||
float SwapFloat(float inf)
|
||||
{
|
||||
float o;
|
||||
unsigned char *inp,*outp;
|
||||
inp=(unsigned char *)&inf;
|
||||
outp=(unsigned char *)&o;
|
||||
outp[0]=inp[3]; outp[1]=inp[2]; outp[2]=inp[1]; outp[3]=inp[0];
|
||||
return(o);
|
||||
}
|
||||
|
||||
double SwapDouble(double inf)
|
||||
{
|
||||
double o;
|
||||
unsigned char *inp,*outp;
|
||||
inp=(unsigned char *)&inf;
|
||||
outp=(unsigned char *)&o;
|
||||
outp[0]=inp[7]; outp[1]=inp[6]; outp[2]=inp[5]; outp[3]=inp[4];
|
||||
outp[4]=inp[3]; outp[5]=inp[2]; outp[6]=inp[1]; outp[7]=inp[0];
|
||||
return(o);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#include "Object.h"
|
||||
|
||||
INT32 SwapINT32(INT32 inf);
|
||||
INT16 SwapINT16(INT16 inf);
|
||||
float SwapFloat(float inf);
|
||||
double SwapDouble(float inf);
|
||||
@@ -1,10 +1,10 @@
|
||||
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
|
||||
Version 3.1
|
||||
Version 3.2
|
||||
|
||||
By Perry R. Cook, 1995-2000
|
||||
and Gary P. Scavone, 1997-2000.
|
||||
|
||||
STK Classes, Version 3.1
|
||||
STK Classes, Version 3.2
|
||||
Please read README.txt for more information.
|
||||
|
||||
<--------Building Blocks---------->|<----------------Instruments------------------>
|
||||
@@ -17,41 +17,43 @@ Object-----------------------------------Instrmnt----------.
|
||||
Envelope| Filter Reverb BowTabl | .----------------------------------------.
|
||||
| | | | JetTabl | | | | | | | | |
|
||||
ADSR | OneZero PRCRev ReedTabl| Modal4 | FM4Op---.| | | | Shakers
|
||||
| OnePole JCRev | | | | || | | | |
|
||||
._____| TwoZero NRev .____| Marimba | FM4Alg3 || Plucked Sampler | Maraca
|
||||
| | TwoPole | Vibraphn| | || Clarinet | | Sekere
|
||||
Noise | DCBlock LipFilt AgogoBel| HeavyMtl|| Brass SamplFlt| Cabasa
|
||||
| | BiQuad | || Flute | | Bamboo
|
||||
SubNoise| DlineL .____| .____|| Bowed Moog1 | Water Drops
|
||||
| DLineA | | || BowedBar | Tambourine
|
||||
._____| DLineN VoicForm FM4Alg4 ||____. | SleighBells
|
||||
| | FormSwep | | | | Guiro
|
||||
WvIn | PoleZero PercFlut| Plucked2 | Wrench
|
||||
| |____. | | | Coke Can
|
||||
WavWvIn | | .____| Mandolin .____| Sticks
|
||||
SndWvIn | TablLook | | | Crunch
|
||||
RawWvIn | FM4Alg5 | DrumSynt Sand Paper
|
||||
MatWvIn | | |
|
||||
RTWvIn | Rhodey |
|
||||
| Wurley |
|
||||
._____| TubeBell |
|
||||
| | .____|
|
||||
Modulatr| | |
|
||||
| FM4Alg6 |
|
||||
._____| | |
|
||||
| | FMVoices|
|
||||
SingWave|_____. |
|
||||
| | .____|
|
||||
._____| WvOut |
|
||||
| OnePole JCRev | | | | || | | |
|
||||
._____| TwoZero NRev .____| ModalBar| FM4Alg3 || Plucked Sampler |
|
||||
| | TwoPole | | | || Clarinet | |
|
||||
Noise | DCBlock LipFilt | HeavyMtl|| Brass SamplFlt|
|
||||
| | BiQuad | || Flute | |
|
||||
SubNoise| DlineL .____| .____|| Bowed Moog1 |
|
||||
| DLineA | | || BowedBar |
|
||||
| DLineN VoicForm FM4Alg4 || BlowHole |
|
||||
| FormSwep | ||____. |
|
||||
| PoleZero PercFlut| | |
|
||||
.____| FIR | Plucked2 |
|
||||
| | .____| | .____|
|
||||
TablLook| | | Mandolin |
|
||||
| FM4Alg5 | DrumSynt
|
||||
|____. | |
|
||||
| | Rhodey |
|
||||
| WvIn Wurley |
|
||||
._____| | TubeBell |
|
||||
| | WavWvIn .____|
|
||||
Modulatr| SndWvIn | |
|
||||
| RawWvIn FM4Alg6 |
|
||||
._____| MatWvIn | |
|
||||
| | AifWvIn FMVoices|
|
||||
SingWave| StrmWvIn |
|
||||
| .____|
|
||||
._____|_____. |
|
||||
| | | FM4Alg8
|
||||
VoicMang| WavWvOut |
|
||||
| SndWvOut BeeThree
|
||||
| RTWvOut
|
||||
| MatWvOut
|
||||
._____| RawWvOut
|
||||
|
|
||||
MIDIIO
|
||||
|
||||
VoicMang| WvOut |
|
||||
| | BeeThree
|
||||
| WavWvOut
|
||||
._____| SndWvOut
|
||||
| | RawWvOut
|
||||
RtMidi | MatWvOut
|
||||
| AifWvOut
|
||||
._____| RtWvOut
|
||||
| StrmWvOut
|
||||
RtAudio
|
||||
|
||||
********** INSTRUMENTS AND ALGORITHMS **************
|
||||
|
||||
@@ -65,12 +67,11 @@ Mandolin.cpp My Own Mandolin <<flavor of Plucked2>>
|
||||
Bowed.cpp Not Hideous Bowed String DlineL,BowTabl,OnePole,BiQuad,RawWave,ADSR
|
||||
Brass.cpp Not So Bad Brass Inst. DLineA,LipFilt,DCBlock,ADSR,RawWvIn
|
||||
Clarinet.cpp Pretty Good Clarinet DLineL,ReedTabl,OneZero,Envelope,Noise,RawWvIn
|
||||
BlowHole.cpp Clarinet w/ tone/reghole DLineL,ReedTabl,OneZero,Envelope,Noise,RawWvIn,PoleZero
|
||||
Flute.cpp Pretty Good Flute JetTabl,DLineL,OnePole,DCBlock,Noise,ADSR,RawWvIn
|
||||
BowedBar.cpp Pretty Good Bowed Bar DLineN,BowTabl,ADSR,BiQuad
|
||||
Modal4.cpp 4 Resonances Envelope,RawWvIn,RawWvIn,BiQuad,OnePole
|
||||
Marimba.cpp <<flavor of MODAL4>>
|
||||
Vibraphn.cpp <<flavor of MODAL4>>
|
||||
Agogobel.cpp <<flavor of MODAL4>>
|
||||
ModalBar.cpp Various presets <<flavor of MODAL4>>
|
||||
FM4Op.cpp 4 Operator FM Master ADSR,RawWvIn,TwoZero
|
||||
FM4Alg3.cpp 3 Cascade w/ FB Mod. <<flavor of FM4OP>>
|
||||
FM4Alg4.cpp Like Alg3 but diff. <<flavor of FM4OP>>
|
||||
@@ -107,16 +108,24 @@ Inputs: TablLook.cpp Lookup Table (assumes given data in big-endian f
|
||||
SndWvIn.cpp .snd Input Class
|
||||
WavWvIn.cpp .wav Input Class
|
||||
MatWvIn.cpp Matlab MAT-file Input Class
|
||||
RTWvIn.cpp Realtime Input Class
|
||||
AifWvIn.cpp AIFF Input Class
|
||||
RtWvIn.cpp Realtime Input Class
|
||||
StrmWvIn.cpp Audio Streaming (socket server) Input Class
|
||||
|
||||
Outputs: WvOut.cpp Output Master Class
|
||||
RawWvOut.cpp STK Raw-file Output Class
|
||||
SndWvOut.cpp .snd Output Class
|
||||
WavWvOut.cpp .wav Output Class
|
||||
RTWvOut.cpp Realtime Output Class
|
||||
MatWvOut.cpp Matlab MaT-file Output Class
|
||||
AifWvOut.cpp AIFF Output Class
|
||||
RtWvOut.cpp Realtime Output Class
|
||||
StrmWvOut.cpp Audio Streaming (socket client) Output Class
|
||||
|
||||
MIDI: MIDIIO.cpp MIDI I/O Class
|
||||
Duplex: RtDuplex.cpp Realtime Input/Output Class
|
||||
|
||||
MIDI: RtMidi.cpp MIDI I/O Class
|
||||
|
||||
Audio I/O: RtAudio.cpp Multi-OS Audio I/O Routines
|
||||
|
||||
Filters: Filter.cpp Filter Master Class
|
||||
OneZero.cpp One Zero Filter
|
||||
@@ -143,3 +152,5 @@ NonLin&Lookup: JetTabl.cpp Cubic Jet NonLinearity
|
||||
|
||||
Derived: Modulatr.cpp Per. and Rnd. Vibrato: RawWave, SubNoise, OnePole
|
||||
SingWave.cpp Looping Wavetable with: Modulatr, Envelope
|
||||
|
||||
Control: Controller.cpp Pipe, Socket, and MIDI control message handling
|
||||
28
doc/README-Linux.txt
Normal file
28
doc/README-Linux.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
|
||||
Version 3.2
|
||||
|
||||
By Perry R. Cook, 1995-2000
|
||||
and Gary P. Scavone, 1997-2000.
|
||||
|
||||
Please read the file README.txt for more general STK information.
|
||||
|
||||
STK for Linux is currently using either the Open Sound System (OSS) or the Advanced Linux Sound Architecture (ALSA) sound and MIDI APIs. The free version of OSS works as well (and in some cases better than the commercial OSS version ... such as with my Maestro 2e chipset). In general, the ALSA drivers seem to perform well though we have had some problems with them at CCRMA. You can read more about ALSA at http://www.alsa-project.org/. ALSA is open source and holds great promise for audio under Linux. Select (uncomment) the proper API #define statement in Object.h.
|
||||
|
||||
STK should compile without much trouble under Linux ... afterall, it is primarily developed on Linux platforms. Since all Linux distributions typically include the GNU makefile utilities, you should be able to use the default Makefile. Typing "make" will initiate the compilation process.
|
||||
|
||||
MIDIATOR SERIAL PORT MIDI SUPPORT:
|
||||
|
||||
STK now has special support for the MIDIator serial port MIDI interface. This is of primary interest to us laptop users, whose computers usually don't have a gameport. If you want to buy one of these devices, make sure you get the MS-124w model (www.midiator.com). For it to work in STK, make sure you uncomment the MIDIATOR define statement in Object.h. This support currently only works within the OSS API framework, though I should be able to get it to work with ALSA in the future as well.
|
||||
|
||||
There are a few things that need to be done on your system to get the MIDIator working. Add the following lines to your bootup sequence in /etc/rc.d/rc.local:
|
||||
|
||||
setserial /dev/ttyS0 baud_base 57600
|
||||
setserial /dev/ttyS0 divisor 1
|
||||
|
||||
You may need to specify the full path to the setserial function, depending on how your PATH variable is set up. Also, you may need to modify the permissions of /dev/ttyS0 (chmod a+rwx). And finally, the MIDIator should be set for "single addresssed" mode (the S/A switch on S and the A/B switch on A), which puts identical output on all 4 MIDI output ports. It is possible to use the MIDIator in a "multi-port" mode, though I'm not currently supporting that in STK.
|
||||
|
||||
NOTE REGARDING PTHREADS:
|
||||
|
||||
There haven't been any problems with threads since the old days of RedHat Linux 5.0. STK uses the MIT pthreads API.
|
||||
|
||||
|
||||
14
doc/README-NeXT.txt
Normal file
14
doc/README-NeXT.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
|
||||
Version 3.2
|
||||
|
||||
By Perry R. Cook, 1995-2000
|
||||
and Gary P. Scavone, 1997-2000.
|
||||
|
||||
Please read the file README.txt for more general STK information.
|
||||
|
||||
STK has always worked under NeXTStep without realtime audio or MIDI support. In general, STK should compile in this way using any generic C++ compiler. C++ exception handling was added to STK with release 3.2. I have had some difficulty testing this release under NeXTStep because our NeXTStep compilers at CCRMA are very old. We tried a newer version of gcc-2.7.2.2 and that mostly worked, though it died trying to compile the BowedBar class. Also, I was unable to locate the correct header for the random() function.
|
||||
|
||||
In summary, I _think_ STK will compile under NeXTStep with a fairly recent compiler, but you may have to do a little work to make it happen. If you do succeed, please let us know.
|
||||
|
||||
Just for clarification, "realtime" support and the use of the __STK_REALTIME_ define statement includes audio and MIDI input/output routines, as well as socket and thread routines for realtime message acquisition (Controller) and internet audio streaming (StrmWvIn, StrmWvOut).
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
|
||||
Version 3.1
|
||||
Version 3.2
|
||||
|
||||
By Perry R. Cook, 1995-2000
|
||||
and Gary P. Scavone, 1997-2000.
|
||||
@@ -8,8 +8,8 @@ Please read the file README.txt for more general STK information.
|
||||
|
||||
It seems that SGI systems are not distributed with the GNU Makefile utilities. The default Make utility has very limited functionality, so your safest bet is to download the GNU Makefile utilities from the Internet and use STK's default Makefile. If this is not possible, try using Makefile.sgi (make -f Makefile.sgi).
|
||||
|
||||
Aside from the Makefile issues, STK should compile and run on SGI platforms without any problems.
|
||||
Another issue that has crept up with this release is proper compiler support for C++ error handling. If you experience problems, you probably don't have a recent version of the C++ compiler. Otherwise, STK should compile and run on SGI platforms without any problems.
|
||||
|
||||
NOTE REGARDING PTHREADS:
|
||||
|
||||
With release 3.1, STK is now using the pthread API under Irix. It appears that pthread functionality is standard on SGI, so this change shouldn't cause any problems. If I'm wrong, let me know!
|
||||
Since release 3.1, STK has used the pthread API under Irix. It appears that pthread functionality is standard on SGI, so this change shouldn't cause any problems. If I'm wrong, let me know!
|
||||
69
doc/README-Win.txt
Normal file
69
doc/README-Win.txt
Normal file
@@ -0,0 +1,69 @@
|
||||
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
|
||||
Version 3.2
|
||||
|
||||
By Perry R. Cook, 1995-2000
|
||||
and Gary P. Scavone, 1997-2000.
|
||||
|
||||
Please read the file README.txt for more general STK information.
|
||||
|
||||
DirectX and WindowsNT Issues:
|
||||
-----------------------------
|
||||
|
||||
STK is currently distributed with Visual C++ 6.0 project and workspace files.
|
||||
|
||||
The STK realtime sound input capabilities under Windoze are only supported using the DirectSoundCapture API. The latency is pretty horrendous, but what do you expect? Also, there is a chance you don't have DirectSoundCapture support on your computer. If not, you should download the DirectX 6.0 (or higher) runtime libraries from Microsoft's WWW site (http://www.microsoft.com/directx/download.asp) in order to run the pre-compiled STK executables for Windoze. The last time I checked, there was no DirectSoundCapture support for WindowsNT ... you'll have to switch to Windows 2000. I stopped supporting the WinMM audio output code with this release. So, if you wish to compile STK under WindowsNT (without realtime audio input support), you'll have to download an older version of STK, uncomment the __WINMM_API_ flag (and comment out the __WINDS_API flag) in Object.h and recompile the source code.
|
||||
|
||||
Realtime sound output under Windoze is supported using the DirectSound (dsound.lib) API. All new versions of Win95/98/NT come with the DirectSound library, but early versions did not. If you have trouble running the distributed executables, then you probably don't have DirectSound installed on your system. You can download the necessary DirectSound stuff from Microsoft's WWW pages (http://www.microsoft.com/directx/download.asp).
|
||||
|
||||
Realtime MIDI input is supported using the winmm.lib API.
|
||||
|
||||
Visual C++ 6.0 workspaces have been created for the various STK projects. Everything has already been configured for you. The intermediate .obj files will be written to either the "Release" or "Debug" directories, but the executable files will be written to the main project directories (where they need to be for proper execution). If you should somehow lose or hose the VC++ workspace file (STK.dsw), then you will have to do a LOT of configuring to recreate it ... it's probably easier just to download the distribution again from our WWW sites. Anyway, for your benefit and mine, here is a list of things that need to be added to the various "Project Settings":
|
||||
|
||||
1. Under General: Set "Output files:" to <blank> (this will put the executable in the main project directory.
|
||||
|
||||
2. Under C/C++ > Code Generation: Set "Use run-time library:" to Multithreaded (use "debug" versions for the debug configuration).
|
||||
|
||||
3. Under Link > General: Add winmm.lib, dsound.lib, and Wsock32.lib to the end of the Object/library modules list.
|
||||
|
||||
4. Under C/C++ > Preprocessor: Add "../../include" directory to the "extra include" field.
|
||||
|
||||
5. Add all the necessary files to the project.
|
||||
|
||||
Remember that items 1-3 above need to be done for each project and for each configuration. There might be an easy way to make global changes, but I couldn't figure it out.
|
||||
|
||||
To use the Tcl/Tk GUIs, you will have to install Tcl/Tk. I got version 8.0 and it works very well (and installed easily). The distribution is available on the WWW and is free.
|
||||
|
||||
In order for socketing to work, it is necessary to have the TCP protocol installed on your computer. This can be done from the "Network" control panel.
|
||||
|
||||
Finally, to use it all -
|
||||
|
||||
|
||||
PLAY SKINI SCOREFILES IN REALTIME:
|
||||
|
||||
syntmono Clarinet -or < scores/streetsf.ski
|
||||
|
||||
|
||||
USE TCL/TK GUIs FOR REALTIME CONTROL:
|
||||
|
||||
1. Open a DOS console window and start syntmono (eg. syntmono Clarinet -or -is).
|
||||
|
||||
2. Double click on a Tcl/Tk file in TCLSpecs (eg. TCLPhys.tcl) from the Windows Explorer to start the GUI. Select the "communications" menu item and "Socket" and make the connection.
|
||||
|
||||
3. Start moving the sliders to control the instrument.
|
||||
|
||||
|
||||
USE REALTIME MIDI INPUT FOR CONTROL:
|
||||
|
||||
1. Open a DOS console window and start syntmono with MIDI input (eg. syntmono Clarinet -or -im).
|
||||
|
||||
This assumes you already have MIDI setup correctly for your computer.
|
||||
|
||||
|
||||
WINDOWS NT ONLY:
|
||||
|
||||
Realtime piping seems to work under WindowsNT in much the same way as on Unix platforms. Thus, it is possible to pipe realtime control data to syntmono under WindowsNT as well.
|
||||
|
||||
|
||||
WINDOWS 2000:
|
||||
|
||||
I don't have Windows 2000 and I doubt I'll get it anytime soon. However, we briefly tested release 3.2 of STK on Perry's Win2000 machine and it worked fine. There is an advantage in using Windows 2000 over 95/98 in that piping works, just as under unix. Also, the scheduler in Win2000 seems to be much better, so socketed messages don't get clumped together like they do in Win 95/98. Since 2000 is supposed to ship with DirectX 7.0, the DirectSoundCapture functionality should work as well.
|
||||
@@ -1,5 +1,5 @@
|
||||
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
|
||||
Version 3.1
|
||||
Version 3.2
|
||||
|
||||
By Perry R. Cook, 1995-2000
|
||||
and Gary P. Scavone, 1997-2000.
|
||||
@@ -9,9 +9,9 @@ Please read the Legal and Ethical notes near the bottom of this document.
|
||||
|
||||
OVERVIEW:
|
||||
|
||||
STK is a set of audio signal processing C++ classes and instruments for music synthesis. You can use these classes to create programs which make cool sounds using a variety of synthesis techniques. This is not a terribly novel concept, except that STK is very portable (it's mostly platform-independent C and C++ code) AND it's completely user-extensible. So, the code you write using STK actually has some chance of working in another 5-10 years. STK currently runs on SGI (Irix), Linux, NeXTStep, and Windows computer platforms. Oh, and it's free for non-commercial use. The only parts of STK that are platform-dependent concern real-time sound and MIDI input and output ... but we've taken care of that for you. The interface for MIDI input and the simple Tcl/Tk graphical user interfaces (GUIs) provided is the same, so it's easy to voice and experiment in real time using either the GUIs or MIDI.
|
||||
STK is a set of audio signal processing C++ classes and instruments for music synthesis. You can use these classes to create programs which make cool sounds using a variety of synthesis techniques. This is not a terribly novel concept, except that STK is very portable (it's mostly platform-independent C and C++ code) AND it's completely user-extensible. So, the code you write using STK actually has some chance of working in another 5-10 years. STK currently runs with "realtime" support (audio and MIDI) on SGI (Irix), Linux, and Windows computer platforms. Generic, non-realtime support has been tested under NeXTStep, but should work with any standard C++ compiler. STK is free for non-commercial use. The only parts of STK that are platform-dependent concern real-time sound, MIDI, and control input and output ... but we've taken care of that for you. The interface for MIDI input and the simple Tcl/Tk graphical user interfaces (GUIs) provided is the same, so it's easy to voice and experiment in real time using either the GUIs or MIDI.
|
||||
|
||||
STK isn't one particular program. Rather, STK is a set of C++ classes that you can use to create your own programs. We've provided a few example applications that demonstrate some of the ways that you could use these classes. But if you have specific needs you will probably have to either modify the example programs or write a new program altogether. Further, the example programs don't have a fancy GUI wrapper. If you feel the need to have a "drag and drop" GUI, you probably don't want to use STK. Spending hundreds of hours making platform-dependent GUI code would go against one of the fundamental design goals of STK - platform independence. STK can generate simultaneous .snd, .wav, and .mat output soundfile formats (beside realtime sound output), so you can view your results using one of the numerous sound/signal analysis tools already available over the WWW (e.g. Snd, Cool Edit, Matlab). For those instances where a simple GUI with sliders and buttons is helpful, we use Tcl/Tk (which is freely distributed for all the STK supported platforms). A number of Tcl/Tk GUI scripts are distributed with the STK release.
|
||||
STK isn't one particular program. Rather, STK is a set of C++ classes that you can use to create your own programs. We've provided a few example applications that demonstrate some of the ways that you could use these classes. But if you have specific needs you will probably have to either modify the example programs or write a new program altogether. Further, the example programs don't have a fancy GUI wrapper. If you feel the need to have a "drag and drop" GUI, you probably don't want to use STK. Spending hundreds of hours making platform-dependent GUI code would go against one of the fundamental design goals of STK - platform independence. STK can generate simultaneous .snd, .wav, .aif, and .mat output soundfile formats (as well as realtime sound output), so you can view your results using one of the numerous sound/signal analysis tools already available over the WWW (e.g. Snd, Cool Edit, Matlab). For those instances where a simple GUI with sliders and buttons is helpful, we use Tcl/Tk (which is freely distributed for all the STK supported platforms). A number of Tcl/Tk GUI scripts are distributed with the STK release.
|
||||
|
||||
|
||||
SYSTEM REQUIREMENTS:
|
||||
@@ -21,33 +21,38 @@ See the individual README's (eg. README-linux) for platform specific information
|
||||
|
||||
WHAT'S NEW:
|
||||
|
||||
STK has undergone several key revisions, changes, and additions since its last release in 1998. Despite being available in one form or another since 1996, we still consider STK to be alpha software. Thus, backward compatability has not been a priority. Please read the ReleaseNotes to see what has changed since the last release.
|
||||
STK has undergone several key revisions, changes, and additions since its last release. Despite being available in one form or another since 1996, we still consider STK to be alpha software. Thus, backward compatability has not been a priority. Please read the ReleaseNotes to see what has changed since the last release.
|
||||
|
||||
Realtime audio input capabilities were added to STK with release 3.0, though the behavior of such is very hardware dependent. Under Linux and Irix, audio input and output are possible with very low latency. Using the Windoze DirectSound API, minimum dependable output sound latency seems to be around 15 milliseconds, while input sound latency is on the order of several hundred milliseconds! It is also possible to generate simultaneous .snd, .wav, .raw, and .mat (Matlab MAT-file) output file types, as well as SKINI scorefiles using MD2SKINI. Finally, STK should compile with non-realtime functionality on any platform with a generic C++ compiler.
|
||||
The control message handling scheme has been simplified greatly with release 3.2 through the use of the Controller class. It is now possible to have access to simultaneous piped, socketed, and/or MIDI input control messages. In most cases, this should eliminate the use of the MD2SKINI program.
|
||||
|
||||
Socketing capabilities were extended in release 3.0 to function under Unix platforms, as well as Windoze platforms. Further, the socket server thread was updated to accept multiple simultaneous socket connections. Thus, it is now possible to have several different socket clients sending SKINI control messages to the server at the same time. Under Linux and Irix, it is also possible to pipe GUI messages through MD2SKINI, enabling both MIDI and GUI control via piping at the same time.
|
||||
Realtime audio input capabilities were added to STK with release 3.0, though the behavior of such is very hardware dependent. Under Linux and Irix, audio input and output are possible with very low latency. Using the Windoze DirectSound API, minimum dependable output sound latency seems to be around 20 milliseconds or so, while input sound latency is on the order of a hundred milliseconds or more!
|
||||
|
||||
As mentioned above, it is possible to record the audio ouput of an STK program to .snd, .wav, .raw, .aif, and .mat (Matlab MAT-file) output file types. Though somewhat obsolete, the program MD2SKINI can be used to write SKINI scorefiles from realtime MIDI input. Finally, STK should compile with non-realtime functionality on any platform with a generic C++ compiler.
|
||||
|
||||
For those who wish to make a library from the core STK classes, there is a Makefile in the src directory that will accomplish that (Linux and SGI only).
|
||||
|
||||
GETTING STARTED:
|
||||
|
||||
A number of example executables are provided with this distribution. The effects directory contains a program that demonstrates realtime duplex mode (simultaneous audio input and output) operation, as well as several simple delay-line based effects algorithms. The MUS151 directory contains a simple two-oscillator program that can be used to demonstrate psychoacoustic masking effects. RagaMatic is a totally cool application for achieving inner piece. The syntmono directory offers a program for monophonic STK instrument playback and manipulation. Syntmono is the primary STK synthesis server and is used to demonstrate all the current STK instruments. MD2SKINI is an executable (currently compiles from the syntmono project) which takes raw MIDI input, converts it to SKINI format, and outputs the result to stdout or any socket host and port ID. Control data (in the form of SKINI messages) can be fed to syntmono through three principal means - SKINI scorefiles, MD2SKINI output, and Tcl/Tk GUIs. A variety of SKINI scorefiles are distributed with STK and can be found in the "scores" directory of the syntmono project.
|
||||
A number of example "projects" are provided with this distribution. The effects directory contains a program that demonstrates realtime duplex mode (simultaneous audio input and output) operation, as well as several simple delay-line based effects algorithms. RagaMatic is a totally cool application for achieving inner peace. The examples directory contains several simple programs which demonstrate audio input/output, as well as the use of the audio internet streaming classes. The syntmono directory offers a program for monophonic STK instrument playback and manipulation. Syntmono is used to demonstrate most of the current STK instruments. Control data (in the form of MIDI or SKINI messages) is acquired by syntmono through pipe, socket, or MIDI connections. Tcl/Tk GUIs are provided which output SKINI formatted messages. A variety of SKINI scorefiles are distributed with STK and can be found in the "scores" directory of the syntmono project. MD2SKINI is an executable (currently compiles from the syntmono project) which takes raw MIDI input, converts it to SKINI format, and outputs the result to stdout or any socket host and port ID.
|
||||
|
||||
Unless you downloaded the distribution with precompiled Windoze binaries, it is necessary to first compile the sources. Under Linux or Irix, simply typing "make" in any of the particular project directories will begin the compilation process. If your Unix system does not have the GNU Makefile utilities, you will have to use one of the platform specific Makefiles (eg. make -f Makefile.sgi). To compile the projects under Windoze, you should use the VC++ project files provided with the STK distribution.
|
||||
Unless you downloaded the distribution with precompiled Windoze binaries, it is necessary to first compile the sources. Under Linux or Irix, simply typing "make" in any of the particular project directories will begin the compilation process. If your Unix system does not have the GNU Makefile utilities, you will have to use one of the platform specific Makefiles (eg. make -f Makefile.sgi). To compile the projects under Windoze, you should use the VC++ 6.0 project files provided with the STK distribution.
|
||||
|
||||
|
||||
SYNTMONO:
|
||||
|
||||
Syntmono is the primary STK synthesis server and is used to demonstrate all the current STK instruments. Syntmono can take realtime control (SKINI) input via pipes or sockets, or it can be fed SKINI scorefile (non-realtime) input. Syntmono can output data in realtime, .wav, .snd, .mat (Matlab MAT-file), and/or .raw formats. Assuming you have successfully compiled the syntmono executable, a scorefile can be redirected to syntmono and the output heard in realtime in the following way:
|
||||
Syntmono is used to demonstrate most of the current STK instruments. Syntmono can take realtime control input via MIDI and/or SKINI format via pipes or sockets, or it can be fed SKINI scorefile (non-realtime) input. Syntmono can output data in realtime, .wav, .snd, .aif, .mat (Matlab MAT-file), and/or .raw formats. Assuming you have successfully compiled the syntmono executable, a scorefile can be redirected to syntmono and the output heard in realtime in the following way:
|
||||
|
||||
syntmono Clarinet -r < scores/streetsf.ski
|
||||
syntmono Clarinet -or < scores/streetsf.ski
|
||||
|
||||
The "-r" flag specifies the realtime output option. Typing syntmono without arguments will provide a brief description of the instruments possible and the various input/output option flags. Tcl/Tk GUIs are provided in the "tcl" directory of each project, though you will have to install Tcl/Tk version 8.0 or higher on your system to use them (older versions of Tcl/Tk under Linux seem to be more forgiving than under IRIX). Realtime SKINI control data (via MD2SKINI or GUIs) can be piped to syntmono on Unix platforms and WinNT in the following way:
|
||||
The "-or" flag specifies the realtime output option. Typing syntmono without arguments will provide a brief description of the instruments possible and the various input/output option flags. Tcl/Tk GUIs are provided in the "tcl" directory of each project, though you will have to install Tcl/Tk version 8.0 or higher on your system to use them (older versions of Tcl/Tk under Linux seem to be more forgiving than under IRIX). Realtime SKINI control data can be piped to syntmono from a Tcl/Tk GUI on Unix platforms and WinNT in the following way:
|
||||
|
||||
MD2SKINI | syntmono Clarinet -r -ip
|
||||
or
|
||||
wish < TCLSpecs/TCLPhys.tcl | syntmono Clarinet -r -ip
|
||||
wish < TCLSpecs/TCLPhys.tcl | syntmono Clarinet -or -ip
|
||||
|
||||
The "-ip" flag specifies piped realtime input. It is not possible to use realtime pipes under Windoze95/98, so socket communication must be used instead. For socket communication, it is necessary to first start the syntmono socket server using the "-is" flag (socketed realtime input). For the time being, a default (hardwired) socket port of 2001 is being used by syntmono. After syntmono is running (and waiting for a socket client connection), either MD2SKINI or a Tcl/Tk GUI can be started. When using the GUI, it is necessary to invoke the "communications" menu item and select "socket" to establish the connection. The same procedure is also possible on Unix platforms.
|
||||
The "-ip" flag specifies piped realtime input. It is not possible to use realtime pipes under Windoze95/98, so socket communication must be used instead. For socket communication, it is necessary to first start the syntmono socket server using the "-is" flag (socketed realtime input). For the time being, a default (hardwired) socket port of 2001 is being used by syntmono. After syntmono is running (and waiting for a socket client connection), a Tcl/Tk GUI can be started. When using the GUI, it is necessary to invoke the "communications" menu item and select "socket" to establish the connection. The same procedure is also possible on Unix platforms. Finally, realtime MIDI control input can be used to control syntmono by typing:
|
||||
|
||||
syntmono Clarinet -or -im
|
||||
|
||||
The "-im" flag specifies realtime MIDI input. It is possible to use piped, socketed, and/or MIDI control input simultaneously.
|
||||
|
||||
|
||||
DISCLAIMER:
|
||||
@@ -68,7 +73,7 @@ The good news is that large hunks of the techniques used here are public domain.
|
||||
|
||||
FURTHER READING:
|
||||
|
||||
For more documentation on this ToolKit, the classes, etc., read the file HIERARCH.txt and the individual class definitions. Also check the platform specific README's for specific system requirements.
|
||||
For more documentation on this ToolKit, the classes, etc., read the file Hierarchy.txt and the individual class definitions. Also check the platform specific README's for specific system requirements.
|
||||
|
||||
|
||||
PERRY'S NOTES FROM THE ORIGINAL DISTRIBUTION:
|
||||
@@ -1,9 +1,28 @@
|
||||
STK: A ToolKit of Audio Synthesis Classes and Instruments in C++
|
||||
Release 3.1
|
||||
Release 3.2
|
||||
|
||||
By Perry R. Cook, 1995-2000
|
||||
and Gary P. Scavone, 1997-2000
|
||||
|
||||
v3.2: (13 November 2000)
|
||||
- new control handling class (Controller)
|
||||
- added AIFF file input/output support
|
||||
- stklib.a Makefile in src directory
|
||||
- added C++ error handling capabilities
|
||||
- added input/output internet streaming support (StrmWvIn/StrmWvOut)
|
||||
- added native ALSA support for linux
|
||||
- added optional "device" argument to all "Rt" classes (audio and MIDI) and printout of devices when argument is invalid
|
||||
- WvIn classes rewritten to support very big files (incremental load from disk)
|
||||
- changed WvIn/WvOut classes to work with sample frame buffers
|
||||
- fixed looping and negative rate calculations in WvIn classes
|
||||
- fixed interpolation bug in RtWvIn
|
||||
- windoze RtAudio code rewritten (thanks Dave!)
|
||||
- simplified byte-swapping functions (in-place swapping)
|
||||
- new FIR filter class (thanks Julius!)
|
||||
- "stereo-ized" RagaMatic
|
||||
- probably a bunch more fixes that I've long since forgotten about
|
||||
|
||||
|
||||
v3.1: (13 March 2000)
|
||||
- new RagaMatic project!!!
|
||||
- added "microphone position" to Mandolin in STKdemo
|
||||
@@ -1,165 +0,0 @@
|
||||
/************** Test Effects Program *********************/
|
||||
|
||||
#include "../STK/RTSoundIO.h"
|
||||
#include "../STK/RTDuplex.h"
|
||||
#include "../STK/SKINI11.h"
|
||||
#include "../STK/SKINI11.msg"
|
||||
#include "../STK/Envelope.h"
|
||||
#include "../STK/PRCRev.h"
|
||||
#include "../STK/JCRev.h"
|
||||
#include "../STK/NRev.h"
|
||||
#include "Echo.h"
|
||||
#include "PitShift.h"
|
||||
#include "Chorus.h"
|
||||
|
||||
// The input command pipe and socket threads are defined in threads.cpp.
|
||||
#include "threads.h"
|
||||
|
||||
int numStrings = 0;
|
||||
int notDone = 1;
|
||||
char **inputString;
|
||||
|
||||
void usage(void) {
|
||||
/* Error function in case of incorrect command-line argument specifications */
|
||||
printf("\nuseage: effects flag \n");
|
||||
printf(" where flag = -ip for realtime SKINI input by pipe\n");
|
||||
printf(" (won't work under Win95/98),\n");
|
||||
printf(" and flag = -is for realtime SKINI input by socket.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
MY_FLOAT inSample = 0.0;
|
||||
MY_FLOAT lastSample = 0.0;
|
||||
MY_FLOAT byte3;
|
||||
long i, synlength;
|
||||
int type, j, outOne = 0, effect = 0, useSocket = 0;
|
||||
|
||||
if (argc != 2) usage();
|
||||
|
||||
if (!strcmp(argv[1],"-is") )
|
||||
useSocket = 1;
|
||||
else if (strcmp(argv[1],"-ip")) {
|
||||
usage();
|
||||
}
|
||||
|
||||
RTDuplex *inout = new RTDuplex(SRATE,1);
|
||||
Echo *echo = new Echo(SRATE); // one second delay
|
||||
PitShift *shifter = new PitShift();
|
||||
Chorus *chorus = new Chorus(5000.0);
|
||||
PRCRev *prcrev = new PRCRev(2.0);
|
||||
JCRev *jcrev = new JCRev(2.0);
|
||||
NRev *nrev = new NRev(2.0);
|
||||
SKINI11 *score = new SKINI11();
|
||||
Envelope *envelope = new Envelope;
|
||||
|
||||
// Start the input thread
|
||||
if (useSocket)
|
||||
startSocketThread();
|
||||
else
|
||||
startPipeThread();
|
||||
|
||||
/* Finally ... the runtime loop begins! */
|
||||
notDone = 1;
|
||||
synlength = RT_BUFFER_SIZE;
|
||||
while(notDone || numStrings) {
|
||||
if (numStrings > 1) synlength = (long) RT_BUFFER_SIZE / numStrings;
|
||||
else synlength = RT_BUFFER_SIZE;
|
||||
for ( i=0; i<synlength; i++ ) {
|
||||
if (effect == 0)
|
||||
inSample = inout->tick(envelope->tick() * echo->tick(lastSample));
|
||||
else if (effect == 1)
|
||||
inSample = inout->tick(envelope->tick() * shifter->tick(lastSample));
|
||||
else if (effect == 2)
|
||||
inSample = inout->tick(envelope->tick() * chorus->tick(lastSample));
|
||||
else if (effect == 3)
|
||||
inSample = inout->tick(envelope->tick() * prcrev->tick(lastSample));
|
||||
else if (effect == 4)
|
||||
inSample = inout->tick(envelope->tick() * jcrev->tick(lastSample));
|
||||
else if (effect == 5)
|
||||
inSample = inout->tick(envelope->tick() * nrev->tick(lastSample));
|
||||
lastSample = inSample;
|
||||
}
|
||||
if (numStrings) {
|
||||
score->parseThis(inputString[outOne]);
|
||||
type = score->getType();
|
||||
if (type > 0) {
|
||||
switch(type) {
|
||||
case __SK_NoteOn_:
|
||||
// check to see if velocity is zero ... really a NoteOff
|
||||
if (( byte3 = score->getByteThree() ) == 0) { // NoteOff
|
||||
envelope->setRate(0.001);
|
||||
envelope->setTarget(0.0);
|
||||
}
|
||||
else { // really a NoteOn
|
||||
envelope->setRate(0.001);
|
||||
envelope->setTarget(1.0);
|
||||
}
|
||||
break;
|
||||
|
||||
case __SK_NoteOff_:
|
||||
envelope->setRate(0.001);
|
||||
envelope->setTarget(0.0);
|
||||
break;
|
||||
|
||||
case __SK_ControlChange_:
|
||||
j = (int) score->getByteTwo();
|
||||
byte3 = score->getByteThree();
|
||||
if (j == 20) effect = (int) byte3; // effect change
|
||||
else if (j == 21) { // effects mix
|
||||
echo->setEffectMix(byte3*NORM_7);
|
||||
shifter->setEffectMix(byte3*NORM_7);
|
||||
chorus->setEffectMix(byte3*NORM_7);
|
||||
prcrev->setEffectMix(byte3*NORM_7);
|
||||
jcrev->setEffectMix(byte3*NORM_7);
|
||||
nrev->setEffectMix(byte3*NORM_7);
|
||||
}
|
||||
else if (j == 22) { // effect1 parameter change
|
||||
echo->setDelay(byte3*NORM_7*SRATE*0.95 + 2);
|
||||
shifter->setShift(byte3*NORM_7*3 + 0.25);
|
||||
chorus->setModFreq(byte3*NORM_7);
|
||||
}
|
||||
else if (j == 23) { // effect1 parameter change
|
||||
chorus->setModDepth(byte3*NORM_7*0.2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
outOne += 1;
|
||||
if (outOne == MAX_IN_STRINGS) outOne = 0;
|
||||
numStrings--;
|
||||
}
|
||||
}
|
||||
|
||||
envelope->setRate(0.001);
|
||||
envelope->setTarget(0.0);
|
||||
for (i=0;i<SRATE;i++) { /* let the sound settle a bit */
|
||||
if (effect == 0)
|
||||
inSample = inout->tick(envelope->tick() * echo->tick(lastSample));
|
||||
else if (effect == 1)
|
||||
inSample = inout->tick(envelope->tick() * shifter->tick(lastSample));
|
||||
else if (effect == 2)
|
||||
inSample = inout->tick(envelope->tick() * chorus->tick(lastSample));
|
||||
else if (effect == 3)
|
||||
inSample = inout->tick(envelope->tick() * prcrev->tick(lastSample));
|
||||
else if (effect == 4)
|
||||
inSample = inout->tick(envelope->tick() * jcrev->tick(lastSample));
|
||||
else if (effect == 5)
|
||||
inSample = inout->tick(envelope->tick() * nrev->tick(lastSample));
|
||||
lastSample = inSample;
|
||||
}
|
||||
|
||||
delete inout;
|
||||
delete echo;
|
||||
delete shifter;
|
||||
delete chorus;
|
||||
delete prcrev;
|
||||
delete jcrev;
|
||||
delete nrev;
|
||||
delete score;
|
||||
delete envelope;
|
||||
|
||||
printf("effects finished ... goodbye.\n");
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
@@ -1,80 +0,0 @@
|
||||
--------------------Configuration: effects - Win32 Release--------------------
|
||||
Begining build with project "D:\gary\stk\effects\effects.dsp", at root.
|
||||
Active configuration is Win32 (x86) Console Application (based on Win32 (x86) Console Application)
|
||||
|
||||
Project's tools are:
|
||||
"32-bit C/C++ Compiler for 80x86" with flags "/nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__OS_Win_" /Fp"Release/effects.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c "
|
||||
"Win32 Resource Compiler" with flags "/l 0x409 /d "NDEBUG" "
|
||||
"Browser Database Maker" with flags "/nologo /o"effects.bsc" "
|
||||
"COFF Linker for 80x86" with flags "kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Wsock32.lib dsound.lib /nologo /subsystem:console /incremental:no /pdb:"effects.pdb" /machine:I386 /out:"effects.exe" "
|
||||
"Custom Build" with flags ""
|
||||
"<Component 0xa>" with flags ""
|
||||
|
||||
Creating temp file "C:\WINDOWS\TEMP\RSP1050.TMP" with contents </nologo /MT /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__OS_Win_" /Fp"Release/effects.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c
|
||||
"D:\gary\stk\effects\Chorus.cpp"
|
||||
"D:\gary\stk\Stk\DLineL.cpp"
|
||||
"D:\gary\stk\Stk\DLineN.cpp"
|
||||
"D:\gary\stk\effects\Echo.cpp"
|
||||
"D:\gary\stk\effects\effects.cpp"
|
||||
"D:\gary\stk\Stk\Envelope.cpp"
|
||||
"D:\gary\stk\Stk\Filter.cpp"
|
||||
"D:\gary\stk\Stk\JCRev.cpp"
|
||||
"D:\gary\stk\Stk\NRev.cpp"
|
||||
"D:\gary\stk\Stk\Object.cpp"
|
||||
"D:\gary\stk\effects\PitShift.cpp"
|
||||
"D:\gary\stk\Stk\PRCRev.cpp"
|
||||
"D:\gary\stk\Stk\RawWvIn.cpp"
|
||||
"D:\gary\stk\Stk\Reverb.cpp"
|
||||
"D:\gary\stk\Stk\RTDuplex.cpp"
|
||||
"D:\gary\stk\Stk\RTSoundIO.cpp"
|
||||
"D:\gary\stk\Stk\SKINI11.cpp"
|
||||
"D:\gary\stk\Stk\swapstuf.cpp"
|
||||
"D:\gary\stk\Stk\WvIn.cpp"
|
||||
>
|
||||
Creating command line "cl.exe @C:\WINDOWS\TEMP\RSP1050.TMP"
|
||||
Creating temp file "C:\WINDOWS\TEMP\RSP1051.TMP" with contents <kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Wsock32.lib dsound.lib /nologo /subsystem:console /incremental:no /pdb:"effects.pdb" /machine:I386 /out:"effects.exe"
|
||||
.\Release\Chorus.obj
|
||||
.\Release\DLineL.obj
|
||||
.\Release\DLineN.obj
|
||||
.\Release\Echo.obj
|
||||
.\Release\effects.obj
|
||||
.\Release\Envelope.obj
|
||||
.\Release\Filter.obj
|
||||
.\Release\JCRev.obj
|
||||
.\Release\NRev.obj
|
||||
.\Release\Object.obj
|
||||
.\Release\PitShift.obj
|
||||
.\Release\PRCRev.obj
|
||||
.\Release\RawWvIn.obj
|
||||
.\Release\Reverb.obj
|
||||
.\Release\RTDuplex.obj
|
||||
.\Release\RTSoundIO.obj
|
||||
.\Release\SKINI11.obj
|
||||
.\Release\swapstuf.obj
|
||||
.\Release\WvIn.obj>
|
||||
Creating command line "link.exe @C:\WINDOWS\TEMP\RSP1051.TMP"
|
||||
Compiling...
|
||||
Chorus.cpp
|
||||
DLineL.cpp
|
||||
DLineN.cpp
|
||||
Echo.cpp
|
||||
effects.cpp
|
||||
Envelope.cpp
|
||||
Filter.cpp
|
||||
JCRev.cpp
|
||||
NRev.cpp
|
||||
Object.cpp
|
||||
PitShift.cpp
|
||||
PRCRev.cpp
|
||||
RawWvIn.cpp
|
||||
Reverb.cpp
|
||||
RTDuplex.cpp
|
||||
RTSoundIO.cpp
|
||||
SKINI11.cpp
|
||||
swapstuf.cpp
|
||||
WvIn.cpp
|
||||
Linking...
|
||||
|
||||
|
||||
|
||||
effects.exe - 0 error(s), 0 warning(s)
|
||||
@@ -1,279 +0,0 @@
|
||||
// Thread functions for use with syntmono.
|
||||
//
|
||||
// No mutexes are currently being used when accessing
|
||||
// the global variables shared between these threads
|
||||
// and the main() routine. In a single processor
|
||||
// environment, no problems have resulted from such data
|
||||
// sharing. However, if STK is to be run on a true parallel
|
||||
// processing platform, it is likely that mutexes will be
|
||||
// necessary. While the mutex calls are simple to code, I
|
||||
// am trying to keep the code as generic as possible. A
|
||||
// quick investigation of threads under Windoze indicates
|
||||
// that mutex functionality is not available, at least with
|
||||
// the standard libraries.
|
||||
//
|
||||
// Gary P. Scavone, 2000.
|
||||
|
||||
#include "threads.h"
|
||||
|
||||
#if defined(__STK_REALTIME_)
|
||||
|
||||
// Default STK socket port ID number
|
||||
#define SERVICE_PORT 2001
|
||||
|
||||
// Do OS dependent declarations and includes
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
|
||||
pthread_t string_thread;
|
||||
|
||||
#elif defined(__OS_Win_)
|
||||
#include <process.h>
|
||||
#include <winsock.h>
|
||||
|
||||
unsigned long string_thread;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// The thread function protocols are slightly different
|
||||
// under Windoze ... but of course!
|
||||
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
|
||||
void *newStringByPipe(void *)
|
||||
|
||||
#elif defined(__OS_Win_)
|
||||
|
||||
void newStringByPipe(void *)
|
||||
|
||||
#endif
|
||||
|
||||
{
|
||||
extern int numStrings, notDone;
|
||||
extern char **inputString;
|
||||
int i;
|
||||
|
||||
// Malloc inputString.
|
||||
inputString = (char **) malloc(MAX_IN_STRINGS * sizeof(char *));
|
||||
for ( i=0;i<MAX_IN_STRINGS;i++ )
|
||||
inputString[i] = (char *) malloc(STRING_LEN * sizeof(char));
|
||||
|
||||
int inOne = 0;
|
||||
while (notDone) {
|
||||
fgets(inputString[inOne],STRING_LEN,stdin);
|
||||
if (inputString[inOne][2] == 'i' && inputString[inOne][3] == 't'
|
||||
&& inputString[inOne][1] == 'x' && inputString[inOne][0] == 'E') {
|
||||
notDone = 0;
|
||||
}
|
||||
else {
|
||||
numStrings++;
|
||||
if (numStrings > MAX_IN_STRINGS) {
|
||||
fprintf(stderr,"Losing MIDI data ... try increasing MAX_IN_STRINGS.\n");
|
||||
numStrings--;
|
||||
}
|
||||
inOne++;
|
||||
if (inOne == MAX_IN_STRINGS) inOne = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Free inputString.
|
||||
for ( i=0;i<MAX_IN_STRINGS;i++ ) free(inputString[i]);
|
||||
free(inputString);
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
pthread_exit(NULL);
|
||||
return NULL;
|
||||
#elif defined(__OS_Win_)
|
||||
_endthread();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
|
||||
void *newStringBySocket(void *)
|
||||
|
||||
#elif defined(__OS_Win_)
|
||||
|
||||
void newStringBySocket(void *)
|
||||
|
||||
#endif
|
||||
|
||||
{
|
||||
extern int numStrings, notDone;
|
||||
extern char **inputString;
|
||||
|
||||
int inOne = 0, i=0, m=0, n, parsing;
|
||||
int soc_id, accept_id;
|
||||
int maxfd, fd;
|
||||
fd_set mask, rmask;
|
||||
struct sockaddr_in sockname;
|
||||
char socBuf[STRING_LEN];
|
||||
static struct timeval timeout = {0, 10000}; // ten millisecond
|
||||
|
||||
// Malloc inputString.
|
||||
inputString = (char **) malloc(MAX_IN_STRINGS * sizeof(char *));
|
||||
for ( i=0;i<MAX_IN_STRINGS;i++ )
|
||||
inputString[i] = (char *) malloc(STRING_LEN * sizeof(char));
|
||||
|
||||
memset(socBuf, 0, sizeof(socBuf));
|
||||
|
||||
#if defined(__OS_Win_) // Stupid Windoze only stuff
|
||||
WSADATA wsaData;
|
||||
WORD wVersionRequested = MAKEWORD(1,1);
|
||||
|
||||
int nRet = WSAStartup(wVersionRequested, &wsaData);
|
||||
if (wsaData.wVersion != wVersionRequested) {
|
||||
fprintf(stderr,"\n Wrong Windoze socket library version!\n");
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create the server-side socket
|
||||
soc_id = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
|
||||
if(soc_id < 0) {
|
||||
fprintf(stderr,"Couldn't create socket ... aborting!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
sockname.sin_family=AF_INET;
|
||||
sockname.sin_addr.s_addr=INADDR_ANY;
|
||||
sockname.sin_port=htons(SERVICE_PORT);
|
||||
|
||||
/* Bind socket to the appropriate port and interface (INADDR_ANY) */
|
||||
if (bind(soc_id,(struct sockaddr *)&sockname,sizeof(sockname)) < 0) {
|
||||
fprintf(stderr,"Couldn't bind socket ... aborting!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Listen for incoming connections */
|
||||
printf("Listening for socket connections on port %d\n", SERVICE_PORT);
|
||||
if (listen(soc_id,SOMAXCONN) < 0) {
|
||||
fprintf(stderr,"Couldn't set up listen on socket ... aborting!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
FD_ZERO(&mask);
|
||||
FD_SET(soc_id, &mask);
|
||||
maxfd = soc_id;
|
||||
|
||||
while (notDone) {
|
||||
rmask = mask;
|
||||
// Need to reset the timeout values because of linux "select" implementation
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 10000; // 0.01 seconds
|
||||
select(maxfd+1, &rmask, (fd_set *)0, (fd_set *)0, &timeout);
|
||||
if (FD_ISSET(soc_id,&rmask)) { // a new connection is available
|
||||
// Accept and service the incoming connection request
|
||||
accept_id=accept(soc_id,NULL,NULL);
|
||||
if (accept_id < 0) {
|
||||
fprintf(stderr,"Couldn't accept incoming connection on socket ... aborting!\n");
|
||||
exit(0);
|
||||
}
|
||||
printf("New socket connection made ... ready to receive SKINI messages.\n");
|
||||
|
||||
FD_SET(accept_id, &mask);
|
||||
if (accept_id > maxfd) maxfd = accept_id;
|
||||
FD_CLR(soc_id, &rmask);
|
||||
}
|
||||
for (fd=0;fd<=maxfd;fd++) { // look for other sockets with data
|
||||
if (FD_ISSET(fd, &rmask)) { // process the data
|
||||
parsing = 1;
|
||||
while (parsing) {
|
||||
i = recv(fd, socBuf, STRING_LEN,0);
|
||||
if (i==0) {
|
||||
printf("Closing a socket connection.\n");
|
||||
FD_CLR(fd, &mask);
|
||||
#if defined(__OS_Win_)
|
||||
closesocket(fd);
|
||||
#else
|
||||
close(fd);
|
||||
#endif
|
||||
parsing = 0;
|
||||
}
|
||||
n = 0;
|
||||
while (n < i) {
|
||||
inputString[inOne][m++] = socBuf[n];
|
||||
if (socBuf[n++] == '\n') {
|
||||
if (inputString[inOne][2] == 'i' && inputString[inOne][3] == 't'
|
||||
&& inputString[inOne][1] == 'x' && inputString[inOne][0] == 'E') {
|
||||
notDone = 0;
|
||||
n = i;
|
||||
parsing = 0;
|
||||
}
|
||||
else {
|
||||
m = 0;
|
||||
if (n >= i) parsing = 0;
|
||||
numStrings++;
|
||||
if (numStrings > MAX_IN_STRINGS) {
|
||||
fprintf(stderr,"Losing MIDI data ... try increasing MAX_IN_STRINGS.\n");
|
||||
numStrings--;
|
||||
}
|
||||
inOne++;
|
||||
if (inOne == MAX_IN_STRINGS) inOne = 0;
|
||||
memset(inputString[inOne], 0, STRING_LEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#if defined(__OS_Win_) // Stupid Windoze only stuff
|
||||
closesocket(soc_id);
|
||||
WSACleanup();
|
||||
#else
|
||||
shutdown(soc_id,0);
|
||||
#endif
|
||||
|
||||
// Free inputString.
|
||||
for ( i=0;i<MAX_IN_STRINGS;i++ ) free(inputString[i]);
|
||||
free(inputString);
|
||||
|
||||
printf("Socket connection closed.\n");
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
pthread_exit(NULL);
|
||||
return NULL;
|
||||
#elif defined(__OS_Win_)
|
||||
_endthread();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void startPipeThread()
|
||||
{
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
if (pthread_create(&string_thread, NULL, newStringByPipe, NULL)) {
|
||||
fprintf(stderr, "unable to create input pipe thread ... aborting.\n");
|
||||
exit(0);
|
||||
}
|
||||
#elif defined(__OS_Win_)
|
||||
string_thread = _beginthread(newStringByPipe, 0, NULL);
|
||||
if (string_thread == -1) {
|
||||
fprintf(stderr, "unable to create input pipe thread ... aborting.\n");
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void startSocketThread()
|
||||
{
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
if (pthread_create(&string_thread, NULL, newStringBySocket, NULL)) {
|
||||
fprintf(stderr, "unable to create input socket thread...aborting.\n");
|
||||
exit(0);
|
||||
}
|
||||
#elif defined(__OS_Win_)
|
||||
string_thread = _beginthread(newStringBySocket, 0, NULL);
|
||||
if (string_thread == -1) {
|
||||
fprintf(stderr, "unable to create input socket thread...aborting.\n");
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,30 +0,0 @@
|
||||
// Thread functions for use with syntmono.
|
||||
//
|
||||
// Gary P. Scavone, 1999.
|
||||
|
||||
#include "../STK/Object.h"
|
||||
|
||||
#define STRING_LEN 60
|
||||
|
||||
/*
|
||||
#if (defined(__STK_REALTIME_) && defined(__OS_IRIX_) )
|
||||
|
||||
void newStringByPipe(void *);
|
||||
void newStringBySocket(void *);
|
||||
|
||||
#elif (defined(__STK_REALTIME_) && defined(__OS_Linux_) )
|
||||
*/
|
||||
#if (defined(__STK_REALTIME_) && (defined(__OS_IRIX_) || defined(__OS_Linux_)))
|
||||
|
||||
void *newStringByPipe(void *);
|
||||
void *newStringBySocket(void *);
|
||||
|
||||
#elif (defined(__STK_REALTIME_) && defined(__OS_Win_) )
|
||||
|
||||
void newStringByPipe(void *);
|
||||
void newStringBySocket(void *);
|
||||
|
||||
#endif
|
||||
|
||||
void startPipeThread();
|
||||
void startSocketThread();
|
||||
30
include/AifWvIn.h
Normal file
30
include/AifWvIn.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*******************************************/
|
||||
/*
|
||||
AifWvIn Input Class,
|
||||
by Gary P. Scavone, 2000
|
||||
|
||||
This object inherits from WvIn and is
|
||||
used to open Audio Interchange File
|
||||
Format files with 16-bit data (signed
|
||||
integer) for playback.
|
||||
|
||||
.aif files are always bif-endian.
|
||||
*/
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__AifWvIn_h)
|
||||
#define __AifWvIn_h
|
||||
|
||||
#include "Object.h"
|
||||
#include "WvIn.h"
|
||||
|
||||
class AifWvIn : public WvIn
|
||||
{
|
||||
public:
|
||||
AifWvIn(char *fileName, const char *mode);
|
||||
~AifWvIn();
|
||||
protected:
|
||||
void getData(long index);
|
||||
};
|
||||
|
||||
#endif
|
||||
32
include/AifWvOut.h
Normal file
32
include/AifWvOut.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*******************************************/
|
||||
/*
|
||||
AifWvOut Output Class,
|
||||
by Gary P. Scavone, 2000
|
||||
|
||||
This object inherits from WvOut and is
|
||||
used to write Audio Interchange File
|
||||
Format files with 16-bit data (signed
|
||||
integer).
|
||||
|
||||
.aif files are always bif-endian.
|
||||
*/
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__AifWvOut_h)
|
||||
#define __AifWvOut_h
|
||||
|
||||
#include "Object.h"
|
||||
#include "WvOut.h"
|
||||
|
||||
class AifWvOut : public WvOut
|
||||
{
|
||||
protected:
|
||||
FILE *fd;
|
||||
public:
|
||||
AifWvOut(char *fileName, int chans = 1);
|
||||
~AifWvOut();
|
||||
void tick(MY_FLOAT sample);
|
||||
void mtick(MY_MULTI samples);
|
||||
};
|
||||
|
||||
#endif
|
||||
40
include/BiQuad.h
Normal file
40
include/BiQuad.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*******************************************/
|
||||
/*
|
||||
BiQuad (2-pole, 2-zero) Filter Class,
|
||||
by Perry R. Cook, 1995-96.
|
||||
Modified by Julius Smith, 2000:
|
||||
setA1,setA2,setB1,setB2
|
||||
|
||||
See books on filters to understand
|
||||
more about how this works. Nothing
|
||||
out of the ordinary in this version.
|
||||
*/
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__BiQuad_h)
|
||||
#define __BiQuad_h
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
class BiQuad : public Filter
|
||||
{
|
||||
protected:
|
||||
MY_FLOAT poleCoeffs[2];
|
||||
MY_FLOAT zeroCoeffs[2];
|
||||
public:
|
||||
BiQuad();
|
||||
~BiQuad();
|
||||
void clear();
|
||||
void setA1(MY_FLOAT a1);
|
||||
void setA2(MY_FLOAT a2);
|
||||
void setB1(MY_FLOAT b1);
|
||||
void setB2(MY_FLOAT b2);
|
||||
void setPoleCoeffs(MY_FLOAT *coeffs);
|
||||
void setZeroCoeffs(MY_FLOAT *coeffs);
|
||||
void setGain(MY_FLOAT aValue);
|
||||
void setFreqAndReson(MY_FLOAT freq, MY_FLOAT reson);
|
||||
void setEqualGainZeroes();
|
||||
MY_FLOAT tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
#endif
|
||||
57
include/BlowHole.h
Normal file
57
include/BlowHole.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/***********************************************/
|
||||
/*
|
||||
Waveguide reed model with a register hole
|
||||
and one tonehole
|
||||
|
||||
by Gary P. Scavone, 2000.
|
||||
*/
|
||||
/***********************************************/
|
||||
|
||||
#if !defined(__BlowHole_h)
|
||||
#define __BlowHole_h
|
||||
|
||||
#include "Instrmnt.h"
|
||||
#include "DLineL.h"
|
||||
#include "ReedTabl.h"
|
||||
#include "OneZero.h"
|
||||
#include "PoleZero.h"
|
||||
#include "Envelope.h"
|
||||
#include "Noise.h"
|
||||
#include "RawWvIn.h"
|
||||
|
||||
class BlowHole : public Instrmnt
|
||||
{
|
||||
protected:
|
||||
DLineL *delays;
|
||||
ReedTabl *reedTable;
|
||||
OneZero *filter;
|
||||
PoleZero *tonehole;
|
||||
PoleZero *vent;
|
||||
Envelope *envelope;
|
||||
Noise *noise;
|
||||
RawWvIn *vibr;
|
||||
long length;
|
||||
MY_FLOAT scatter;
|
||||
MY_FLOAT th_coeff;
|
||||
MY_FLOAT r_th;
|
||||
MY_FLOAT rh_coeff;
|
||||
MY_FLOAT rh_gain;
|
||||
MY_FLOAT outputGain;
|
||||
MY_FLOAT noiseGain;
|
||||
MY_FLOAT vibrGain;
|
||||
public:
|
||||
BlowHole(MY_FLOAT lowestFreq);
|
||||
~BlowHole();
|
||||
void clear();
|
||||
virtual void setFreq(MY_FLOAT frequency);
|
||||
void setTonehole(MY_FLOAT newValue);
|
||||
void setVent(MY_FLOAT newValue);
|
||||
void startBlowing(MY_FLOAT amplitude,MY_FLOAT rate);
|
||||
void stopBlowing(MY_FLOAT rate);
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
virtual void noteOff(MY_FLOAT amp);
|
||||
virtual MY_FLOAT tick();
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -21,11 +21,11 @@ class BowedBar : public Instrmnt
|
||||
protected:
|
||||
BowTabl *bowTabl;
|
||||
ADSR *adsr;
|
||||
BiQuad *bandpass_;
|
||||
|
||||
BiQuad *bandpass;
|
||||
MY_FLOAT maxVelocity;
|
||||
MY_FLOAT modes[4];
|
||||
DLineN delay[4];
|
||||
int NR_MODES;
|
||||
float Zs[4][2];
|
||||
MY_FLOAT coeffs[4][2];
|
||||
float filtOut[4];
|
||||
@@ -38,13 +38,13 @@ class BowedBar : public Instrmnt
|
||||
MY_FLOAT gains[4];
|
||||
MY_FLOAT slope;
|
||||
MY_FLOAT velinput;
|
||||
MY_FLOAT integration_const_;
|
||||
MY_FLOAT integration_const;
|
||||
int trackVel;
|
||||
MY_FLOAT bowvel, bowTarg, bowPos, lastBowPos;
|
||||
int pluck_;
|
||||
int doPluck;
|
||||
|
||||
public:
|
||||
BowedBar(MY_FLOAT lowestFreq=16);
|
||||
BowedBar();
|
||||
~BowedBar();
|
||||
void tuneBandPasses();
|
||||
void clear();
|
||||
@@ -52,11 +52,11 @@ class BowedBar : public Instrmnt
|
||||
void stopBowing(MY_FLOAT rate);
|
||||
void pluck(MY_FLOAT amp);
|
||||
void setStrikePosition(MY_FLOAT position);
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
virtual void noteOff(MY_FLOAT amp);
|
||||
virtual void setFreq(MY_FLOAT frequency);
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
virtual MY_FLOAT tick();
|
||||
void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
void noteOff(MY_FLOAT amp);
|
||||
void setFreq(MY_FLOAT frequency);
|
||||
void controlChange(int number, MY_FLOAT value);
|
||||
MY_FLOAT tick();
|
||||
};
|
||||
|
||||
#endif
|
||||
5
include/ByteSwap.h
Normal file
5
include/ByteSwap.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#include "Object.h"
|
||||
|
||||
void swap16(unsigned char *ptr);
|
||||
void swap32(unsigned char *ptr);
|
||||
void swap64(unsigned char *ptr);
|
||||
119
include/Controller.h
Normal file
119
include/Controller.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/******************************************/
|
||||
/*
|
||||
Controller Class,
|
||||
by Gary P. Scavone, 2000
|
||||
|
||||
This object will accept control messages
|
||||
from a variety of sources, such as a MIDI
|
||||
port, scorefile, socket connection, or
|
||||
pipe. MIDI messages are retrieved with
|
||||
the RtMidi class. All other input sources
|
||||
(scorefile, socket, or pipe) are assumed
|
||||
to provide SKINI formatted messages.
|
||||
|
||||
For each call of getNextMessage(), the
|
||||
active input devices are queried to see
|
||||
if a new control message is available.
|
||||
Only one message per call is returned, so
|
||||
a subsequent call begins querying the
|
||||
next available device "after" the previously
|
||||
handled one.
|
||||
|
||||
This class is primarily for use in STK
|
||||
main() event loops.
|
||||
|
||||
One of my original goals in creating this class
|
||||
was to simplify the message acquisition process
|
||||
by removing all threads. If the windoze
|
||||
select() function behaved just like the unix one,
|
||||
that would have been possible. Since it does not
|
||||
(it can't be used to poll STDIN), I am using a
|
||||
thread to acquire messages from STDIN, which are
|
||||
then sent via a socket connection to the message
|
||||
socket server. Perhaps in the future, I will be
|
||||
able to simplify things.
|
||||
*/
|
||||
/******************************************/
|
||||
|
||||
#if !defined(__Controller_h)
|
||||
#define __Controller_h
|
||||
|
||||
#include "Object.h"
|
||||
#include "SKINI11.h"
|
||||
|
||||
#if defined(__STK_REALTIME_)
|
||||
#include "RtMidi.h"
|
||||
#include "StkError.h"
|
||||
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <pthread.h>
|
||||
#include <netdb.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
void *stdinHandler(void *);
|
||||
|
||||
#elif defined(__OS_Win_)
|
||||
#include <process.h>
|
||||
#include <winsock.h>
|
||||
|
||||
void stdinHandler(void *);
|
||||
|
||||
#endif
|
||||
|
||||
#endif // __STK_REALTIME
|
||||
|
||||
#define STK_MIDI 0x0001
|
||||
#define STK_PIPE 0x0002
|
||||
#define STK_SOCKET 0x0004
|
||||
#define STK_SCOREFILE 0x0008
|
||||
|
||||
#define MESSAGE_LENGTH 128
|
||||
#define MAX_MESSAGES 25
|
||||
#define STK_SOCKET_PORT 2001
|
||||
|
||||
class Controller : public Object
|
||||
{
|
||||
protected:
|
||||
int source;
|
||||
long default_ticks;
|
||||
int type;
|
||||
MY_FLOAT channel;
|
||||
MY_FLOAT byte2;
|
||||
MY_FLOAT byte3;
|
||||
char message[MAX_MESSAGES][MESSAGE_LENGTH];
|
||||
int msg_index;
|
||||
int num_messages;
|
||||
SKINI11 *score;
|
||||
|
||||
#if defined(__STK_REALTIME_)
|
||||
fd_set mask;
|
||||
int maxfd;
|
||||
int fd[16];
|
||||
int local_socket;
|
||||
RtMidi *midi_input;
|
||||
int parseSocketData(int fd);
|
||||
#if (defined(__OS_IRIX_) || defined(__OS_Linux_))
|
||||
pthread_t stdin_thread;
|
||||
#elif defined(__OS_Win_)
|
||||
unsigned long stdin_thread;
|
||||
#endif
|
||||
#endif // __STK_REALTIME
|
||||
|
||||
public:
|
||||
Controller(int inputMask);
|
||||
~Controller();
|
||||
void setDefaultTicks(long nSamples);
|
||||
int getNextMessage();
|
||||
int getType();
|
||||
MY_FLOAT getByte2();
|
||||
MY_FLOAT getByte3();
|
||||
MY_FLOAT getChannel();
|
||||
};
|
||||
|
||||
#endif // defined(__Controller_h)
|
||||
45
include/DLineL.h
Normal file
45
include/DLineL.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*******************************************/
|
||||
/*
|
||||
Linearly Interpolating Delay Line
|
||||
Object by Perry R. Cook 1995-96.
|
||||
Added methods by Julius Smith, 2000.
|
||||
|
||||
This one uses a delay line of maximum
|
||||
length specified on creation, and
|
||||
linearly interpolates fractional
|
||||
length. It is designed to be more
|
||||
efficient if the delay length is not
|
||||
changed very often.
|
||||
*/
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__DLineL_h)
|
||||
#define __DLineL_h
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
class DLineL : public Filter
|
||||
{
|
||||
protected:
|
||||
long inPoint;
|
||||
long outPoint;
|
||||
long length;
|
||||
MY_FLOAT alpha;
|
||||
MY_FLOAT omAlpha;
|
||||
MY_FLOAT currentDelay;
|
||||
public:
|
||||
DLineL();
|
||||
DLineL(long max_length);
|
||||
~DLineL();
|
||||
void clear();
|
||||
void setDelay(MY_FLOAT length);
|
||||
MY_FLOAT delay(void);
|
||||
MY_FLOAT energy(void);
|
||||
long currentInPoint(void);
|
||||
long currentOutPoint(void);
|
||||
MY_FLOAT contentsAt(int n);
|
||||
MY_FLOAT contentsAtNowMinus(int n);
|
||||
MY_FLOAT tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
#endif
|
||||
45
include/DLineN.h
Normal file
45
include/DLineN.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*******************************************/
|
||||
/*
|
||||
Non-Interpolating Delay Line
|
||||
Object by Perry R. Cook 1995-96.
|
||||
Revised by Gary Scavone, 1999.
|
||||
Added methods by Julius Smith, 2000.
|
||||
|
||||
This one uses either a delay line of
|
||||
maximum length specified on creation
|
||||
or a default length of 2047 samples.
|
||||
A non-interpolating delay line is
|
||||
typically used in non-time varying
|
||||
(reverb) applications.
|
||||
*/
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__DLineN_h)
|
||||
#define __DLineN_h
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
class DLineN : public Filter
|
||||
{
|
||||
protected:
|
||||
long inPoint;
|
||||
long outPoint;
|
||||
long length;
|
||||
MY_FLOAT currentDelay;
|
||||
public:
|
||||
DLineN();
|
||||
DLineN(long max_length);
|
||||
~DLineN();
|
||||
void clear();
|
||||
void setDelay(MY_FLOAT length);
|
||||
MY_FLOAT energy(void);
|
||||
long currentInPoint(void);
|
||||
long currentOutPoint(void);
|
||||
MY_FLOAT contentsAt(int n);
|
||||
MY_FLOAT contentsAtNowMinus(int n);
|
||||
MY_FLOAT delay(void);
|
||||
MY_FLOAT tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
34
include/FIR.h
Normal file
34
include/FIR.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/********************************************/
|
||||
/*
|
||||
General Finite-Impulse-Response (FIR)
|
||||
Digital Filter Class
|
||||
by Julius Smith, 1997
|
||||
*/
|
||||
/********************************************/
|
||||
|
||||
#if !defined(__FIR_h)
|
||||
#define __FIR_h
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
class FIR : public Object
|
||||
{
|
||||
protected:
|
||||
int length;
|
||||
MY_FLOAT *coeffs;
|
||||
MY_FLOAT *pastInputs;
|
||||
int piOffset;
|
||||
MY_FLOAT delay;
|
||||
public:
|
||||
FIR(int length);
|
||||
FIR(const char *filterFile);
|
||||
~FIR();
|
||||
void clear(void);
|
||||
void setCoeffs(MY_FLOAT *theCoeffs);
|
||||
MY_FLOAT tick(MY_FLOAT input);
|
||||
MY_FLOAT lastOutput;
|
||||
MY_FLOAT getDelay(MY_FLOAT freq);
|
||||
int getLength(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -25,9 +25,13 @@
|
||||
|
||||
class MatWvIn : public WvIn
|
||||
{
|
||||
public:
|
||||
MatWvIn(char *fileName, char *mode);
|
||||
~MatWvIn();
|
||||
public:
|
||||
MatWvIn(char *fileName, char *mode);
|
||||
~MatWvIn();
|
||||
protected:
|
||||
void getData(long index);
|
||||
int doSwap;
|
||||
int interleaved;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -15,28 +15,20 @@
|
||||
/* specifications. */
|
||||
/*******************************************/
|
||||
|
||||
#include "Object.h"
|
||||
#include "WvOut.h"
|
||||
|
||||
#if !defined(__MatWvOut_h)
|
||||
#define __MatWvOut_h
|
||||
|
||||
#define MAT_BUFFER_SIZE 1024
|
||||
#include "Object.h"
|
||||
#include "WvOut.h"
|
||||
|
||||
class MatWvOut : public WvOut
|
||||
{
|
||||
protected:
|
||||
FILE *fd;
|
||||
double data[MAT_BUFFER_SIZE]; /* not MY_FLOAT because MAT-file uses doubles */
|
||||
INT32 counter;
|
||||
INT32 totalCount;
|
||||
int channels;
|
||||
double *matdata; /* not MY_FLOAT because MAT-file uses doubles */
|
||||
public:
|
||||
MatWvOut(char *infileName);
|
||||
MatWvOut(int chans, char *infileName);
|
||||
MatWvOut(char *infileName, int chans = 1);
|
||||
~MatWvOut();
|
||||
INT32 getCounter();
|
||||
MY_FLOAT getTime();
|
||||
void tick(MY_FLOAT sample);
|
||||
void mtick(MY_MULTI samples);
|
||||
};
|
||||
55
include/Modal4.h
Normal file
55
include/Modal4.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*******************************************/
|
||||
/*
|
||||
Four Resonance Modal Synthesis Instrument
|
||||
by Perry R. Cook, 1995-2000
|
||||
|
||||
This instrument contains an excitation
|
||||
wavetable, an envelope, an oscillator,
|
||||
and four resonances (Non-Sweeping BiQuad
|
||||
Filters).
|
||||
*/
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__Modal4_h)
|
||||
#define __Modal4_h
|
||||
|
||||
#include "Instrmnt.h"
|
||||
#include "Envelope.h"
|
||||
#include "RawWvIn.h"
|
||||
#include "BiQuad.h"
|
||||
#include "OnePole.h"
|
||||
|
||||
class Modal4 : public Instrmnt
|
||||
{
|
||||
protected:
|
||||
Envelope *envelope;
|
||||
RawWvIn *wave;
|
||||
BiQuad *filters[4];
|
||||
OnePole *onepole;
|
||||
RawWvIn *vibr;
|
||||
MY_FLOAT vibrGain;
|
||||
MY_FLOAT masterGain;
|
||||
MY_FLOAT directGain;
|
||||
MY_FLOAT stickHardness;
|
||||
MY_FLOAT strikePosition;
|
||||
MY_FLOAT baseFreq;
|
||||
MY_FLOAT ratios[4];
|
||||
MY_FLOAT resons[4];
|
||||
public:
|
||||
Modal4();
|
||||
virtual ~Modal4();
|
||||
void clear();
|
||||
virtual void setFreq(MY_FLOAT frequency);
|
||||
void setRatioAndReson(int whichOne, MY_FLOAT ratio, MY_FLOAT reson);
|
||||
void setMasterGain(MY_FLOAT aGain);
|
||||
void setDirectGain(MY_FLOAT aGain);
|
||||
void setFiltGain(int whichOne, MY_FLOAT gain);
|
||||
virtual void strike(MY_FLOAT amplitude);
|
||||
virtual void noteOn(MY_FLOAT freq, MY_FLOAT amp);
|
||||
virtual void noteOff(MY_FLOAT amp);
|
||||
void damp(MY_FLOAT amplitude);
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
virtual MY_FLOAT tick();
|
||||
};
|
||||
|
||||
#endif
|
||||
30
include/ModalBar.h
Normal file
30
include/ModalBar.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*******************************************/
|
||||
/*
|
||||
ModalBar SubClass of Modal4 Instrument
|
||||
by Perry R. Cook, 1999-2000
|
||||
|
||||
Controls: CONTROL1 = stickHardness
|
||||
CONTROL2 = strikePosition
|
||||
CONTROL3 = Mode Presets
|
||||
*/
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__ModalBar_h)
|
||||
#define __ModalBar_h
|
||||
|
||||
#include "Modal4.h"
|
||||
|
||||
class ModalBar : public Modal4
|
||||
{
|
||||
private:
|
||||
public:
|
||||
ModalBar();
|
||||
~ModalBar();
|
||||
void setStickHardness(MY_FLOAT hardness);
|
||||
void setStrikePosition(MY_FLOAT position);
|
||||
void setModalPreset(int which);
|
||||
void setModulationDepth(MY_FLOAT mDepth);
|
||||
virtual void controlChange(int number, MY_FLOAT value);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -33,56 +33,34 @@ class Object
|
||||
#elif defined(__OS_Linux_) /* For Linux */
|
||||
#define __STK_REALTIME_
|
||||
#define __OSS_API_ /* Use OSS API */
|
||||
// #define __MIDIATOR_ /* Use special MIDIator support */
|
||||
// #define __ALSA_API_ /* Use ALSA API */
|
||||
#define __LITTLE_ENDIAN__
|
||||
#define RANDLIMIT 2147483647
|
||||
#elif defined(__OS_Win_) /* For WindowsXX or NT */
|
||||
#define __STK_REALTIME_
|
||||
#define __WINDS_API_ /* For DirectSound API */
|
||||
// #define __WINMM_API_ /* For Win MM API */
|
||||
#define __LITTLE_ENDIAN__
|
||||
#define RANDLIMIT 32767
|
||||
#endif
|
||||
|
||||
/* Real-time audio input and output buffer size. The value of
|
||||
* this buffer should be an integer multiple of the number of
|
||||
* channels your application plans to support, in order that
|
||||
* multi-channel data is not split across multiple buffers. If
|
||||
* clicks are occuring in the input or output sound stream, a
|
||||
* larger buffer size may help. Larger buffer sizes, however,
|
||||
* produce more latency between input and output.
|
||||
*
|
||||
* NOTE FOR WINDOZE USERS: Given inherent delays in the audio
|
||||
* input and output mechanism under Windoze, there is a trade-off
|
||||
* between smoothness of fast SKINI parameter updates and input/output
|
||||
* latency as discussed above. You can use buffer sizes as low
|
||||
* as 100 (maybe lower) for delay critical applications, but in
|
||||
* this case SKINI parameter updates will be clumped together
|
||||
* and sound unnatural. If you want smoother parameter updates
|
||||
* and you can live with more delay, try using buffer sizes
|
||||
* closer to 1000. If you need smooth parameter updates AND
|
||||
* low delay, don't use Windoze!
|
||||
/*
|
||||
Real-time audio input and output buffer size. If clicks
|
||||
are occuring in the input or output sound stream, a
|
||||
larger buffer size may help. Larger buffer sizes, however,
|
||||
produce more latency between input and output.
|
||||
*/
|
||||
#define RT_BUFFER_SIZE 256
|
||||
|
||||
/* This sets the maximum number of simultaneous
|
||||
* (within a buffer) MIDI messages that can be
|
||||
* serviced before messages begin to be lost or
|
||||
* overwritten. It should be a function of
|
||||
* RT_BUFFER_SIZE
|
||||
*/
|
||||
#define MAX_IN_STRINGS 25
|
||||
|
||||
/* The following definition is concatenated to the
|
||||
* beginning of all references to rawwave files in
|
||||
* the various STK core classes (ex. Clarinet.cpp).
|
||||
* If you wish to move the rawwaves directory to a
|
||||
* different location in your file system, you will
|
||||
* need to set this path definition appropriately.
|
||||
* The current definition is a relative reference
|
||||
* that will work "out of the box" for the STK
|
||||
* distribution.
|
||||
*/
|
||||
#define RAWWAVE_PATH "../"
|
||||
/*
|
||||
The following definition is concatenated to the beginning
|
||||
of all references to rawwave files in the various STK core
|
||||
classes (ex. Clarinet.cpp). If you wish to move the
|
||||
rawwaves directory to a different location in your file
|
||||
system, you will need to set this path definition
|
||||
appropriately. The current definition is a relative reference
|
||||
that will work "out of the box" for the STK distribution.
|
||||
*/
|
||||
#define RAWWAVE_PATH "../../"
|
||||
|
||||
/* Sampling Rate */
|
||||
#define SRATE (MY_FLOAT) 22050.0
|
||||
@@ -96,8 +74,8 @@ class Object
|
||||
#if !defined(PI)
|
||||
#define PI (MY_FLOAT) 3.14159265359
|
||||
#endif
|
||||
#define TWO_PI (MY_FLOAT) 6.28318530718
|
||||
#define ONE_OVER_TWO_PI (MY_FLOAT) 0.15915494309
|
||||
#define TWO_PI (MY_FLOAT) (MY_FLOAT) (2 * PI)
|
||||
#define ONE_OVER_TWO_PI (MY_FLOAT) (1.0 / PI)
|
||||
#define SQRT_TWO 1.414213562
|
||||
|
||||
/* Useful random number generator values */
|
||||
@@ -141,7 +119,11 @@ typedef MY_FLOAT *MY_MULTI;
|
||||
typedef signed short INT16;
|
||||
|
||||
/* INT32 is just that ... a 32-bit signed integer. */
|
||||
typedef signed long INT32;
|
||||
typedef int INT32;
|
||||
|
||||
/* Boolean values */
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
/* Debugging define, causes massive printf's to come out.
|
||||
* Also enables timing calculations in WaveOut class, other stuff.
|
||||
44
include/OnePole.h
Normal file
44
include/OnePole.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*******************************************/
|
||||
/*
|
||||
One Pole Filter Class,
|
||||
by Perry R. Cook, 1995-96.
|
||||
Added methods by Julius Smith, 2000.
|
||||
|
||||
The parameter gain is an additional
|
||||
gain parameter applied to the filter
|
||||
on top of the normalization that takes
|
||||
place automatically. So the net max
|
||||
gain through the system equals the
|
||||
value of gain. sgain is the combina-
|
||||
tion of gain and the normalization
|
||||
parameter, so if you set the poleCoeff
|
||||
to alpha, sgain is always set to
|
||||
gain * (1.0 - fabs(alpha)).
|
||||
*/
|
||||
/*******************************************/
|
||||
|
||||
#if !defined(__OnePole_h)
|
||||
#define __OnePole_h
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
class OnePole : public Filter
|
||||
{
|
||||
protected:
|
||||
MY_FLOAT poleCoeff;
|
||||
MY_FLOAT sgain;
|
||||
public:
|
||||
OnePole();
|
||||
OnePole(MY_FLOAT thePole);
|
||||
~OnePole();
|
||||
void clear();
|
||||
void setB0(MY_FLOAT aValue); /* set numerator b0 in b0/(1+a1/z) */
|
||||
void setNum(MY_FLOAT *values);
|
||||
void setA1(MY_FLOAT aValue); /* set denominator a1 in b0/(1+a1/z) */
|
||||
void setDen(MY_FLOAT *values);
|
||||
void setPole(MY_FLOAT aValue);
|
||||
void setGain(MY_FLOAT aValue);
|
||||
MY_FLOAT tick(MY_FLOAT sample);
|
||||
};
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user