1/*
2Author:	Jerome LEVEQUE
3Email:	jerl1@caramail.com
4*/
5#include "MidiPlayerWindow.h"
6#include "MidiDelay.h"
7#include "Activity.h"
8
9#include <Application.h>
10#include <Roster.h>
11#include <Resources.h>
12#include <Alert.h>
13#include <PopUpMenu.h>
14#include <MenuItem.h>
15#include <StringView.h>
16#include <String.h>
17#include <File.h>
18#include <MidiStore.h>
19#include <MidiPort.h>
20#include <MidiSynth.h>
21#include <MidiSynthFile.h>
22
23//----------------------------------------------------------
24
25class MidiPlayerApp : public BApplication
26{
27public:
28	MidiPlayerApp(void)
29		: BApplication("application/x-vnd.MidiPlayer")
30	{
31	app_info info;
32	BFile file;
33	BResources resource;
34	size_t len;
35		GetAppInfo(&info);
36		if (file.SetTo(&(info.ref), B_READ_ONLY) != B_OK) return;
37		resource.SetTo(&file);
38		BPoint *origin((BPoint*)resource.LoadResource('BPNT', "origin", &len));
39		if (origin == NULL)
40			fWindows = new MidiPlayerWindow(BPoint(100.0, 100.0));
41		else
42			fWindows = new MidiPlayerWindow(*origin);
43	}
44
45//--------------
46
47	void ReadyToRun(void)
48	{
49		fWindows->Show();
50	}
51
52//--------------
53
54	void SetOrigin(BPoint origin)
55	{
56	app_info info;
57	BFile file;
58	BResources resource;
59	int32 temp;
60		GetAppInfo(&info);
61		if (file.SetTo(&(info.ref), B_READ_WRITE) != B_OK) return;
62		resource.SetTo(&file);
63		temp = resource.RemoveResource('BPNT', 1);
64		temp = resource.AddResource('BPNT', 1, &origin, sizeof(origin), "origin");
65	}
66
67//--------------
68
69	virtual void RefsReceived(BMessage *message)
70	{
71		message->what = B_SIMPLE_DATA;
72		fWindows->PostMessage(message);
73	}
74
75//--------------
76//--------------
77//--------------
78//--------------
79//--------------
80
81private:
82	MidiPlayerWindow *fWindows;
83
84//--------------
85
86};
87
88//----------------------------------------------------------
89//----------------------------------------------------------
90//----------------------------------------------------------
91//----------------------------------------------------------
92//----------------------------------------------------------
93//----------------------------------------------------------
94//----------------------------------------------------------
95//----------------------------------------------------------
96
97MidiPlayerWindow::MidiPlayerWindow(BPoint start)
98				:	BWindow(BRect(start, start + BPoint(660, 360)), "Midi Player",
99							B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS | B_NOT_RESIZABLE),
100					fMidiInput(NULL),
101					fMidiOutput(NULL),
102					fMidiDisplay(NULL),
103					fInputType(0),
104					fOutputType(0),
105					fDisplayType(0),
106					fInputFilePanel(NULL),
107					fOutputFilePanel(NULL),
108					fInputCurrentEvent(0),
109					fOutputCurrentEvent(0)
110{
111	AddChild(fStandartView = new MidiPlayerView());
112	fMidiDelay = new MidiDelay();
113}
114
115//----------------------------------------------------------
116
117MidiPlayerWindow::~MidiPlayerWindow(void)
118{
119	Disconnect();
120	delete fMidiInput;
121	delete fMidiOutput;
122}
123
124//----------------------------------------------------------
125
126bool MidiPlayerWindow::QuitRequested(void)
127{
128	be_app->PostMessage(B_QUIT_REQUESTED);
129	return true;
130}
131
132//----------------------------------------------------------
133
134void MidiPlayerWindow::FrameMoved(BPoint origin)
135{
136	((MidiPlayerApp*)be_app)->SetOrigin(origin);
137}
138
139//----------------------------------------------------------
140
141void MidiPlayerWindow::MessageReceived(BMessage *msg)
142{
143uint32 temp = 0;
144BPopUpMenu *MidiPortMenu = NULL;
145BMenuItem *item = NULL;
146BMessage message;
147entry_ref ref;
148	switch (msg->what)
149	{
150//--------------
151//For The Input
152//--------------
153//--------------
154		case INPUT_CHANGE_TO_FILE :
155				if (fInputType == FILE)
156					break;
157				fInputType = FILE;
158				Disconnect();
159				delete fMidiInput;
160				fMidiInput = new BMidiStore();
161				if (!fMidiInput)
162				{
163					(new BAlert(NULL, "Can't initialise a BMidiStore object", "OK"))->Go();
164					break;
165				}
166				Connect();
167				PostMessage(msg, fStandartView);
168				break;
169//--------------
170		case INPUT_CHANGE_TO_MIDIPORT :
171				if (fInputType == MIDIPORT)
172					break;
173				fInputType = MIDIPORT;
174				Disconnect();
175				delete fMidiInput;
176				fMidiInput = new BMidiPort();
177				if (!fMidiInput)
178				{
179					(new BAlert(NULL, "Can't initialise a BMidiPort object", "OK"))->Go();
180					break;
181				}
182				MidiPortMenu = new BPopUpMenu("Midi Port");
183				for(int i = ((BMidiPort*)fMidiInput)->CountDevices(); i > 0; i--)
184				{
185				char name[B_OS_NAME_LENGTH];
186					((BMidiPort*)fMidiInput)->GetDeviceName(i - 1, name);
187					MidiPortMenu->AddItem(new BMenuItem(name, new BMessage(CHANGE_INPUT_MIDIPORT)));
188				}
189				msg->AddPointer("Menu", MidiPortMenu);
190				Connect();
191				PostMessage(msg, fStandartView);
192				break;
193//--------------
194//For the Output
195//--------------
196//--------------
197		case OUTPUT_CHANGE_TO_FILE :
198				if (fOutputType == FILE)
199					break;
200				fOutputType = FILE;
201				Disconnect();
202				delete fMidiOutput;
203				fMidiOutput = new BMidiStore();
204				if (!fMidiOutput)
205				{
206					(new BAlert(NULL, "Can't initialise a BMidiStore object", "OK"))->Go();
207					break;
208				}
209				Connect();
210				PostMessage(msg, fStandartView);
211				break;
212//--------------
213		case OUTPUT_CHANGE_TO_BEOS_SYNTH :
214				if (fOutputType == BEOS_SYNTH)
215					break;
216				fOutputType = BEOS_SYNTH;
217				Disconnect();
218				delete fMidiOutput;
219				fMidiOutput = new BMidiSynth();
220				if (!fMidiOutput)
221				{
222					(new BAlert(NULL, "Can't initialise a BMidiSynth object", "OK"))->Go();
223					break;
224				}
225				Connect();
226				((BMidiSynth*)fMidiOutput)->EnableInput(true, true);
227				PostMessage(msg, fStandartView);
228				break;
229//--------------
230		case OUTPUT_CHANGE_TO_BEOS_SYNTH_FILE :
231				if (fOutputType == BEOS_SYNTH_FILE)
232					break;
233				fOutputType = BEOS_SYNTH_FILE;
234				Disconnect();
235				delete fMidiOutput;
236				fMidiOutput = new BMidiSynthFile();
237				if (!fMidiOutput)
238				{
239					(new BAlert(NULL, "Can't initialise a BMidiSynth object", "OK"))->Go();
240					break;
241				}
242				Connect();
243				((BMidiSynthFile*)fMidiOutput)->EnableInput(true, true);
244				PostMessage(msg, fStandartView);
245				break;
246//--------------
247		case OUTPUT_CHANGE_TO_MIDIPORT :
248				if (fOutputType == MIDIPORT)
249					break;
250				fOutputType = MIDIPORT;
251				Disconnect();
252				delete fMidiOutput;
253				fMidiOutput = new BMidiPort();
254				if (!fMidiOutput)
255				{
256					(new BAlert(NULL, "Can't initialise a BMidiPort object", "OK"))->Go();
257					break;
258				}
259				MidiPortMenu = new BPopUpMenu("Midi Port");
260				for(int i = ((BMidiPort*)fMidiOutput)->CountDevices(); i > 0; i--)
261				{
262				char name[B_OS_NAME_LENGTH];
263					((BMidiPort*)fMidiOutput)->GetDeviceName(i - 1, name);
264					MidiPortMenu->AddItem(new BMenuItem(name, new BMessage(CHANGE_OUTPUT_MIDIPORT)));
265				}
266				msg->AddPointer("Menu", MidiPortMenu);
267				Connect();
268				PostMessage(msg, fStandartView);
269				break;
270//--------------
271//For the display view
272//--------------
273//--------------
274		case VIEW_CHANGE_TO_NONE :
275				if (fDisplayType == 0)
276					break;
277				fDisplayType = 0;
278				if (fMidiDisplay != NULL)
279					fMidiDelay->Disconnect(fMidiDisplay); //Object will be deleted in MidiPlayerView::RemoveAll
280				PostMessage(msg, fStandartView);
281				break;
282//--------------
283		case VIEW_CHANGE_TO_SCOPE :
284				if (fDisplayType == SCOPE)
285					break;
286				fDisplayType = SCOPE;
287				PostMessage(msg, fStandartView);
288				break;
289//--------------
290		case VIEW_CHANGE_TO_ACTIVITY :
291				if (fDisplayType == ACTIVITY)
292					break;
293				fDisplayType = ACTIVITY;
294				fMidiDisplay = (BMidi*)new Activity(BRect(10, 25, 340, 340));
295				fMidiDelay->Connect(fMidiDisplay);
296				((Activity*)fMidiDisplay)->Start();
297				msg->AddPointer("View", fMidiDisplay);
298				PostMessage(msg, fStandartView);
299				break;
300//--------------
301//--------------
302//Message from Input file
303//--------------
304		case CHANGE_INPUT_FILE :
305				if (fInputFilePanel)
306				{
307				entry_ref File;
308					if (msg->FindRef("refs", &File) != B_OK)
309						break;
310					Disconnect();
311					delete fMidiInput;
312					fMidiInput = new BMidiStore();
313					if (!fMidiInput)
314					{
315						(new BAlert(NULL, "Can't initialise a BMidiPort object", "OK"))->Go();
316						return;
317					}
318					Connect();
319					if (((BMidiStore*)fMidiInput)->Import(&File) == B_OK)
320					{
321					BStringView *aStringView = fStandartView->GetInputStringView();
322						aStringView->SetText(File.name);
323					}
324					delete fInputFilePanel;
325					fInputFilePanel = NULL;
326				}
327				else
328				{
329					BMessenger messenger(this)
330					fInputFilePanel = new BFilePanel(B_OPEN_PANEL, &messenger,
331						NULL, B_FILE_NODE, false, msg);
332					fInputFilePanel->Show();
333				}
334				break;
335//--------------
336		case REWIND_INPUT_FILE :
337				((BMidiStore*)fMidiInput)->Stop();
338				if (fMidiOutput) fMidiOutput->AllNotesOff();
339				fInputCurrentEvent = 0;
340				return;
341//--------------
342		case PLAY_INPUT_FILE :
343				((BMidiStore*)fMidiInput)->SetCurrentEvent(fInputCurrentEvent);
344				((BMidiStore*)fMidiInput)->Start();
345				break;
346//--------------
347		case PAUSE_INPUT_FILE :
348				fInputCurrentEvent = ((BMidiStore*)fMidiInput)->CurrentEvent();
349				((BMidiStore*)fMidiInput)->Stop();
350				if (fMidiOutput) fMidiOutput->AllNotesOff();
351				break;
352//--------------
353//--------------
354//Message from Output file
355//--------------
356		case CHANGE_OUTPUT_FILE :
357				if (fOutputFilePanel)
358				{
359					const char *filename;
360					msg->FindRef("directory", &fOutputFile);
361					msg->FindString("name", &filename);
362					BDirectory path(&fOutputFile);
363					BFile fichier(&path, filename, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
364					if (fichier.InitCheck() == B_OK)
365					{
366					BStringView *aStringView = fStandartView->GetOutputStringView();
367						BEntry entry(&path, filename);
368						entry.GetRef(&fOutputFile);
369						aStringView->SetText(fOutputFile.name);
370					}
371					else
372					{
373						(new BAlert(NULL, "Can't Create File", "OK"))->Go();
374					}
375					delete fOutputFilePanel;
376					fOutputFilePanel = NULL;
377				}
378				else
379				{
380					BMessenger messenger(this)
381					fOutputFilePanel = new BFilePanel(B_SAVE_PANEL, &messenger,
382						NULL, B_FILE_NODE, false, msg);
383					fOutputFilePanel->Show();
384				}
385				break;
386//--------------
387		case REWIND_OUTPUT_FILE :
388				Disconnect();
389				delete fMidiOutput;
390				fMidiOutput = new BMidiPort();
391				if (!fMidiOutput)
392				{
393					(new BAlert(NULL, "Can't initialise a BMidiPort object", "OK"))->Go();
394					return;
395				}
396				Connect();
397				fOutputCurrentEvent = 0;
398				return;
399//--------------
400		case SAVE_OUTPUT_FILE :
401				((BMidiStore*)fMidiOutput)->Export(&fOutputFile, 0);
402				break;
403//--------------
404//--------------
405//Message from the input Midiport
406//--------------
407		case CHANGE_INPUT_MIDIPORT :
408				if (msg->FindPointer("source", (void**)&item) == B_OK)
409				{
410					((BMidiPort*)fMidiInput)->Open(item->Label());
411					((BMidiPort*)fMidiInput)->Start();
412				}
413				break;
414//--------------
415//--------------
416//Message from the output Midiport
417//--------------
418		case CHANGE_OUTPUT_MIDIPORT :
419				if (msg->FindPointer("source", (void**)&item) == B_OK)
420				{
421					((BMidiPort*)fMidiOutput)->Open(item->Label());
422					((BMidiPort*)fMidiOutput)->Start();
423				}
424				break;
425//--------------
426//--------------
427//Message from the BeOS Synth
428//--------------
429		case CHANGE_BEOS_SYNTH_FILE:
430				if (fOutputFilePanel)
431				{
432					msg->FindRef("refs", &fOutputFile);
433					((BMidiSynthFile*)fMidiOutput)->UnloadFile();
434					if (((BMidiSynthFile*)fMidiOutput)->LoadFile(&fOutputFile) == B_OK)
435					{
436					BStringView *aStringView = fStandartView->GetOutputStringView();
437						aStringView->SetText(fOutputFile.name);
438					}
439					delete fOutputFilePanel;
440					fOutputFilePanel = NULL;
441				}
442				else
443				{
444					BMessenger messenger(this)
445					fOutputFilePanel = new BFilePanel(B_OPEN_PANEL, &messenger,
446						NULL, B_FILE_NODE, false, msg);
447					fOutputFilePanel->Show();
448				}
449				break;
450//--------------
451		case REWIND_BEOS_SYNTH_FILE :
452				((BMidiSynthFile*)fMidiOutput)->Stop();
453				fOutputCurrentEvent = 0;
454				return;
455//--------------
456		case PLAY_BEOS_SYNTH_FILE :
457				if (fOutputCurrentEvent == 1)
458					((BMidiSynthFile*)fMidiOutput)->Resume();
459				else
460					((BMidiSynthFile*)fMidiOutput)->Start();
461				fOutputCurrentEvent = 0;
462				break;
463//--------------
464		case PAUSE_BEOS_SYNTH_FILE :
465				fOutputCurrentEvent = 1;
466				((BMidiSynthFile*)fMidiOutput)->Pause();
467				break;
468//--------------
469		case CHANGE_SAMPLE_RATE_SYNTH :
470				msg->FindInt32("index", (int32*)&temp);
471				switch(temp)
472				{
473					case 0 : be_synth->SetSamplingRate(11025); break;
474					case 1 : be_synth->SetSamplingRate(22050); break;
475					case 2 : be_synth->SetSamplingRate(44100); break;
476				}
477				break;
478//--------------
479		case CHANGE_INTERPOLATION_TYPE_SYNTH :
480				msg->FindInt32("index", (int32*)&temp);
481				switch(temp)
482				{
483					case 0 : be_synth->SetInterpolation(B_DROP_SAMPLE); break;
484					case 1 : be_synth->SetInterpolation(B_2_POINT_INTERPOLATION); break;
485					case 2 : be_synth->SetInterpolation(B_LINEAR_INTERPOLATION); break;
486				}
487				break;
488//--------------
489		case CHANGE_REVERB_TYPE_SYNTH :
490				msg->FindInt32("index", (int32*)&temp);
491				switch(temp)
492				{
493					case 0 :
494						be_synth->EnableReverb(false);
495						break;
496					case 1 :
497						be_synth->EnableReverb(true);
498						be_synth->SetReverb(B_REVERB_CLOSET);
499						break;
500					case 2 :
501						be_synth->EnableReverb(true);
502						be_synth->SetReverb(B_REVERB_GARAGE);
503						break;
504					case 3 :
505						be_synth->EnableReverb(true);
506						be_synth->SetReverb(B_REVERB_BALLROOM);
507						break;
508					case 4 :
509						be_synth->EnableReverb(true);
510						be_synth->SetReverb(B_REVERB_CAVERN);
511						break;
512					case 5 :
513						be_synth->EnableReverb(true);
514						be_synth->SetReverb(B_REVERB_DUNGEON);
515						break;
516				}
517				break;
518//--------------
519		case CHANGE_FILE_SAMPLE_SYNTH :
520				if (msg->FindPointer("source", (void**)&item) == B_OK)
521				{
522				BString path = BString(BEOS_SYNTH_DIRECTORY);
523					path += item->Label();
524				BEntry entry = BEntry(path.String());
525					if (entry.InitCheck() == B_OK)
526					{
527					entry_ref ref;
528						be_synth->Unload();
529						entry.GetRef(&ref);
530						be_synth->LoadSynthData(&ref);
531						((BMidiSynth*)fMidiOutput)->EnableInput(true, true);
532						if (!be_synth->IsLoaded())
533						{
534							(new BAlert(NULL, "Instrument File can't be loaded correctly", "OK"))->Go();
535						}
536						((BMidiSynthFile*)fMidiOutput)->LoadFile(&fOutputFile);
537						((BMidiSynthFile*)fMidiOutput)->Start();
538					}
539					else
540					{
541						(new BAlert(NULL, "Can't initialise instrument File", "OK"))->Go();
542					}
543				}
544				break;
545//--------------
546		case CHANGE_VOLUME_SYNTH :
547				msg->FindInt32("be:value", (int32*)&temp);
548				be_synth->SetSynthVolume(temp / 1000.0);
549				break;
550//--------------
551//--------------
552//For the drag and drop function
553//--------------
554		case B_SIMPLE_DATA : //A file had been dropped into application
555				if (msg->FindRef("refs", &ref) == B_OK)
556				{
557					message = BMessage(INPUT_CHANGE_TO_FILE);
558					PostMessage(&message);
559					message = BMessage(*msg);
560					message.what = CHANGE_INPUT_FILE;
561					BMessenger messenger(this)
562					fInputFilePanel = new BFilePanel(B_OPEN_PANEL, &messenger,
563						NULL, B_FILE_NODE, false, msg);;
564					PostMessage(&message);
565					message = BMessage(OUTPUT_CHANGE_TO_BEOS_SYNTH);
566					PostMessage(&message);
567					message = BMessage(PLAY_INPUT_FILE);
568					PostMessage(&message);
569				}
570				break;
571//--------------
572		case B_CANCEL :
573				msg->FindInt32("old_what", (int32*)&temp);
574				if (temp == CHANGE_INPUT_FILE)
575				{
576					delete fInputFilePanel;
577					fInputFilePanel = NULL;
578				}
579				if (temp == CHANGE_OUTPUT_FILE)
580				{
581					delete fOutputFilePanel;
582					fOutputFilePanel = NULL;
583				}
584				break;
585//--------------
586//--------------
587//--------------
588//--------------
589//--------------
590//--------------
591//--------------
592//--------------
593//--------------
594//--------------
595//--------------
596//--------------
597//--------------
598//--------------
599//--------------
600//--------------
601//--------------
602//--------------
603//--------------
604//--------------
605//--------------
606//--------------
607//--------------
608//--------------
609//--------------
610	default : BWindow::MessageReceived(msg);
611	}
612}
613
614
615//----------------------------------------------------------
616
617void MidiPlayerWindow::Disconnect(void)
618{//This function must be rewrited for a better disconnection
619	if (fMidiInput != NULL)
620	{
621		fMidiInput->AllNotesOff(false);
622		fMidiInput->Disconnect(fMidiDelay);
623	}
624	if (fMidiOutput != NULL)
625	{
626		fMidiOutput->AllNotesOff(false);
627		fMidiDelay->Disconnect(fMidiOutput);
628	}
629}
630
631//----------------------------------------------------------
632
633void MidiPlayerWindow::Connect(void)
634{//This function must be rewrited for a better connection
635	if (fMidiInput != NULL)
636		fMidiInput->Connect(fMidiDelay);
637	if (fMidiOutput != NULL)
638		fMidiDelay->Connect(fMidiOutput);
639}
640
641//----------------------------------------------------------
642//----------------------------------------------------------
643//----------------------------------------------------------
644//----------------------------------------------------------
645//----------------------------------------------------------
646//----------------------------------------------------------
647//----------------------------------------------------------
648//----------------------------------------------------------
649//----------------------------------------------------------
650
651int main(int, char**)
652{
653	MidiPlayerApp *App = new MidiPlayerApp();
654	App->Run();
655	delete App;
656	return B_NO_ERROR;
657};
658
659//----------------------------------------------------------
660