mirror of
https://github.com/thestk/stk
synced 2026-01-18 07:01:53 +00:00
Version 4.2.0
This commit is contained in:
committed by
Stephen Sinclair
parent
cf06b7598b
commit
a6381b9d38
@@ -6,71 +6,171 @@
|
||||
(via the RtMidi class), parses it, and turns it
|
||||
into SKINI messages.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2002.
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2004.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "RtMidi.h"
|
||||
#include "Thread.h"
|
||||
#include "Socket.h"
|
||||
#include "SKINI.msg"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Exit thread declaration.
|
||||
extern "C" THREAD_RETURN THREAD_TYPE stdinMonitor(void * ptr);
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
void usage(void) {
|
||||
printf("\nuseage: Md2Skini <flag(s)>\n\n");
|
||||
printf(" With no arguments, Md2Skini converts MIDI input to SKINI\n");
|
||||
printf(" format and sends the output directly to stdout.\n");
|
||||
printf(" With flag = -s <hostname>, the output is sent over a socket\n");
|
||||
printf(" connection (port 2001) to the optional hostname (default = localhost).\n");
|
||||
printf(" With flag = -f <filename>, the output stream is simultaneously\n");
|
||||
printf(" written to the file specified by the optional <filename>\n");
|
||||
printf(" (default = test.ski).\n\n");
|
||||
std::cout << "\nuseage: Md2Skini <flag(s)>\n\n";
|
||||
std::cout << " With no arguments, Md2Skini converts MIDI input to SKINI\n";
|
||||
std::cout << " format and sends the output directly to stdout.\n";
|
||||
std::cout << " With flag = -f <filename>, the output stream is simultaneously\n";
|
||||
std::cout << " written to the file specified by the optional <filename>\n";
|
||||
std::cout << " (default = test.ski).\n";
|
||||
std::cout << " A MIDI input port can be specified with flag = -p portNumber.\n" << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
void midiCallback( double deltatime, std::vector< unsigned char > *bytes, void *userData )
|
||||
{
|
||||
bool done = false, firstMessage = true, writeFile = false, useSocket = false;
|
||||
FILE *file = NULL;
|
||||
char fileName[256];
|
||||
char hostName[128];
|
||||
RtMidi *rtmidi = 0;
|
||||
Socket *soket = 0;
|
||||
Thread *thread = 0;
|
||||
if ( bytes->size() < 2 ) return;
|
||||
|
||||
if ( argc>5 ) {
|
||||
usage();
|
||||
// Parse the MIDI bytes ... only keep MIDI channel messages.
|
||||
if ( bytes->at(0) > 239 ) return;
|
||||
|
||||
register long type = bytes->at(0) & 0xF0;
|
||||
register long channel = bytes->at(0) & 0x0F;
|
||||
register long databyte1 = bytes->at(1);
|
||||
register long databyte2 = 0;
|
||||
if ( ( type != 0xC0 ) && ( type != 0xD0 ) ) {
|
||||
if ( bytes->size() < 3 ) return;
|
||||
databyte2 = bytes->at(2);
|
||||
}
|
||||
|
||||
std::string typeName;
|
||||
switch( type ) {
|
||||
case __SK_NoteOn_:
|
||||
if ( databyte2 == 0 ) {
|
||||
typeName = "NoteOff\t\t";
|
||||
databyte2 = 64;
|
||||
}
|
||||
else typeName = "NoteOn\t\t";
|
||||
break;
|
||||
|
||||
case __SK_NoteOff_:
|
||||
typeName = "NoteOff\t\t";
|
||||
break;
|
||||
|
||||
case __SK_PolyPressure_:
|
||||
typeName = "PolyPressure\t";
|
||||
break;
|
||||
|
||||
case __SK_ProgramChange_:
|
||||
typeName = "ProgramChange\t";
|
||||
break;
|
||||
|
||||
case __SK_ChannelPressure_:
|
||||
typeName = "ChannelPressure\t";
|
||||
break;
|
||||
|
||||
case __SK_PitchBend_:
|
||||
typeName = "PitchBend\t";
|
||||
break;
|
||||
|
||||
case __SK_ControlChange_:
|
||||
|
||||
switch( databyte1 ) {
|
||||
case __SK_PitchChange_:
|
||||
typeName = "PitchChange\t";
|
||||
break;
|
||||
|
||||
case __SK_Volume_:
|
||||
typeName = "Volume\t";
|
||||
break;
|
||||
|
||||
case __SK_ModWheel_:
|
||||
typeName = "ModWheel\t";
|
||||
break;
|
||||
|
||||
case __SK_Breath_:
|
||||
typeName = "Breath\t\t";
|
||||
break;
|
||||
|
||||
case __SK_FootControl_:
|
||||
typeName = "FootControl\t";
|
||||
break;
|
||||
|
||||
case __SK_Portamento_:
|
||||
typeName = "Portamento\t";
|
||||
break;
|
||||
|
||||
case __SK_Balance_:
|
||||
typeName = "Balance\t";
|
||||
break;
|
||||
|
||||
case __SK_Pan_:
|
||||
typeName = "Pan\t\t";
|
||||
break;
|
||||
|
||||
case __SK_Sustain_:
|
||||
typeName = "Sustain\t";
|
||||
break;
|
||||
|
||||
case __SK_Expression_:
|
||||
typeName = "Expression\t";
|
||||
break;
|
||||
|
||||
default:
|
||||
typeName = "ControlChange\t";
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
typeName = "Unknown\t";
|
||||
}
|
||||
|
||||
FILE *file = (FILE *) userData;
|
||||
if ( type == 0xC0 || type == 0xD0 || type == 0xE0 ) { // program change, channel pressure, or pitchbend
|
||||
fprintf( stdout, "%s %.3f %d %.1f\n", typeName.c_str(), 0.0, channel, (float)databyte1 );
|
||||
if ( file != NULL )
|
||||
fprintf( file, "%s %.3f %d %.1f\n", typeName.c_str(), deltatime, channel, (float)databyte1 );
|
||||
}
|
||||
else if ( type == 0xB0 ) { // control change
|
||||
fprintf( stdout, "%s %.3f %d %.1f\n", typeName.c_str(), 0.0, channel, (float)databyte2 );
|
||||
if ( file != NULL )
|
||||
fprintf( file, "%s %.3f %d %.1f\n", typeName.c_str(), deltatime, channel, (float)databyte2 );
|
||||
}
|
||||
else { // noteon, noteoff, aftertouch, and unknown
|
||||
fprintf( stdout, "%s %.3f %d %.1f %.1f\n", typeName.c_str(), 0.0, channel, (float)databyte1, (float)databyte2 );
|
||||
if ( file != NULL )
|
||||
fprintf( file, "%s %.3f %d %.1f %.1f\n", typeName.c_str(), deltatime, channel, (float)databyte1, (float)databyte2 );
|
||||
}
|
||||
}
|
||||
|
||||
int main( int argc,char *argv[] )
|
||||
{
|
||||
FILE *file = NULL;
|
||||
std::string fileName;
|
||||
RtMidiIn *midiin = 0;
|
||||
unsigned int port = 0;
|
||||
|
||||
if ( argc > 5 ) usage();
|
||||
|
||||
// Parse the command-line arguments.
|
||||
int i = 1;
|
||||
while (i < argc) {
|
||||
while ( i < argc ) {
|
||||
if (argv[i][0] == '-') {
|
||||
switch(argv[i][1]) {
|
||||
|
||||
case 's':
|
||||
if ((i+1 < argc) && argv[i+1][0] != '-') {
|
||||
i++;
|
||||
strncpy(hostName, argv[i], 128);
|
||||
}
|
||||
else strcpy(hostName, "localhost");
|
||||
useSocket = true;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
if ((i+1 < argc) && argv[i+1][0] != '-') {
|
||||
if ( (i+1 < argc) && argv[i+1][0] != '-' ) {
|
||||
i++;
|
||||
strncpy(fileName, argv[i], 252);
|
||||
if ( strstr(fileName,".ski") == NULL ) strcat(fileName, ".ski");
|
||||
fileName = argv[i];
|
||||
if ( fileName.find( ".ski" ) == std::string::npos ) fileName.append( ".ski" );
|
||||
}
|
||||
else strcpy(fileName, "test.ski");
|
||||
file = fopen(fileName,"wb");
|
||||
writeFile = true;
|
||||
else fileName = "test.ski";
|
||||
file = fopen( fileName.c_str(), "wb" );
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
if ( i++ >= argc) usage();
|
||||
port = (unsigned int) atoi( argv[i] );
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -82,234 +182,51 @@ int main(int argc,char *argv[])
|
||||
i++;
|
||||
}
|
||||
|
||||
MY_FLOAT dt=0.0;
|
||||
try {
|
||||
rtmidi = new RtMidi();
|
||||
midiin = new RtMidiIn();
|
||||
}
|
||||
catch (StkError &) {
|
||||
exit(0);
|
||||
catch (RtError &error) {
|
||||
error.printMessage();
|
||||
if ( file != NULL ) fclose( file );
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// If using sockets, setup the client socket
|
||||
if (useSocket) {
|
||||
try {
|
||||
soket = new Socket( 2001, hostName );
|
||||
}
|
||||
catch (StkError &) {
|
||||
exit(0);
|
||||
}
|
||||
// Check available ports vs. specified.
|
||||
unsigned int nPorts = midiin->getPortCount();
|
||||
if ( nPorts == 0 ) {
|
||||
std::cout << "No MIDI ports available!\n";
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Start the "exit" thread.
|
||||
thread = new Thread();
|
||||
if ( !thread->start( (THREAD_FUNCTION)&stdinMonitor, (void *) &done ) ) {
|
||||
fprintf(stderr, "Unable to create exit thread ... aborting.\n");
|
||||
else if ( port >= nPorts ) {
|
||||
std::cout << "Invalid port specifier!\n";
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Write SKINI messages to buffer 's'. This is the easiest way to
|
||||
// allow this single executable to work for both socketing and
|
||||
// printf's to stdout.
|
||||
char s[128];
|
||||
int channel, j;
|
||||
MY_FLOAT byte2, byte3;
|
||||
while ( !done ) {
|
||||
if (rtmidi->nextMessage() > 0) {
|
||||
byte3 = rtmidi->getByteThree();
|
||||
byte2 = rtmidi->getByteTwo();
|
||||
channel = rtmidi->getChannel();
|
||||
if (writeFile) dt = rtmidi->getDeltaTime();
|
||||
if (firstMessage) { // first MIDI message time stamp is meaningless
|
||||
dt = 0.0;
|
||||
firstMessage = false;
|
||||
}
|
||||
|
||||
switch(rtmidi->getType()) {
|
||||
case __SK_NoteOn_:
|
||||
if (byte3 < 1.0) {
|
||||
sprintf(s,"NoteOff\t\t%.3f %d %.1f %.1f\n",0.0,channel,byte2,64.0);
|
||||
if (writeFile) {
|
||||
fprintf(file,"NoteOff\t\t%.3f %d %.1f %.1f\n",dt,channel,byte2,64.0);
|
||||
}
|
||||
} else {
|
||||
sprintf(s,"NoteOn\t\t%.3f %d %.1f %.1f\n",0.0,channel,byte2,byte3);
|
||||
if (writeFile) {
|
||||
fprintf(file,"NoteOn\t\t%.3f %d %.1f %.1f\n",dt,channel,byte2,byte3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case __SK_NoteOff_:
|
||||
if (byte3 < 2.0) byte3 = 64.0;
|
||||
sprintf(s,"NoteOff\t\t%.3f %d %.1f %.1f\n",0.0,channel,byte2,byte3);
|
||||
if (writeFile) {
|
||||
fprintf(file,"NoteOff\t\t%.3f %d %.1f %.1f\n",dt,channel,byte2,byte3);
|
||||
}
|
||||
break;
|
||||
|
||||
case __SK_PolyPressure_:
|
||||
sprintf(s,"PolyPressure\t%.3f %d %.1f %.1f\n",0.0,channel,byte2,byte3);
|
||||
if (writeFile) {
|
||||
fprintf(file,"PolyPressure\t%.3f %d %.1f %.1f\n",dt,channel,byte2,byte3);
|
||||
}
|
||||
break;
|
||||
|
||||
case __SK_ControlChange_:
|
||||
j = (int) byte2;
|
||||
switch(j) {
|
||||
case __SK_PitchChange_:
|
||||
sprintf(s,"PitchChange\t%.3f %d %.1f\n",0.0,channel,byte3);
|
||||
if (writeFile) {
|
||||
fprintf(file,"PitchChange\t%.3f %d %.1f\n",dt,channel,byte3);
|
||||
}
|
||||
break;
|
||||
case __SK_Volume_:
|
||||
sprintf(s,"Volume\t%.3f %d %.1f\n",0.0,channel,byte3);
|
||||
if (writeFile) {
|
||||
fprintf(file,"Volume\t%.3f %d %.1f\n",dt,channel,byte3);
|
||||
}
|
||||
break;
|
||||
case __SK_ModWheel_:
|
||||
sprintf(s,"ModWheel\t%.3f %d %.1f\n",0.0,channel,byte3);
|
||||
if (writeFile) {
|
||||
fprintf(file,"ModWheel\t%.3f %d %.1f\n",dt,channel,byte3);
|
||||
}
|
||||
break;
|
||||
case __SK_Breath_:
|
||||
sprintf(s,"Breath\t\t%.3f %d %.1f\n",0.0,channel,byte3);
|
||||
if (writeFile) {
|
||||
fprintf(file,"Breath\t\t%.3f %d %.1f\n",dt,channel,byte3);
|
||||
}
|
||||
break;
|
||||
case __SK_FootControl_:
|
||||
sprintf(s,"FootControl\t%.3f %d %.1f\n",0.0,channel,byte3);
|
||||
if (writeFile) {
|
||||
fprintf(file,"FootControl\t%.3f %d %.1f\n",dt,channel,byte3);
|
||||
}
|
||||
break;
|
||||
case __SK_Portamento_:
|
||||
sprintf(s,"Portamento\t%.3f %d %.1f\n",0.0,channel,byte3);
|
||||
if (writeFile) {
|
||||
fprintf(file,"Portamento\t%.3f %d %.1f\n",dt,channel,byte3);
|
||||
}
|
||||
break;
|
||||
case __SK_Balance_:
|
||||
sprintf(s,"Balance\t%.3f %d %.1f\n",0.0,channel,byte3);
|
||||
if (writeFile) {
|
||||
fprintf(file,"Balance\t%.3f %d %.1f\n",dt,channel,byte3);
|
||||
}
|
||||
break;
|
||||
case __SK_Pan_:
|
||||
sprintf(s,"Pan\t\t%.3f %d %.1f\n",0.0,channel,byte3);
|
||||
if (writeFile) {
|
||||
fprintf(file,"Pan\t\t%.3f %d %.1f\n",dt,channel,byte3);
|
||||
}
|
||||
break;
|
||||
case __SK_Sustain_:
|
||||
sprintf(s,"Sustain\t%.3f %d %.1f\n",0.0,channel,byte3);
|
||||
if (writeFile) {
|
||||
fprintf(file,"Sustain\t%.3f %d %.1f\n",dt,channel,byte3);
|
||||
}
|
||||
break;
|
||||
case __SK_Expression_:
|
||||
sprintf(s,"Expression\t%.3f %d %.1f\n",0.0,channel,byte3);
|
||||
if (writeFile) {
|
||||
fprintf(file,"Expression\t%.3f %d %.1f\n",dt,channel,byte3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sprintf(s,"ControlChange\t%.3f %d %d %.1f\n",0.0,channel,j,byte3);
|
||||
if (writeFile) {
|
||||
fprintf(file,"ControlChange\t%.3f %d %d %.1f\n",dt,channel,j,byte3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case __SK_ProgramChange_:
|
||||
j = (int) byte2;
|
||||
sprintf(s,"ProgramChange\t%.3f %d %d\n",0.0,channel,j);
|
||||
if (writeFile) {
|
||||
fprintf(file,"ProgramChange\t%.3f %d %d\n",dt,channel,j);
|
||||
}
|
||||
break;
|
||||
|
||||
case __SK_ChannelPressure_:
|
||||
sprintf(s,"ChannelPressure\t%.3f %d %.1f\n",0.0,channel,byte2);
|
||||
if (writeFile) {
|
||||
fprintf(file,"ChannelPressure\t%.3f %d %.1f\n",dt,channel,byte2);
|
||||
}
|
||||
break;
|
||||
|
||||
case __SK_PitchBend_:
|
||||
sprintf(s,"PitchBend\t%.3f %d %f\n",0.0,channel,byte2);
|
||||
if (writeFile) {
|
||||
fprintf(file,"PitchBend\t%.3f %d %f\n",dt,channel,byte2);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
sprintf(s,"// Unknown\t%.3f %d %f %f\n",0.0,channel,byte2,byte3);
|
||||
if (writeFile) {
|
||||
fprintf(file,"// Unknown\t\t%.3f %d %f %f\n",dt,channel,byte2,byte3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (useSocket) {
|
||||
if ( soket->writeBuffer( s, strlen(s), 0 ) < 0 ) {
|
||||
fprintf(stderr,"Socket connection failed ... aborting.\n");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("%s", s);
|
||||
fflush(stdout);
|
||||
}
|
||||
memset(s, 0, sizeof(s));
|
||||
} else {
|
||||
// Sleep for 10 milliseconds
|
||||
Stk::sleep( 10 );
|
||||
}
|
||||
// Open the port.
|
||||
try {
|
||||
midiin->openPort( port );
|
||||
}
|
||||
catch (RtError &error) {
|
||||
error.printMessage();
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
sprintf(s, "Exiting Md2Skini process ... bye!\n");
|
||||
if (useSocket)
|
||||
soket->writeBuffer( s, strlen(s), 0 );
|
||||
else {
|
||||
printf("%s", s);
|
||||
fflush(stdout);
|
||||
}
|
||||
// Set our callback function. This should be done immediately after
|
||||
// opening the port to avoid having incoming messages written to the
|
||||
// queue instead of sent to the callback function.
|
||||
midiin->setCallback( &midiCallback, file );
|
||||
|
||||
if (writeFile) {
|
||||
printf("Wrote SKINI output to file %s.\n", fileName);
|
||||
fclose(file);
|
||||
}
|
||||
// We'll ignore sysex, timing, and active sensing messages.
|
||||
midiin->ignoreTypes( true, true, true );
|
||||
|
||||
std::cout << "\nReading MIDI input ... press <enter> to quit.\n";
|
||||
char input;
|
||||
std::cin.get(input);
|
||||
|
||||
cleanup:
|
||||
done = true;
|
||||
delete rtmidi;
|
||||
delete soket;
|
||||
delete thread;
|
||||
delete midiin;
|
||||
if ( file != NULL ) fclose( file );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
THREAD_RETURN THREAD_TYPE stdinMonitor(void * ptr)
|
||||
{
|
||||
bool *done = (bool *) ptr;
|
||||
char inputString[128];
|
||||
printf("Type 'Exit<cr>' to quit.\n");
|
||||
while ( !*done ) {
|
||||
fgets(inputString, 128, stdin);
|
||||
if (inputString[3] == 't' && inputString[1] == 'x'
|
||||
&& inputString[2] == 'i' && inputString[0] == 'E') {
|
||||
*done = true;
|
||||
}
|
||||
else {
|
||||
printf(inputString);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
std::cout << "Md2Skini finished ... bye!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user