Version 4.4.4

This commit is contained in:
Gary Scavone
2013-09-29 23:22:28 +02:00
committed by Stephen Sinclair
parent 0aec39260a
commit fc877b87bf
233 changed files with 9035 additions and 5800 deletions

View File

View File

@@ -0,0 +1 @@
wish < tcl/EGuitar.tcl | ./eguitar -or -ip

View File

@@ -0,0 +1 @@
wish < tcl/EGuitar.tcl | eguitar -or -ip

View File

@@ -0,0 +1,71 @@
### Do not edit -- Generated by 'configure --with-whatever' from Makefile.in
### STK eguitar Makefile - for various flavors of unix
PROGRAMS =
RM = /bin/rm
SRC_PATH = ../../src
OBJECT_PATH = @object_path@
vpath %.o $(OBJECT_PATH)
OBJECTS = Stk.o Filter.o Fir.o Delay.o DelayL.o DelayA.o OnePole.o \
Effect.o JCRev.o Twang.o \
Guitar.o Noise.o Cubic.o \
FileRead.o WvIn.o FileWvIn.o FileWrite.o FileWvOut.o \
Skini.o Messager.o utilities.o
INCLUDE = @include@
ifeq ($(strip $(INCLUDE)), )
INCLUDE = ../../include
endif
vpath %.h $(INCLUDE)
CC = @CXX@
DEFS = @CPPFLAGS@
DEFS += @byte_order@
CFLAGS = @CXXFLAGS@
CFLAGS += -I$(INCLUDE) -I$(INCLUDE)/../src/include
LIBRARY = @LIBS@
REALTIME = @realtime@
ifeq ($(REALTIME),yes)
PROGRAMS += eguitar
OBJECTS += RtMidi.o RtAudio.o Thread.o Mutex.o Socket.o TcpServer.o @objects@
endif
RAWWAVES = @rawwaves@
ifeq ($(strip $(RAWWAVES)), )
RAWWAVES = ../../rawwaves/
endif
DEFS += -DRAWWAVE_PATH=\"$(RAWWAVES)\"
%.o : $(SRC_PATH)/%.cpp
$(CC) $(CFLAGS) $(DEFS) -c $(<) -o $(OBJECT_PATH)/$@
%.o : ../../src/include/%.cpp
$(CC) $(CFLAGS) $(DEFS) -c $(<) -o $(OBJECT_PATH)/$@
all : $(PROGRAMS)
eguitar: eguitar.cpp $(OBJECTS)
$(CC) $(LDFLAGS) $(CFLAGS) $(DEFS) -o eguitar eguitar.cpp $(OBJECT_PATH)/*.o $(LIBRARY)
libeguitar: eguitar.cpp
$(CC) $(LDFLAGS) $(CFLAGS) $(DEFS) -o eguitar utilities.cpp eguitar.cpp -L../../src -lstk $(LIBRARY)
$(OBJECTS) : Stk.h
clean :
$(RM) -f $(OBJECT_PATH)/*.o
$(RM) -f $(PROGRAMS) *.exe
$(RM) -fR *~ *.dSYM
distclean: clean
$(RM) Makefile
strip :
strip $(PROGRAMS)
# Project specific objects:
utilities.o: utilities.cpp
$(CC) $(CFLAGS) $(DEFS) -c utilities.cpp -o $(OBJECT_PATH)/$@

View File

@@ -0,0 +1,44 @@
This is eguitar by Gary Scavone, McGill University, 2012.
This is a program to create a simple electric guitar model using
the STK Guitar class. The is model is derived in part from an
implementation made by Nicholas Donaldson at McGill University in
2009. The distortion model is poor, using a simple soft-clipping
expression provided by Charles R. Sullivan in "Extending the
Karplus-String Algorithm to Synthesize Electric Guitar Timbres with
Distortion and Feedback," Computer Music Journal, Vol.14 No.3, Fall
1990. Other distortion models would be better, such as that found
in Pakarinen and Yeh's "A Review of Digital Techniques for Modeling
Vacuum-Tube Guitar Amplifiers," Computer Music Journal, Vol 33
No. 2, Summer 2009.
This program performs simple voice management if all noteOn and
noteOff events are on channel 0. Otherwise, channel values > 0 are
mapped to specific string numbers. By default, the program creates
a 6-string guitar. If the normalized noteOn() velocity is < 0.2, a
string is undamped but not plucked (this is implemented in the
stk::Guitar class). Thus, you can lightly depress a key on a MIDI
keyboard and then experiment with string coupling.
The Tcl/Tk GUI allows you to experiment with various parameter
settings and that can be used in conjunction with a MIDI keyboard
as: wish < tcl/EGuitar.tcl | ./eguitar -or -ip -im 1
For the moment, this program does not support pitch bends.
In the eguitar directory, type:
> make
to compile and then
> ElectricGuitar.bat
to run the program with the Tcl/Tk GUI.
There are many improvements that could be made to this project. In
particular, you could record real body responses from different
guitars and use those with the Guitar class. As well, you could
improve the distortion model and perhaps add some typical electric
guitar effects, such as an echo. If you find any bugs, please let me
know!

View File

View File

@@ -0,0 +1,381 @@
// Eguitar.cpp
//
// This is a program to create a simple electric guitar model using
// the STK Guitar class. The is model is derived in part from an
// implementation made by Nicholas Donaldson at McGill University in
// 2009. The distortion model is poor, using a simple soft-clipping
// expression provided by Charles R. Sullivan in "Extending the
// Karplus-String Algorithm to Synthesize Electric Guitar Timbres with
// Distortion and Feedback," Computer Music Journal, Vol.14 No.3, Fall
// 1990. Other distortion models would be better, such as that found
// in Pakarinen and Yeh's "A Review of Digital Techniques for Modeling
// Vacuum-Tube Guitar Amplifiers," Computer Music Journal, Vol 33
// No. 2, Summer 2009.
//
// This program performs simple voice management if all noteOn and
// noteOff events are on channel 0. Otherwise, channel values > 0 are
// mapped to specific string numbers. By default, the program creates
// a 6-string guitar. If the normalized noteOn() velocity is < 0.2, a
// string is undamped but not plucked (this is implemented in the
// stk::Guitar class). Thus, you can lightly depress a key on a MIDI
// keyboard and then experiment with string coupling.
//
// The Tcl/Tk GUI allows you to experiment with various parameter
// settings and that can be used in conjunction with a MIDI keyboard
// as: wish < tcl/EGuitar.tcl | ./eguitar -or -ip -im 1
//
// For the moment, this program does not support pitch bends.
//
// Gary P. Scavone, McGill University 2012.
#include "Guitar.h"
#include "SKINI.msg"
#include "WvOut.h"
#include "JCRev.h"
#include "Skini.h"
#include "RtAudio.h"
#include "Delay.h"
#include "Cubic.h"
// Miscellaneous command-line parsing and instrument allocation
// functions are defined in utilites.cpp ... specific to this program.
#include "utilities.h"
#include <signal.h>
#include <iostream>
#include <algorithm>
#include <cmath>
using std::min;
bool done;
static void finish(int ignore){ done = true; }
using namespace stk;
const unsigned int nStrings = 6;
// Data structure for string information.
struct StringInfo{
bool inUse; // is this string being used?
unsigned int iNote; // note number associated with this string
StringInfo() : inUse(false), iNote(0) {};
};
// The TickData structure holds all the class instances and data that
// are shared by the various processing functions.
struct TickData {
WvOut **wvout;
Guitar *guitar;
StringInfo voices[nStrings];
JCRev reverb;
Messager messager;
Skini::Message message;
StkFloat volume;
StkFloat t60;
unsigned int nWvOuts;
int channels;
int counter;
bool realtime;
bool settling;
bool haveMessage;
int keysDown;
StkFloat feedbackGain;
StkFloat oldFeedbackGain;
StkFloat distortionGain;
StkFloat distortionMix;
Delay feedbackDelay;
Cubic distortion;
StkFloat feedbackSample;
// Default constructor.
TickData()
: wvout(0), volume(1.0), t60(0.75),
nWvOuts(0), channels(2), counter(0),
realtime( false ), settling( false ), haveMessage( false ),
keysDown(0), feedbackSample( 0.0 ) {}
};
#define DELTA_CONTROL_TICKS 30 // default sample frames between control input checks
// The processMessage() function encapsulates the handling of control
// messages. It can be easily relocated within a program structure
// depending on the desired scheduling scheme.
void processMessage( TickData* data )
{
register StkFloat value1 = data->message.floatValues[0];
register StkFloat value2 = data->message.floatValues[1];
unsigned int channel = (unsigned int) data->message.channel;
switch( data->message.type ) {
case __SK_Exit_:
if ( data->settling == false ) goto settle;
done = true;
return;
case __SK_NoteOn_:
if ( value2 > 0.0 ) { // velocity > 0
unsigned int iNote = data->message.intValues[0];
if ( channel == 0 ) { // do basic voice management
unsigned int s;
if ( data->keysDown >= (int) nStrings ) break; // ignore extra note on's
// Find first unused string
for ( s=0; s<nStrings; s++ )
if ( !data->voices[s].inUse ) break;
if ( s == nStrings ) break;
data->voices[s].inUse = true;
data->voices[s].iNote = iNote;
data->guitar->noteOn( Midi2Pitch[iNote], value2 * ONE_OVER_128, s );
data->keysDown++;
// If first key down, turn on feedback gain
if ( data->keysDown == 1 )
data->feedbackGain = data->oldFeedbackGain;
}
else if ( channel <= nStrings )
data->guitar->noteOn( Midi2Pitch[iNote], value2 * ONE_OVER_128, channel-1 );
break;
}
// else a note off, so continue to next case
case __SK_NoteOff_:
if ( channel == 0 ) { // do basic voice management
if ( !data->keysDown ) break;
// Search for the released note
unsigned int s, iNote;
iNote = data->message.intValues[0];
for ( s=0; s<nStrings; s++ )
if ( data->voices[s].inUse && iNote == data->voices[s].iNote )
break;
if ( s == nStrings ) break;
data->voices[s].inUse = false;
data->guitar->noteOff( value2 * ONE_OVER_128, s );
data->keysDown--;
if ( data->keysDown == 0 ) { // turn off feedback gain and clear delay
data->feedbackDelay.clear();
data->feedbackGain = 0.0;
}
}
else if ( channel <= nStrings )
data->guitar->noteOff( value2 * ONE_OVER_128, channel-1 );
break;
case __SK_ControlChange_:
if ( value1 == 44.0 )
data->reverb.setEffectMix( value2 * ONE_OVER_128 );
else if ( value1 == 7.0 )
data->volume = value2 * ONE_OVER_128;
else if ( value1 == 27 ) // feedback delay
data->feedbackDelay.setDelay( (value2 * Stk::sampleRate() / 127) + 1 );
else if ( value1 == 28 ) { // feedback gain
//data->oldFeedbackGain = value2 * 0.01 / 127.0;
data->oldFeedbackGain = value2 * 0.02 / 127.0;
data->feedbackGain = data->oldFeedbackGain;
}
else if ( value1 == 71 ) // pre-distortion gain
data->distortionGain = 2.0 * value2 * ONE_OVER_128;
else if ( value1 == 72 ) // distortion mix
data->distortionMix = value2 * ONE_OVER_128;
else
data->guitar->controlChange( (int) value1, value2 );
break;
case __SK_AfterTouch_:
data->guitar->controlChange( 128, value1 );
break;
case __SK_PitchBend_:
// Implement me!
break;
case __SK_Volume_:
data->volume = value1 * ONE_OVER_128;
break;
} // end of switch
data->haveMessage = false;
return;
settle:
// Exit and program change messages are preceeded with a short settling period.
for ( unsigned int s=0; s<nStrings; s++ )
if ( data->voices[s].inUse ) data->guitar->noteOff( 0.6, s );
data->counter = (int) (0.3 * data->t60 * Stk::sampleRate());
data->settling = true;
}
// The tick() function handles sample computation and scheduling of
// control updates. If doing realtime audio output, it will be called
// automatically when the system needs a new buffer of audio samples.
int tick( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
double streamTime, RtAudioStreamStatus status, void *dataPointer )
{
TickData *data = (TickData *) dataPointer;
register StkFloat temp, sample, *samples = (StkFloat *) outputBuffer;
int counter, nTicks = (int) nBufferFrames;
while ( nTicks > 0 && !done ) {
if ( !data->haveMessage ) {
data->messager.popMessage( data->message );
if ( data->message.type > 0 ) {
data->counter = (long) (data->message.time * Stk::sampleRate());
data->haveMessage = true;
}
else
data->counter = DELTA_CONTROL_TICKS;
}
counter = min( nTicks, data->counter );
data->counter -= counter;
for ( int i=0; i<counter; i++ ) {
// Put the previous distorted sample thru feedback
sample = data->feedbackDelay.tick( data->feedbackSample * data->feedbackGain );
sample = data->guitar->tick( sample );
// Apply distortion (x - x^3/3) and mix
temp = data->distortionGain * sample;
if ( temp > 0.6666667 ) temp = 0.6666667;
else if ( temp < -0.6666667 ) temp = -0.6666667;
else temp = data->distortion.tick( temp );
sample = (data->distortionMix * temp) + ((1 - data->distortionMix) * sample );
data->feedbackSample = sample;
// Tick instrument and apply reverb
sample = data->volume * data->reverb.tick( sample );
for ( unsigned int j=0; j<data->nWvOuts; j++ ) data->wvout[j]->tick( sample );
if ( data->realtime )
for ( int k=0; k<data->channels; k++ ) *samples++ = sample;
nTicks--;
}
if ( nTicks == 0 ) break;
// Process control messages.
if ( data->haveMessage ) processMessage( data );
}
return 0;
}
int main( int argc, char *argv[] )
{
TickData data;
int i;
#if defined(__STK_REALTIME__)
RtAudio dac;
#endif
// If you want to change the default sample rate (set in Stk.h), do
// it before instantiating any objects! If the sample rate is
// specified in the command line, it will override this setting.
Stk::setSampleRate( 44100.0 );
// By default, warning messages are not printed. If we want to see
// them, we need to specify that here.
Stk::showWarnings( true );
// Check the command-line arguments for errors and to determine
// the number of WvOut objects to be instantiated (in utilities.cpp).
data.nWvOuts = checkArgs( argc, argv );
data.wvout = (WvOut **) calloc( data.nWvOuts, sizeof(WvOut *) );
// Parse the command-line flags, instantiate WvOut objects, and
// instantiate the input message controller (in utilities.cpp).
try {
data.realtime = parseArgs( argc, argv, data.wvout, data.messager );
}
catch (StkError &) {
goto cleanup;
}
// If realtime output, allocate the dac here.
#if defined(__STK_REALTIME__)
if ( data.realtime ) {
RtAudioFormat format = ( sizeof(StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
RtAudio::StreamParameters parameters;
parameters.deviceId = dac.getDefaultOutputDevice();
parameters.nChannels = data.channels;
unsigned int bufferFrames = RT_BUFFER_SIZE;
try {
dac.openStream( &parameters, NULL, format, (unsigned int)Stk::sampleRate(), &bufferFrames, &tick, (void *)&data );
}
catch ( RtError& error ) {
error.printMessage();
goto cleanup;
}
}
#endif
// Set the reverb parameters.
data.reverb.setT60( data.t60 );
data.reverb.setEffectMix( 0.2 );
// Allocate guitar
data.guitar = new Guitar( nStrings );
// Configure distortion and feedback.
data.distortion.setThreshold( 2.0 / 3.0 );
data.distortion.setA1( 1.0 );
data.distortion.setA2( 0.0 );
data.distortion.setA3( -1.0 / 3.0 );
data.distortionMix = 0.9;
data.distortionGain = 1.0;
data.feedbackDelay.setMaximumDelay( (unsigned long int)( 1.1 * Stk::sampleRate() ) );
data.feedbackDelay.setDelay( 20000 );
data.feedbackGain = 0.001;
data.oldFeedbackGain = 0.001;
// Install an interrupt handler function.
(void) signal(SIGINT, finish);
// If realtime output, set our callback function and start the dac.
#if defined(__STK_REALTIME__)
if ( data.realtime ) {
try {
dac.startStream();
}
catch ( RtError &error ) {
error.printMessage();
goto cleanup;
}
}
#endif
// Setup finished.
while ( !done ) {
#if defined(__STK_REALTIME__)
if ( data.realtime )
// Periodically check "done" status.
Stk::sleep( 200 );
else
#endif
// Call the "tick" function to process data.
tick( NULL, NULL, 256, 0, 0, (void *)&data );
}
// Shut down the output stream.
#if defined(__STK_REALTIME__)
if ( data.realtime ) {
try {
dac.closeStream();
}
catch ( RtError& error ) {
error.printMessage();
}
}
#endif
cleanup:
for ( i=0; i<(int)data.nWvOuts; i++ ) delete data.wvout[i];
free( data.wvout );
delete data.guitar;
std::cout << "\nStk eguitar finished ... goodbye.\n\n";
return 0;
}

View File

@@ -0,0 +1,298 @@
# Microsoft Developer Studio Project File - Name="eguitar" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=eguitar - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "ragamat.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "ragamat.mak" CFG="eguitar - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "eguitar - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "eguitar - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "eguitar - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir ""
# PROP Intermediate_Dir "release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__LITTLE_ENDIAN__" /D "__WINDOWS_MM__" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 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 winmm.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "eguitar - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir ""
# PROP Intermediate_Dir "debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\..\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "__WINDOWS_DS__" /D "__LITTLE_ENDIAN__" /D "__WINDOWS_MM__" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 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 winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "eguitar - Win32 Release"
# Name "eguitar - Win32 Debug"
# Begin Source File
SOURCE=..\..\src\Fir.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\Fir.h
# End Source File
# Begin Source File
SOURCE=..\..\src\Delay.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\Delay.h
# End Source File
# Begin Source File
SOURCE=..\..\src\DelayA.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\DelayA.h
# End Source File
# Begin Source File
SOURCE=..\..\src\DelayL.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\DelayL.h
# End Source File
# Begin Source File
SOURCE=..\..\include\Effect.h
# End Source File
# Begin Source File
SOURCE=..\..\src\Twang.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\Twang.h
# End Source File
# Begin Source File
SOURCE=..\..\src\Guitar.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\Guitar.h
# End Source File
# Begin Source File
SOURCE=..\..\src\FileRead.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\FileRead.h
# End Source File
# Begin Source File
SOURCE=..\..\src\FileWrite.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\FileWrite.h
# End Source File
# Begin Source File
SOURCE=..\..\src\FileWvOut.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\FileWvOut.h
# End Source File
# Begin Source File
SOURCE=..\..\src\FileWvIn.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\FileWvIn.h
# End Source File
# Begin Source File
SOURCE=..\..\include\Filter.h
# End Source File
# Begin Source File
SOURCE=..\..\include\Generator.h
# End Source File
# Begin Source File
SOURCE=..\..\src\JCRev.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\JCRev.h
# End Source File
# Begin Source File
SOURCE=..\..\src\Messager.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\Messager.h
# End Source File
# Begin Source File
SOURCE=..\..\src\Mutex.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\Mutex.h
# End Source File
# Begin Source File
SOURCE=..\..\src\Noise.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\Noise.h
# End Source File
# Begin Source File
SOURCE=..\..\include\Cubic.h
# End Source File
# Begin Source File
SOURCE=..\..\src\OnePole.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\OnePole.h
# End Source File
# Begin Source File
SOURCE=.\eguitar.cpp
# End Source File
# Begin Source File
SOURCE=.\utilities.cpp
# End Source File
# Begin Source File
SOURCE=.\utilities.h
# End Source File
# Begin Source File
SOURCE=..\..\src\RtAudio.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\RtAudio.h
# End Source File
# Begin Source File
SOURCE=..\..\src\RtMidi.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\RtMidi.h
# End Source File
# Begin Source File
SOURCE=..\..\src\SKINI.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\SKINI.h
# End Source File
# Begin Source File
SOURCE=..\..\src\Socket.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\Socket.h
# End Source File
# Begin Source File
SOURCE=..\..\src\Stk.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\Stk.h
# End Source File
# Begin Source File
SOURCE=..\..\src\TcpServer.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\TcpServer.h
# End Source File
# Begin Source File
SOURCE=..\..\src\Thread.cpp
# End Source File
# Begin Source File
SOURCE=..\..\include\Thread.h
# End Source File
# Begin Source File
SOURCE=..\..\include\WvIn.h
# End Source File
# Begin Source File
SOURCE=..\..\include\WvOut.h
# End Source File
# End Target
# End Project

View File

@@ -0,0 +1,29 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "eguitar"=.\eguitar.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

View File

@@ -0,0 +1,27 @@
/* Howdy!! SKINI File, Perry Cook */
NoteOn 0.1 0 40 100.000000
NoteOn 0.01 0 44 100.000000
NoteOn 0.01 0 47 100.000000
NoteOn 0.01 0 52 100.000000
NoteOff 1.0 0 40 64.000000
NoteOff 0.0 0 44 64.000000
NoteOff 0.0 0 47 64.000000
NoteOff 0.0 0 52 64.000000
NoteOn 0.3 0 39 100.000000
NoteOn 0.01 0 42 100.000000
NoteOn 0.01 0 47 100.000000
NoteOn 0.01 0 51 100.000000
NoteOff 1.0 0 39 64.000000
NoteOff 0.0 0 42 64.000000
NoteOff 0.0 0 47 64.000000
NoteOff 0.0 0 51 64.000000
NoteOn 0.3 0 40 100.000000
NoteOn 0.01 0 44 100.000000
NoteOn 0.01 0 47 100.000000
NoteOn 0.01 0 52 100.000000
NoteOff 2.0 0 40 64.000000
NoteOff 0.0 0 44 64.000000
NoteOff 0.0 0 47 64.000000
NoteOff 0.0 0 52 64.000000

View File

@@ -0,0 +1,264 @@
# Tcl/Tk Electric Guitar Model GUI for the Synthesis Toolkit (STK)
# by Gary P. Scavone, McGill University, 2012.
# Set lowest string note numbers and range
set stringRange 20
array set stringMin {
1 40
2 45
3 50
4 55
5 59
6 64
}
array set stringNote {
1 40
2 45
3 50
4 55
5 59
6 64
}
#array set stringAmp { 1 64 2 64 3 64 4 64 5 64 6 64 }
array set stringAmp {
1 64
2 64
3 64
4 64
5 64
6 64
}
# Set initial control values
set cont2 20.0
set cont7 100.0
set cont27 64.0
set cont28 0.0
set cont44 24.0
set cont72 64.0
set cont128 64.0
set velocity 64.0
# Configure main window
wm title . "STK Electric Guitar Model Controller"
wm iconname . "guitar"
. config -bg white
# Configure message box
label .message -font {Times 14 normal} -background white \
-foreground darkred -relief raised \
-wraplength 300 -width 60 \
-text "Use the spacebar or button to strum all the strings. Use the pulldown menu next to the velocity slider to control the velocity for individual strings."
pack .message -padx 5 -pady 10
# Configure "note on" buttons
frame .top
button .top.on -text Strum -bg grey66 -command strum
button .top.off -text "All Off" -bg grey66 -command allOff
button .top.exit -text "Quit" -bg grey66 -command quit
pack .top.on -side left -padx 5
pack .top.off -side left -padx 5 -pady 10
pack .top.exit -side left -padx 5 -pady 10
pack .top
frame .left -borderwidth 5 -relief groove -bg grey88
scale .left.volume -from 0 -to 128 -length 200 \
-command {printWhatz "ControlChange 0.0 1 " 7} \
-orient horizontal -label "Volume" \
-tickinterval 32 -showvalue true \
-variable cont7
scale .left.reverb -from 0 -to 128 -length 200 \
-command {printWhatz "ControlChange 0.0 1 " 44} \
-orient horizontal -label "Reverb Mix" \
-tickinterval 32 -showvalue true \
-variable cont44
scale .left.bridge -from 0 -to 128 -length 200 \
-command {printWhatz "ControlChange 0.0 1 " 2} \
-orient horizontal -label "Bridge Coupling Gain" \
-tickinterval 32 -showvalue true -variable cont2
scale .left.fbGain -from 0 -to 128 -length 200 \
-command {printWhatz "ControlChange 0.0 1 " 28} \
-orient horizontal -label "Feedback Gain" \
-tickinterval 32 -showvalue true -variable cont28
scale .left.fbDelay -from 0 -to 128 -length 200 \
-command {printWhatz "ControlChange 0.0 1 " 27} \
-orient horizontal -label "Feedback Delay" \
-tickinterval 32 -showvalue true -variable cont27
scale .left.dmix -from 0 -to 128 -length 200 \
-command {printWhatz "ControlChange 0.0 1 " 72} \
-orient horizontal -label "Distortion Mix" \
-tickinterval 32 -showvalue true -variable cont72
scale .left.pick -from 0 -to 128 -length 200 \
-command {printWhatz "ControlChange 0.0 1 " 128} \
-orient horizontal -label "Pick Hardness" \
-tickinterval 32 -showvalue true -variable cont128
pack .left.volume -padx 10 -pady 5
pack .left.reverb -padx 10 -pady 5
pack .left.bridge -padx 10 -pady 5
pack .left.fbGain -padx 10 -pady 5
pack .left.fbDelay -padx 10 -pady 5
pack .left.dmix -padx 10 -pady 5
pack .left.pick -padx 10 -pady 10
pack .left -side left
proc quit {} {
puts [format "ExitProgram"]
flush stdout
close stdout
exit
}
proc strum {} {
global stringNote stringAmp
for {set n 1} {$n < 7} {incr n} {
puts [format "NoteOn %2.3f %d %3.2f %3.2f" [expr rand()*0.04] $n $stringNote($n) $stringAmp($n)]
}
flush stdout
}
proc allOff {} {
global stringNote stringAmp
for {set n 1} {$n < 7} {incr n} {
puts [format "NoteOff 0.0 %d %3f %3f" $n $stringNote($n) $stringAmp($n)]
}
flush stdout
}
# Set bindings
bind . <KeyPress> { strum }
bind . <Destroy> +quit
proc printWhatz {tag value1 value2 } {
puts [format "%s %2i %3.2f" $tag $value1 $value2]
flush stdout
}
proc pluckOne {value} {
global stringNote stringAmp
puts [format "NoteOn 0.0 %d %3f %3f" $value $stringNote($value) $stringAmp($value)]
flush stdout
}
proc setNote {string value} {
global stringNote
set stringNote($string) $value
}
proc setStringAmp {value} {
global stringAmp cbpath
set n [$cbpath current]
if { $n > 0 } {
set stringAmp($n) $value
} else {
for {set i 1} {$i < 7} {incr i} {
set stringAmp($i) $value
}
}
}
frame .strings -bg grey88 -borderwidth 5 -relief groove
scale .strings.s1 -from $stringMin(1) -to [expr $stringMin(1)+$stringRange] \
-length 350 -orient horizontal -label "String 1: Note Number" \
-tickinterval 5 -showvalue true -variable $stringNote(1) \
-command {setNote 1}
scale .strings.s2 -from $stringMin(2) -to [expr $stringMin(2)+$stringRange] \
-length 350 -orient horizontal -label "String 2: Note Number" \
-tickinterval 5 -showvalue true -variable $stringNote(2) \
-command {setNote 2}
scale .strings.s3 -from $stringMin(3) -to [expr $stringMin(3)+$stringRange] \
-length 350 -orient horizontal -label "String 3: Note Number" \
-tickinterval 5 -showvalue true -variable $stringNote(3) \
-command {setNote 3}
scale .strings.s4 -from $stringMin(4) -to [expr $stringMin(4)+$stringRange] \
-length 350 -orient horizontal -label "String 4: Note Number" \
-tickinterval 5 -showvalue true -variable $stringNote(4) \
-command {setNote 4}
scale .strings.s5 -from $stringMin(5) -to [expr $stringMin(5)+$stringRange] \
-length 350 -orient horizontal -label "String 5: Note Number" \
-tickinterval 5 -showvalue true -variable $stringNote(5) \
-command {setNote 5}
scale .strings.s6 -from $stringMin(6) -to [expr $stringMin(6)+$stringRange] \
-length 350 -orient horizontal -label "String 6: Note Number" \
-tickinterval 5 -showvalue true -variable $stringNote(6) \
-command {setNote 6}
button .strings.b1 -text Pluck -command { pluckOne 1 }
button .strings.b2 -text Pluck -command { pluckOne 2 }
button .strings.b3 -text Pluck -command { pluckOne 3 }
button .strings.b4 -text Pluck -command { pluckOne 4 }
button .strings.b5 -text Pluck -command { pluckOne 5 }
button .strings.b6 -text Pluck -command { pluckOne 6 }
grid .strings -column 0 -row 0
grid .strings.b1 -column 1 -row 0 -padx 5 -pady 5
grid .strings.b2 -column 1 -row 1
grid .strings.b3 -column 1 -row 2
grid .strings.b4 -column 1 -row 3
grid .strings.b5 -column 1 -row 4
grid .strings.b6 -column 1 -row 5
grid .strings.s1 -column 0 -row 0 -padx 5 -pady 5
grid .strings.s2 -column 0 -row 1 -padx 5 -pady 5
grid .strings.s3 -column 0 -row 2 -padx 5 -pady 5
grid .strings.s4 -column 0 -row 3 -padx 5 -pady 5
grid .strings.s5 -column 0 -row 4 -padx 5 -pady 5
grid .strings.s6 -column 0 -row 5 -padx 5 -pady 5
set stringSelect "All"
ttk::combobox .strings.combo \
-values [ list "All" "String 1" "String 2" "String 3" "String 4" "String 5" "String 6" ] \
-width 8 -textvariable stringSelect -justify center
scale .strings.velocity -from 0 -to 128 -length 350 \
-orient horizontal -label "Note Velocity" \
-tickinterval 32 -showvalue true -command setStringAmp -variable velocity
grid .strings.combo -column 1 -row 7
grid .strings.velocity -column 0 -row 7 -padx 5 -pady 10
pack .strings
set cbpath .strings.combo
bind . <Configure> { center_the_toplevel %W }
proc center_the_toplevel { w } {
# Callback on the <Configure> event for a toplevel
# that should be centered on the screen
# Make sure that we aren't configuring a child window
if { [string equal $w [winfo toplevel $w]] } {
# Calculate the desired geometry
set width [winfo reqwidth $w]
set height [winfo reqheight $w]
set x [expr { ( [winfo vrootwidth $w] - $width ) / 2 }]
set y [expr { ( [winfo vrootheight $w] - $height ) / 2 }]
#set y 0
# Hand the geometry off to the window manager
wm geometry $w ${width}x${height}+${x}+${y}
# Unbind <Configure> so that this procedure is
# not called again when the window manager finishes
# centering the window. Also, revert geometry management
# to internal default for subsequent size changes.
bind $w <Configure> {}
wm geometry $w ""
}
return
}

View File

@@ -0,0 +1,207 @@
// Miscellaneous parsing and error functions for use with STK projects.
//
// Gary P. Scavone, 1999.
#include "utilities.h"
#include <cstring>
#include <stdlib.h>
#if defined(__STK_REALTIME__)
#include "RtAudio.h"
#endif
using namespace stk;
void usage(char *function) {
// Error function in case of incorrect command-line argument specifications
printf("\nusage: %s flag(s)\n", function);
printf(" where flag(s) = \n");
printf(" -s RATE to specify a sample rate,\n");
printf(" -ow <file name> for .wav audio output file,\n");
printf(" -os <file name> for .snd audio output file,\n");
printf(" -om <file name> for .mat audio output file,\n");
printf(" -oa <file name> for .aif audio output file,\n");
printf(" -if <file name> to read control input from SKINI file,\n");
#if defined(__STK_REALTIME__)
printf(" -or for realtime audio output,\n");
printf(" -ip for realtime control input by pipe,\n");
printf(" -im <port> for realtime control input by MIDI (virtual port = 0, default = 1).");
#endif
printf("\n");
printf("\n Simultaneous multiple output types are supported.\n");
printf(" Likewise, simultaneous control input types are supported.\n");
printf(" SKINI formatted scorefiles can be piped or redirected\n");
printf(" to %s, though realtime control flags should be omitted\n", function);
printf(" when doing so. If the optional <file names> are not\n");
printf(" specified, default names will be indicated. Each flag\n");
printf(" must include its own '-' sign.\n\n");
exit(0);
}
int checkArgs(int nArgs, char *args[])
{
int w, i = 1, j = 0;
int nWvOuts = 0;
char flags[2][50] = {""};
bool realtime = false;
if (nArgs < 3 || nArgs > 22) usage(args[0]);
while (i < nArgs) {
if (args[i][0] == '-') {
if (args[i][1] == 'o') {
if ( args[i][2] == 'r' ) realtime = true;
if ( (args[i][2] == 's') || (args[i][2] == 'w') ||
(args[i][2] == 'm') || (args[i][2] == 'a') )
nWvOuts++;
flags[0][j] = 'o';
flags[1][j++] = args[i][2];
}
else if (args[i][1] == 'i') {
if ( (args[i][2] != 'p') &&
(args[i][2] != 'm') && (args[i][2] != 'f') ) usage(args[0]);
flags[0][j] = 'i';
flags[1][j++] = args[i][2];
}
else if (args[i][1] == 's' && (i+1 < nArgs) && args[i+1][0] != '-' ) {
Stk::setSampleRate( atoi(args[i+1]) );
flags[0][j++] = 's';
}
else usage(args[0]);
}
i++;
}
// Check for multiple flags of the same type
for ( i=0; i<=j; i++ ) {
w = i+1;
while (w <= j ) {
if ( flags[0][i] == flags[0][w] && flags[1][i] == flags[1][w] ) {
printf("\nError: Multiple command line flags of the same type specified.\n\n");
usage(args[0]);
}
w++;
}
}
// Make sure we have at least one output type
if ( nWvOuts < 1 && !realtime ) usage(args[0]);
return nWvOuts;
}
bool parseArgs(int nArgs, char *args[], WvOut **output, Messager& messager)
{
int i = 1, j = 0, nWvIns = 0;
bool realtime = false;
char fileName[256];
while (i < nArgs) {
if ( (args[i][0] == '-') && (args[i][1] == 'i') ) {
switch(args[i][2]) {
case 'f':
strcpy(fileName,args[++i]);
if ( !messager.setScoreFile( fileName ) ) exit(0);
nWvIns++;
break;
case 'p':
#if defined(__STK_REALTIME__)
if ( !messager.startStdInput() ) exit(0);
nWvIns++;
break;
#else
usage(args[0]);
#endif
case 'm':
#if defined(__STK_REALTIME__)
// Check for an optional MIDI port argument.
if ((i+1 < nArgs) && args[i+1][0] != '-') {
int port = atoi(args[++i]);
if ( !messager.startMidiInput( port-1 ) ) exit(0);
}
else if ( !messager.startMidiInput() ) exit(0);
nWvIns++;
break;
#else
usage(args[0]);
#endif
default:
usage(args[0]);
break;
}
}
else if ( (args[i][0] == '-') && (args[i][1] == 'o') ) {
switch(args[i][2]) {
case 'r':
#if defined(__STK_REALTIME__)
realtime = true;
break;
#else
usage(args[0]);
#endif
case 'w':
if ((i+1 < nArgs) && args[i+1][0] != '-') {
i++;
strcpy(fileName,args[i]);
}
else strcpy(fileName,"testwav");
output[j] = new FileWvOut(fileName, 1, FileWrite::FILE_WAV );
j++;
break;
case 's':
if ((i+1 < nArgs) && args[i+1][0] != '-') {
i++;
strcpy(fileName,args[i]);
}
else strcpy(fileName,"testsnd");
output[j] = new FileWvOut(fileName,1, FileWrite::FILE_SND);
j++;
break;
case 'm':
if ((i+1 < nArgs) && args[i+1][0] != '-') {
i++;
strcpy(fileName,args[i]);
}
else strcpy(fileName,"testmat");
output[j] = new FileWvOut(fileName,1, FileWrite::FILE_MAT);
j++;
break;
case 'a':
if ((i+1 < nArgs) && args[i+1][0] != '-') {
i++;
strcpy(fileName,args[i]);
}
else strcpy(fileName,"testaif");
output[j] = new FileWvOut(fileName,1, FileWrite::FILE_AIF );
j++;
break;
default:
usage(args[0]);
break;
}
}
i++;
}
if ( nWvIns == 0 ) {
#if defined(__STK_REALTIME__)
if ( !messager.startStdInput() ) exit(0);
#else
printf("\nError: The -if file input flag must be specified for non-realtime use.\n\n");
usage(args[0]);
#endif
}
return realtime;
}

View File

@@ -0,0 +1,12 @@
// Miscellaneous parsing and error functions for use with STK projects.
//
// Gary P. Scavone, 1999.
#include "FileWvOut.h"
#include "Messager.h"
void usage(char *function);
int checkArgs(int numArgs, char *args[]);
bool parseArgs(int numArgs, char *args[], stk::WvOut **output, stk::Messager& messager);