/*
 *    Rosegarden MIDI Sequencer
 *
 *    File:           Menu.c
 *
 *    Description:    Code to set up the pulldown menus using the Y library.
 *
 *    Author:         AJG
 *
 *    History:
 *
 *    Update  Date            Programmer      Comments
 *    ======  ====            ==========      ========
 *
 *    001     16/02/94        AJG             File Created.
 *    002     29/11/95        AJG             Added the "Tools | External
 *                                            Player" menu option. This allows
 *                                            the user to pass MIDI files out
 *                                            to external programs to be
 *                                            played, such as the 'synthia'
 *                                            direct synthesis demo program
 *                                            available for SGIs. The function
 *                                            writes a MIDI file out to the
 *                                            temporary directory, and passes
 *                                            this out the specified program
 *                                            on its command line.  If you need
 *                                            to pipe output then you'll have
 *                                            to use a shell alias or a script.
 *                                            The temporary file is removed
 *                                            when the SIGCHLD signal is
 *                                            received after the player exits
 *                                            (see Midi_ExternalPlayerExitCB).
 *
 *    003     30/05/96        rwb             Altering MIDI Playback calls.
 *    004     24/06/96        rwb             Fixed double file-close bug.
 */

#include <MidiXInclude.h>
#include <MidiFile.h>
#include <MidiTrack.h>
#include <ILClient.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "Types.h"
#include "Menu.h"
#include "Main.h"
#include "Globals.h"
#include "MainWindow.h"
#include "TrackList.h"
#include "EventListWindow.h"
#include "PianoRollMenu.h"
#include "PianoRoll.h"
#include "Message.h"
#include "Undo.h"
#include "Clipboard.h"
#include "Consts.h"
#include "Sequence.h"
#include "MidiSetup.h"
#include "Record.h"
#include "Dispatch.h"
#include "EventListMenu.h"
#include "Csound.h"

#include <string.h>
#include <unistd.h>

#include <Yawn.h>
#include <Debug.h>

#include <toolbar/beam.xbm>
#include <toolbar/undo.xbm>
#include <toolbar/ninja_cross.xbm>
#include <toolbar/copy.xbm>
#include <toolbar/cut.xbm>
#include <toolbar/paste.xbm>
#include <toolbar/open.xbm>
#include <toolbar/save.xbm>
#include <toolbar/quantize.xbm>
#include <toolbar/event_list.xbm>
#include <toolbar/piano_roll.xbm>
#include <toolbar/sequence.xbm>
#include <toolbar/stop.xbm>
#include <toolbar/record.xbm>


MIDIHeaderChunk MIDIHeaderBuffer;
MIDIFileHandle	MIDIFile;
char	       *MIDIFileName;
EventList      *MIDITracks;
char	       *MIDItempFileName = NULL;
char           *MIDIexternalPlayFileName = NULL;
pid_t           MIDIexternalPlayerPID;


void Unimplemented(Widget w, XtPointer a, XtPointer b)
{
BEGIN("Unimplemented");

  (void)YQuery(topLevel, "Sorry, that function is not yet implemented.",
		1, 0, 0, "Continue", NULL);
END;
}

void Midi_ExternalPlayerExitCB()
{
    int status;
    
    waitpid(MIDIexternalPlayerPID, &status, 0);
    
    unlink(MIDIexternalPlayFileName);
    free(MIDIexternalPlayFileName);
    MIDIexternalPlayFileName = NULL;
    MIDIexternalPlayerPID = 0;
    signal(SIGCHLD, SIG_DFL);
}

Widget Midi_GetWidgetFromPointerPos(void)
{
Window       Root;
Window       Child;
int          RootX, RootY, WinX, WinY;
unsigned int mask;
Widget	     w;

BEGIN("Midi_GetWidgetFromPointerPos");

	XQueryPointer(display, RootWindowOfScreen(XtScreen(topLevel)), &Root, &Child,
		      &RootX, &RootY, &WinX, &WinY, &mask);

	w = XtWindowToWidget(display, Child);


RETURN_WIDGET(w);
}

Widget Midi_GetShellWidget(Widget w)
{
BEGIN("Midi_GetShellWidget");

	if (w == RoseLabel) w = Midi_GetWidgetFromPointerPos();

	while(XtParent(w)) w = XtParent(w);

RETURN_WIDGET(w);
}
	

void Midi_RecordCB(Widget w, XtPointer a, XtPointer b)
{
BEGIN("Midi_RecordCB");

	w = Midi_GetShellWidget(w);

	if (w != topLevel) END;

	Midi_SeqReadTrack();

END;
}


void Midi_FileInfoCB(Widget w, XtPointer a, XtPointer b)
{
char   *FileFormat = 0;
char 	InfoBuffer[1024];
int	i, NumEvents;

BEGIN("Midi_FileInfoCB");

	w = Midi_GetShellWidget(w);

	if (w != topLevel) END;

	switch(MIDIHeaderBuffer.Format)
	{
	case MIDI_SINGLE_TRACK_FILE:

		FileFormat = "1: Single Track File.";
		break;

	case MIDI_SIMULTANEOUS_TRACK_FILE:

		FileFormat = "2: Simultaneous Tracks.";
		break;

	case MIDI_SEQUENTIAL_TRACK_FILE:

		FileFormat = "3: Sequential Tracks.";
		break;

        case MIDI_NO_FILE_LOADED:

		YQuery(topLevel, "There is no file loaded.", 1, 0, 0, "OK",
		       "Sequencer File - Info");
		END;
	}

	NumEvents = 0;

	for (i = 0; i < MIDIHeaderBuffer.NumTracks; ++i)
	{
		NumEvents += Length(MIDITracks[i]);
	}

	sprintf(InfoBuffer, 
		"%s\n\n	File Format %s\n\nNumber Of Tracks: %d\n\nTimebase: %d\n\nTotal No. of Events: %d\n",
		MIDIFileName, FileFormat, MIDIHeaderBuffer.NumTracks, 
		MIDIHeaderBuffer.Timing.Division, NumEvents);

	YQuery(topLevel, InfoBuffer, 1, 0, 0, "OK", "Sequencer File - Info");

END;
} 



void Midi_ShowClipboardCB(Widget w, XtPointer a, XtPointer b)
{
BEGIN("Midi_ShowClipboardCB");

	Midi_ClipboardShowContents();

END;
}




void Midi_NotateAckCB(IL_ReturnCode Rtn)
{
BEGIN("Midi_NotateAckCB");

	if (MIDItempFileName)
	{
	  unlink(MIDItempFileName);
	  XtFree(MIDItempFileName);
	}

	MIDItempFileName = NULL;

	switch(Rtn)
	{
	case IL_NO_SUCH_SERVICE:

		YQuery(topLevel, "Notation service unavailable.", 1, 0, 0, "Continue", NULL);
		break;

	case IL_SERVICE_BUSY:

		YQuery(topLevel, "Notation service is currently busy.\nPlease try again later.", 
		       1, 0, 0, "Continue", NULL);
		break;

	case IL_SERVICE_FAILED:

		YQuery(topLevel, "Notation editor was unable to parse MIDI file.",
		       1, 0, 0, "Continue", NULL);
		break;

	case IL_SERVICE_OK:
	default:

		break;
	}
	
	Midi_SetBusy(False);
END;
}

	
void Midi_NotateCB(Widget w, XtPointer a, XtPointer b)
{
BEGIN("Midi_NotateCB");

	w = Midi_GetShellWidget(w);

	if (w != topLevel) END;

	if (MIDItempFileName) 
	{
		YQuery(topLevel, "Notation Editor has yet to\nacknowledge previous request.",
		       1, 0, 0, "Continue", NULL);
		END;
	}

	if (!(MIDItempFileName = XtNewString(tmpnam(NULL))))
	{
		YQuery(topLevel, "Sorry, I couldn't get a temporary file name.",
		       1, 0, 0, "Continue", NULL);
		END;
	}
	
	Midi_SaveFile(MIDItempFileName);

	IL_RequestService(ILS_EDIT_SERVICE, Midi_NotateAckCB, MIDItempFileName, strlen(MIDItempFileName) + 1);

	Midi_SetBusy(True);
END;
}


Boolean Midi_CloseFile(void)
{
  int i;
  int resp;
  char MsgBuffer[256];
  char *SaveFileName;

  BEGIN("Midi_CloseFile");
	
  if (MIDIfileModified) {

    if (MIDIneverSaved) {

      resp = YQuery(topLevel, "Save changes to current MIDI file?",
		    3, 0, 2, "Yes", "No", "Cancel", NULL);

      if (resp == 2) RETURN_BOOL(False);
      else if (resp == 0) {

	SaveFileName = YFileGetWriteFilename
	  (topLevel, "Sequencer File - Save", ".mid", "MIDI");
	    
	if (SaveFileName) Midi_SaveFile(SaveFileName);
	else if (MIDIinServitude) {
	  IL_AcknowledgeRequest(ILS_SEQUENCE_SERVICE, IL_SERVICE_BUSY);
	  RETURN_BOOL(True);
	}
      }
    } else {

      sprintf(MsgBuffer, "Save changes to MIDI file `%s'?", MIDIFileName);
	  
      resp = YQuery(topLevel, MsgBuffer,
		    3, 0, 2, "Yes", "No", "Cancel", NULL);
	  
      if (resp == 2) RETURN_BOOL(False);
      else if (resp == 0) {
	Midi_SaveFile(MIDIFileName);
      }
    }
  } else {  /* rwb - without this else it all goes horribly awry */

    if (MIDIHeaderBuffer.Format != MIDI_NO_FILE_LOADED) {
      for(i = 0; i < MIDIHeaderBuffer.NumTracks; ++i) {
	Midi_TrackDelete(MIDITracks[i]);
	MIDITracks[i] = NULL;
      }
	
      Midi_FileClose(MIDIFile);	
    }
  }

  Midi_EventListDeleteAllWindows();
  Midi_PianoRollDeleteAllWindows();
  
  MIDIHeaderBuffer.Format    = MIDI_NO_FILE_LOADED;
  MIDIHeaderBuffer.NumTracks = 0;
  
  Midi_TrackListSetup();
  Midi_EnterMenuMode(NoFileLoadedMode);
  
  RETURN_BOOL(True);
}


void Midi_CloseCB(Widget w, XtPointer a, XtPointer b)
{
BEGIN("Midi_CloseCB");


	w = Midi_GetShellWidget(w);

	if (w != topLevel) END;

	Midi_CloseFile();

END;
}

void Midi_LoadFile(char *FileName, Boolean DispMsgs)
{
MIDIHeaderChunk LoadingBuffer;
MIDIFileHandle	NewFile;
short		i;
char		TrackBuff[24];
Cursor		SandsOfTime;

BEGIN("Midi_LoadFile");

	Midi_SetBusy(True);

	if ((NewFile = Midi_FileOpen(FileName, &LoadingBuffer, MIDI_READ)) == NULL)
	{
		Midi_SetBusy(False);
		END;
	}

	MIDIHeaderBuffer = LoadingBuffer;

	MIDIFileName = FileName;

	MIDIFile = NewFile;

	MIDITracks = (EventList *)XtMalloc(MIDIHeaderBuffer.NumTracks * sizeof(EventList));

	for(i = 0; i < MIDIHeaderBuffer.NumTracks; ++i)
	{
		Midi_FileSkipToNextChunk(MIDIFile, MIDI_TRACK_HEADER);

		if (DispMsgs)
		{
			sprintf(TrackBuff, "Reading Track %d of %d", i, MIDIHeaderBuffer.NumTracks - 1);
			Midi_DisplayPermanentMessage(TrackBuff);

			while(XtAppPending(appContext))
			{
				XtAppProcessEvent(appContext, XtIMAll);
			}
		}

		SandsOfTime = HourglassAnimCur[(int)((float)i/MIDIHeaderBuffer.NumTracks * HOUR_FRAMES)];

		XDefineCursor(display, XtWindow(TrackListBox), SandsOfTime);

		MIDITracks[i] = Midi_FileReadTrack(MIDIFile);
		Midi_TrackAggregateDeltas(MIDITracks[i]);
		Midi_TrackConvertToOnePointRepresentation(MIDITracks[i]);
	}

	Midi_TrackListSetup();
	Midi_LeaveMenuMode(NoFileLoadedMode);

	if (DispMsgs)
	{
		Midi_DisplayPermanentMessage(" ");
	}

	Midi_SetBusy(False);
	Midi_SetFileModified(False);
END;
}

void Midi_LoadCB(Widget w, XtPointer a, XtPointer b)
{
String 		FileName;

BEGIN("Midi_LoadCB");


	w = Midi_GetShellWidget(w);

	if (w != topLevel) END;

	FileName = YFileGetReadFilename(topLevel, "Sequencer File - Open",".mid","MIDI");

	if (!FileName) END;

	if (MIDIHeaderBuffer.Format != MIDI_NO_FILE_LOADED)
	  if (!Midi_CloseFile()) END;

	Midi_LoadFile(FileName, True);
	MIDIneverSaved = False;

	Midi_SetTitleBar();
END;
}


void Midi_SaveFile(char *SaveFileName)
{
short          i;
MIDIFileHandle SaveFile;
EventList      ExpandedTrack;

BEGIN("Midi_SaveFile");

	Midi_SetBusy(True);

	if ((SaveFile = Midi_FileOpen(SaveFileName, &MIDIHeaderBuffer, MIDI_WRITE)) == NULL)
	{
		Midi_SetBusy(False);
		YQuery(topLevel, "Unable to open output file.", 1, 0, 0, "Continue", NULL);
		END;
	}

	for(i = 0; i < MIDIHeaderBuffer.NumTracks; ++i)
	{
		ExpandedTrack = Midi_TrackConvertToTwoPointRepresentation(MIDITracks[i]);
		Midi_FileWriteTrack(SaveFile, ExpandedTrack);
		Midi_TrackDelete(ExpandedTrack);
	}

	Midi_FileClose(SaveFile);
	Midi_SetBusy(False);

END;
}

void Midi_SaveAsCB(Widget w, XtPointer a, XtPointer b)
{
String SaveFileName;

BEGIN("Midi_SaveAsCB");


	w = Midi_GetShellWidget(w);

	if (w != topLevel) END;

	SaveFileName = YFileGetWriteFilename(topLevel, "Sequencer File - Save",".mid","MIDI");

	if (!SaveFileName) END;
	Midi_SaveFile(SaveFileName);
	XtFree(MIDIFileName);
	MIDIFileName = SaveFileName;
	MIDIneverSaved = False;
	Midi_SetTitleBar();
END;
}

void Midi_SaveCB(Widget w, XtPointer a, XtPointer b)
{
BEGIN("Midi_SaveCB");

	
	w = Midi_GetShellWidget(w);

	if (w != topLevel) END;

	if (MIDIFileName)
	{
		Midi_SaveFile(MIDIFileName);
		MIDIneverSaved = False;
	}
	else Midi_SaveAsCB(w, a, b);

END;
}

void Midi_SetTimebaseCB(Widget w, XtPointer a, XtPointer b)
{
char 	OldTimebase[12];
char   *NewTimebaseStr;
short	NewTimebase;

BEGIN("Midi_SetTimebaseCB");


	w = Midi_GetShellWidget(w);

	if (w != topLevel) END;

	sprintf(OldTimebase, "%hd", MIDIHeaderBuffer.Timing.Division);

	NewTimebaseStr = YGetUserInput(topLevel, "Set Timebase for file to:", 
				       OldTimebase, YOrientHorizontal, "Sequencer File - Set Timebase");

	if (NewTimebaseStr == NULL) END;

	NewTimebase = (short)atoi(NewTimebaseStr);

	MIDIHeaderBuffer.Timing.Division = NewTimebase;

END;
}

void Midi_PlayCB(Widget w, XtPointer a, XtPointer b)
{
  BEGIN("Midi_PlayCB");

  Midi_LeaveMenuMode(PlaybackMode);
  Midi_EnterMenuMode(NotPlayingMode);

  w = Midi_GetShellWidget(w);

  if (w != topLevel) END;

  /* Midi_SeqPlayFile() should return 0 for "success, and it's playing
     now" (ie. in multithreaded code) or 1 for "failure" or "too late,
     I've already done it" (in single-threaded code). */

  if (Midi_SeqPlayFile()) END;
  else {
    XtAppContext appContext;

    XFlush(display);
    appContext = XtWidgetToApplicationContext(topLevel);
    while(XtAppPending(appContext)) {
      XtAppProcessEvent(appContext, XtIMAll);
    }

    Midi_EnterMenuMode(PlaybackMode);
    Midi_LeaveMenuMode(NotPlayingMode);
  }

  END;
}

void Midi_StopCB(Widget w, XtPointer a, XtPointer b)
{
  BEGIN("Midi_StopCB");

  Midi_DeviceCloseCB(w, a, b);
  
  Midi_LeaveMenuMode(PlaybackMode);
  Midi_EnterMenuMode(NotPlayingMode);
}

void Midi_MenuExitCB(Widget w, XtPointer a, XtPointer b)
{
  BEGIN("Midi_MenuExitCB");

  Midi_StopCB(w, a, b);
  Midi_QuitCB(w, a, b);

  END;
}

void Midi_ExternalPlayCB(Widget w, XtPointer a, XtPointer b)
{
    char 	player[128];
    char   *playerRtn;
    char   *argList[16];
    int     count;
    
    BEGIN("Midi_ExternalPlayCB");
    
    strcpy(player, appData.externalPlayer);

    playerRtn = YGetUserInput(topLevel, "External Player command string:",
                              player, YOrientHorizontal,
			      "Sequencer Tools - External MIDI Player");

    if (!playerRtn) END;

    /***************************/
    /* Create a temporary file */
    /***************************/
    
	if (MIDIexternalPlayFileName) 
	{
		YQuery(topLevel, "External player currently running.",
		       1, 0, 0, "Continue", NULL);
		END;
	}

	if (!(MIDIexternalPlayFileName = XtNewString(tmpnam(NULL))))
	{
		YQuery(topLevel, "Sorry, I couldn't get a temporary file name.",
		       1, 0, 0, "Continue", NULL);
		END;
	}
    
	Midi_SaveFile(MIDIexternalPlayFileName);

    
    argList[0] = strtok(playerRtn, " \t\n");

    count = 1;
    
    while((argList[count] = strtok(NULL, " \t\n")))
    {
        ++count;
    }
    
    
    argList[count] = MIDIexternalPlayFileName;
    argList[count + 1] = NULL;

    MIDIexternalPlayerPID = fork();

    if (MIDIexternalPlayerPID == 0)
    {
        execvp(playerRtn, argList);
    }
    
    signal(SIGCHLD, Midi_ExternalPlayerExitCB);

    END;
}

void Midi_UndoCB(Widget w, XtPointer a, XtPointer b)
{
BEGIN("Midi_UndoCB");

	Midi_UndoLastOperation();

END;
}



YMenuElement FileMenu[] =
{
  { "Record",
#ifdef SYSTEM_SILENT
    EveryMode,
#else
    NullMode | PlaybackMode,
#endif
    Midi_RecordCB, record_bits, NULL, },
  { "Open . . .",    PlaybackMode, Midi_LoadCB,   open_bits,   NULL, },
  YMenuDivider,
  { "Close",         NoFileLoadedMode | PlaybackMode, Midi_CloseCB, NULL, },
  { "Save",          NoFileLoadedMode | PlaybackMode, Midi_SaveCB,save_bits, NULL, },
  { "Save As . . .", NoFileLoadedMode | PlaybackMode, Midi_SaveAsCB,	NULL, },
  YMenuDivider,
  { "Play",
#ifdef SYSTEM_SILENT
    EveryMode,
#else
    NoFileLoadedMode | PlaybackMode,
#endif
    Midi_PlayCB, sequence_bits, NULL, },
#ifdef SYSTEM_LINUX
  { "Stop", NotPlayingMode, Midi_StopCB,  stop_bits, NULL, },
#endif
#ifdef SYSTEM_SGI
  { "Stop", NotPlayingMode, Midi_StopCB,  stop_bits, NULL, },
#endif
  { "File Info",     NoFileLoadedMode | PlaybackMode, Midi_FileInfoCB,  NULL, },
  { "Set Timebase . . .", NoFileLoadedMode | PlaybackMode,	Midi_SetTimebaseCB,	NULL, },
  YMenuDivider,
  { "Exit",          NullMode,     Midi_MenuExitCB,	  NULL },
};

YMenuId	FileMenuId;

YMenuElement	EditMenu[] =
{
  { "Undo",	NoFileLoadedMode | PlaybackMode | NothingDoneMode,	Midi_UndoCB,		undo_bits, NULL, },
  { "Delete",	NoFileLoadedMode | PlaybackMode | NothingSelectedMode,	Midi_DispatchDeleteCB,	ninja_cross_bits, NULL, },
  YMenuDivider,
  { "Cut",	NoFileLoadedMode | PlaybackMode | NothingSelectedMode,	Midi_DispatchCutCB,	cut_bits, NULL, },
  { "Copy",	NoFileLoadedMode | PlaybackMode | NothingSelectedMode,	Midi_DispatchCopyCB,	copy_bits, NULL, },
  { "Paste",	NoFileLoadedMode | PlaybackMode | NothingCutMode,	Midi_DispatchPasteCB,	paste_bits, NULL, },
  { "Show Clipboard",	PlaybackMode,				Midi_ShowClipboardCB,	NULL },
};
  
YMenuId EditMenuId;
  
  
  
YMenuElement	TrackMenu[] =
{
  { "Show Event List",     NoFileLoadedMode | PlaybackMode | NothingSelectedMode, Midi_TrackEventListCB,	  event_list_bits, NULL, },
  { "Show Piano Roll",     NoFileLoadedMode | PlaybackMode | NothingSelectedMode, Midi_TrackPianoRollCB,	  piano_roll_bits, NULL, },
  YMenuDivider,
  { "Rename . . .",	         NoFileLoadedMode | PlaybackMode | NothingSelectedMode, Midi_TrackRenameCB,	  NULL, },
  { "Track Info",	 NoFileLoadedMode | PlaybackMode | NothingSelectedMode, Midi_TrackInfoCB,		  NULL, },
  YMenuDivider,
  { "Clone",	         NoFileLoadedMode | PlaybackMode | NothingSelectedMode, Midi_TrackCloneCB,		  NULL, },
  { "Merge . . .",	         NoFileLoadedMode | PlaybackMode | NothingSelectedMode, Midi_TrackMergeCB,		  NULL, },
  YMenuDivider,
  { "Filter By Channel . . .", NoFileLoadedMode | PlaybackMode | NothingSelectedMode, Midi_TrackFilterByChannelCB, NULL, },
  { "Filter By Event . . .",   NoFileLoadedMode | PlaybackMode | NothingSelectedMode, Midi_TrackFilterByEventCB,   NULL, },
  { "Filter By Pitch . . .",   NoFileLoadedMode | PlaybackMode | NothingSelectedMode, Midi_TrackFilterByPitchCB,	  NULL, },
  YMenuDivider,
  { "Split By Channel . . .",  NoFileLoadedMode | PlaybackMode | NothingSelectedMode, Unimplemented,		  NULL, },
  { "Split By Pitch . . .",    NoFileLoadedMode | PlaybackMode | NothingSelectedMode, Unimplemented,		  NULL, },
  { "Change Channel . . .",    NoFileLoadedMode | PlaybackMode | NothingSelectedMode, Midi_TrackChangeChannelCB,	  NULL, },
  YMenuDivider,
  { "Quantize . . .",	         NoFileLoadedMode | PlaybackMode,			     Midi_TrackQuantizeCB,	  quantize_bits, NULL, },
  { "Transpose . . .",	 NoFileLoadedMode | PlaybackMode,			     Midi_TrackTransposeCB,	  NULL, },
};

YMenuId TrackMenuId;



YMenuElement	MidiMenu[] =
{
  { "MIDI Setup . . .",
#ifdef SYSTEM_SILENT
    EveryMode,
#else
    PlaybackMode,
#endif
    Midi_SetupCB, NULL, },
  { "Set Initial Patches",
#ifdef SYSTEM_LINUX
    PlaybackMode,
#else
    EveryMode,
#endif
    Midi_InitialPatchesDlg, NULL, },
  YMenuDivider,
  { "Reset",
#ifndef SYSTEM_SILENT
    PlaybackMode,
#else
    EveryMode,
#endif
    Unimplemented, NULL, },
  { "System Reset",
#ifndef SYSTEM_SILENT
    PlaybackMode,
#else
    EveryMode,
#endif
    Unimplemented, NULL, },
  YMenuDivider,
  { "System Exclusive",	
#ifndef SYSTEM_SILENT
    PlaybackMode,
#else
    EveryMode,
#endif
    Unimplemented, NULL },
};

YMenuId MidiMenuId;



YMenuElement	ToolsMenu[] =
{
  { "Notate!",		NoFileLoadedMode | PlaybackMode,	Midi_NotateCB,	beam_bits, NULL, },
  { "Export CSound . . .",	NoFileLoadedMode | PlaybackMode, 	Midi_2CsoundCB,	NULL, },
  { "External MIDI Player . . .",  NoFileLoadedMode | PlaybackMode,  Midi_ExternalPlayCB, NULL, },
  /*YMenuDivider,
  { "Preferences . . .",	PlaybackMode,		Unimplemented,	NULL },*/
};

YMenuId ToolsMenuId;



void Midi_InstallFileMenu(Widget File)
{
BEGIN("Midi_InstallFileMenu");

	FileMenuId = YCreateMenu(File, "File Menu", XtNumber(FileMenu), FileMenu);

END;
}


void Midi_InstallEditMenu(Widget Edit)
{
BEGIN("Midi_InstallEditMenu");

	EditMenuId = YCreateMenu(Edit, "Edit Menu", XtNumber(EditMenu), EditMenu);

END;
}


	
void Midi_InstallTrackMenu(Widget Track)
{
BEGIN("Midi_InstallTrackMenu");

	TrackMenuId = YCreateMenu(Track, "Track Menu", XtNumber(TrackMenu), TrackMenu);

END;
}


void Midi_InstallMidiMenu(Widget Midi)
{
BEGIN("Midi_InstallMidiMenu");

	MidiMenuId = YCreateMenu(Midi, "Midi Menu", XtNumber(MidiMenu), MidiMenu);

END;
}


void Midi_InstallToolsMenu(Widget Tools)
{
BEGIN("Midi_InstallToolsMenu");

	ToolsMenuId = YCreateMenu(Tools, "Tools Menu", XtNumber(ToolsMenu), ToolsMenu);

END;
}


void Midi_EnterMenuMode(unsigned long MenuMode)
{
BEGIN("Midi_EnterMenuMode");

	YEnterMenuMode(FileMenuId,  MenuMode);
	YEnterMenuMode(EditMenuId,  MenuMode);
	YEnterMenuMode(TrackMenuId, MenuMode);
	YEnterMenuMode(MidiMenuId,  MenuMode);
	YEnterMenuMode(ToolsMenuId, MenuMode);

	Midi_ELAllWindowsEnterMenuMode(MenuMode);
	Midi_PRAllWindowsEnterMenuMode(MenuMode);

	if (MenuMode == PlaybackMode) {
	  YSetValue(TrackListBox, XtNsensitive, False);
	} else if (MenuMode == NotPlayingMode) {
	  YSetValue(TrackListBox, XtNsensitive, True);
	}
END;
}


void Midi_LeaveMenuMode(unsigned long MenuMode)
{
BEGIN("Midi_LeaveMenuMode");

	YLeaveMenuMode(FileMenuId,  MenuMode);
	YLeaveMenuMode(EditMenuId,  MenuMode);
	YLeaveMenuMode(TrackMenuId, MenuMode);
	YLeaveMenuMode(MidiMenuId,  MenuMode);
	YLeaveMenuMode(ToolsMenuId, MenuMode);

	Midi_ELAllWindowsLeaveMenuMode(MenuMode);
	Midi_PRAllWindowsLeaveMenuMode(MenuMode);
END;
}
