//=========================================================================== // THEREMIN // EZIO CONTROLLED MIDI // Nicholas Gessler // 19 April 2005 // Revised for XP and simplified 3 December 2003 //=========================================================================== //=========================================================================== // BORLAND CODE //=========================================================================== #include #pragma hdrstop #include "Unit1.h" #include // we need this for MIDI //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- //=========================================================================== // COM1 COMMUNICATIONS MANAGEMENT: GLOBAL VARIABLES //=========================================================================== HANDLE hComm = NULL; COMMTIMEOUTS ctmoNew = {0}, ctmoOld; //=========================================================================== // MIDI INTERFACE MANAGEMENT: GLOBAL VARIABLES //=========================================================================== int midiport = 0; HMIDIOUT device; union { public: unsigned long word; unsigned char data[4]; } message; int instrument = 10; int sensorInput; int note; int delay = 100; int selection; //=========================================================================== // COM1 COMMUNICATIONS MANAGEMENT: ON FORM CREATE //=========================================================================== void __fastcall TForm1::FormCreate(TObject *Sender) { // FOR MIDI COMMUNICATION midiOutOpen(&device, midiport, 0, 0, CALLBACK_NULL); // FOR EZIO COMMUNICATION DCB dcbCommPort; // OPEN THE COMM PORT. hComm = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); // IF THE PORT CANNOT BE OPENED, BAIL OUT. if(hComm == INVALID_HANDLE_VALUE) Application->Terminate(); // SET THE COMM TIMEOUTS IN OUR EXAMPLE. GetCommTimeouts(hComm,&ctmoOld); ctmoNew.ReadTotalTimeoutConstant = 10; ctmoNew.ReadTotalTimeoutMultiplier = 0; ctmoNew.WriteTotalTimeoutMultiplier = 0; ctmoNew.WriteTotalTimeoutConstant = 0; SetCommTimeouts(hComm, &ctmoNew); // SET BAUD RATE, PARITY, WORD SIZE, AND STOP BITS. // THERE ARE OTHER WAYS OF DOING SETTING THESE BUT THIS IS THE EASIEST. dcbCommPort.DCBlength = sizeof(DCB); GetCommState(hComm, &dcbCommPort); BuildCommDCB("57600,N,8,1", &dcbCommPort); SetCommState(hComm, &dcbCommPort); } //=========================================================================== // COM1 COMMUNICATIONS MANAGEMENT: ON FORM CLOSE //=========================================================================== void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) { // WAIT FOR THREAD TO TERMINATE, // PURGE THE INTERNAL COMM BUFFER, // RESTORE THE PREVIOUS TIMEOUT SETTINGS, // AND CLOSE THE COMM PORT. Sleep(250); PurgeComm(hComm, PURGE_RXABORT); SetCommTimeouts(hComm, &ctmoOld); CloseHandle(hComm); } //=========================================================================== // EZIO VARIABLES //=========================================================================== DWORD dwBytesRead; // Required for ReadFile() int InBuff[100]; // Data for ReadFile() char InASCII[100]; // Data for ReadFile() int data; // Data for ReadFile() DWORD dwWritten = 0; // Required for WriteFile() char buffer, portBuffer, hiloBuffer; // Data for WriteFile() bool out1, out2, out3, out4, out5; // Data for WriteFile() bool out6, out7, out8, out9, out10; // Data for WriteFile() bool monitorDigitalInputs = false; bool monitorAnalogInputs = false; bool scopeSelectedPort = false; int port; //=========================================================================== // READ ONE ANALOG INPUT //=========================================================================== int readAnalogInput (int port) { portBuffer = port; WriteFile(hComm, "A", 1, &dwWritten, NULL); WriteFile(hComm, &portBuffer, 1, &dwWritten, NULL); ReadFile(hComm, InBuff, 50, &dwBytesRead, NULL); data = *InBuff; return data; } //=========================================================================== // SCOPE AND PLAY //=========================================================================== void scopeAnalogInput (void) { while (scopeSelectedPort) { Form1->Refresh(); Form1->PaintBoxScope->Canvas->Rectangle(0,0, 552, 258); Form1->PaintBoxScope->Canvas->MoveTo(0, 256); for (int i = 0; i < 551; i++) { // Draw the scope trace sensorInput = readAnalogInput(0); note = sensorInput / 3.043 + 34; Form1->PaintBoxScope->Canvas-> LineTo(i, 256 - sensorInput); Form1->EditData->Text = sensorInput; Form1->EditNote->Text = note; message.data[0] = 0xC0; // set instrument message.data[1] = instrument; midiOutShortMsg(device, message.word); if (sensorInput > 3) { // Play the MIDI note message.data[0] = 0x90; // note on message.data[1] = note; // note # message.data[2] = 100; // once set, no need to repeat message.data[3] = 0; // once set, no need to repeat midiOutShortMsg(device, message.word); // this works } Sleep(delay); message.data[0] = 0x80; // note off message.data[1] = note; // note # message.data[2] = 100; // once set, no need to repeat message.data[3] = 0; // once set, no need to repeat midiOutShortMsg(device, message.word); // this works Application->ProcessMessages(); if (!scopeSelectedPort) goto quit; } } quit: Form1->PaintBoxScope->Refresh(); Form1->PaintBoxScope->Canvas->Rectangle(0,0, 552, 258); } //=========================================================================== // EVENT HANDLERS //=========================================================================== //-------------------------------------------------- READ DIGITAL INPUTS ONCE MONITOR DIGITAL INPUTS ON MONITOR DIGITAL INPUTS OFF SET DIGITAL OUTPUT 0 BY PRESSING A SHAPE SET DIGITAL OUTPUT 1 BY PRESSING A SHAPE SET DIGITAL OUTPUT 2 BY PRESSING A SHAPE SET DIGITAL OUTPUT 3 BY PRESSING A SHAPE SET DIGITAL OUTPUT 4 BY PRESSING A SHAPE SET DIGITAL OUTPUT 5 BY PRESSING A SHAPE SET DIGITAL OUTPUT 6 BY PRESSING A SHAPE SET DIGITAL OUTPUT 7 BY PRESSING A SHAPE SET DIGITAL OUTPUT 8 BY PRESSING A SHAPE SET DIGITAL OUTPUT 9 BY PRESSING A SHAPE TURN ALL DIGITAL OUTPUTS ON TURN ALL DIGITAL OUTPUTS OFF READ ALL ANALOG INPUTS ONCE MONITOR ANALOG INPUTS ON MONITOR ANALOG INPUTS OFF SCOPE ANALOG INPUT ON void __fastcall TForm1::ScopeClick(TObject *Sender) { scopeSelectedPort = true; scopeAnalogInput(); } //---------------------------------------------------- SCOPE ANALOG INPUT OFF void __fastcall TForm1::ButtonStopScopeClick(TObject *Sender) { scopeSelectedPort = false; } //------------------------------------------------------------- SCOPE REFRESH void __fastcall TForm1::ButtonClearClick(TObject *Sender) { Form1->PaintBoxScope->Refresh(); Form1->PaintBoxScope->Canvas->Rectangle(0,0, 552, 258); } //------------------------------------------------------------- REPAINT SCOPE void __fastcall TForm1::PaintBoxScopePaint(TObject *Sender) { Form1->PaintBoxScope->Canvas->Rectangle(0,0, 552, 258); } //--------------------------------------------------------------------------- void __fastcall TForm1::TrackBarDelayChange(TObject *Sender) { delay = TrackBarDelay->Position; } //--------------------------------------------------------------------------- void __fastcall TForm1::TrackBarInstrumentChange(TObject *Sender) { instrument = TrackBarInstrument->Position; if (instrument > 95) instrument += 24; Form1->EditInstrument->Text = instrument; } //=========================================================================== // THAT'S ALL FOLKS //=========================================================================== void __fastcall TForm1::EditInstrumentChange(TObject *Sender) { if (EditInstrument->Text != "") { selection = StrToInt(EditInstrument->Text); if (selection < 96) { instrument = selection; Form1->TrackBarInstrument->Position = instrument; } if (selection > 119 && selection < 128) { instrument = selection; Form1->TrackBarInstrument->Position = selection - 24; } } } //---------------------------------------------------------------------------