home *** CD-ROM | disk | FTP | other *** search
/ Mods Anthology 4 / Music-AmigaModsAnthology-4of4-Psychodk.mcsteam.iso / Tools / BeBox / Ralf_Tracker_0.3_Src / tracker_app.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-10  |  27.1 KB  |  1,138 lines

  1. /**********************************************************
  2.  
  3.     Project: ralf_tracker
  4.     -------- ------------
  5.  
  6.     Version : 0.3a (alpha)
  7.     9 April 96 for BeOS 1.1d7
  8.  
  9.     Sample wrapper around the Marc Espie's "tracker 3.19".
  10.     Please feel free to reuse that code, as either a sample code
  11.     for programing onto the BeBox or to add a more robust
  12.     interface with nice features.
  13.     
  14.     Once I get another version of "tracker" from Marc Espie which
  15.     uses something else that K&R formating, I will suppress the tracker_lib.so.
  16.     This library is here because I can't mix C K&R code and C++ code in the
  17.     same project with CodeWarior.
  18.  
  19.     There is no copyright on this code. You can modify it, destroy it,
  20.     reuse it or simply trash it. If you reuse it, please mention my
  21.     name somewhere. If you did something beautifull, please send me
  22.     a copy. I'd like to see "be-demos" like there was "amiga-demos".
  23.  
  24.     Raphael MOLL,
  25.     moll@linux.utc.fr
  26.  
  27.     Disclaimer : there is no link between this code and my work
  28.     at MIPSYS, France.
  29.  
  30. ***********************************************************/
  31.  
  32. //#include <Be.h>
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <stdarg.h>
  36. #include <string.h>
  37.  
  38. #include <AudioSubscriber.h>
  39.  
  40. //------------------------------------------------------
  41.  
  42. char *strdup(const char *s);
  43.  
  44. extern "C"
  45. {
  46.     void setup_play_track(long freq, int stereo);
  47.     void close_play_track(void);
  48.     void play_track(char *filename);
  49.     extern void (*gBeAudioPlayBuffer)(unsigned char *buffer, long length);
  50.     extern int gBeAudioNextModule;
  51.     extern int gBeAudioQuitModule;
  52.  
  53.     // these functions and flags should not be used any more (obsolete)
  54.     int tracker_main(int _argc, char **_argv);
  55.     extern long gBeAudioBufSize;
  56.     extern void (*gBeAudioExit)(void);
  57.     extern int gBeAudioNextModule;
  58.     extern int gBeAudioQuitModule;
  59. }
  60.  
  61. //------------------------------------------------------
  62.  
  63. #define BOOL unsigned char
  64. #define ULONG unsigned long
  65. #define LONG signed long
  66. #define UBYTE unsigned char
  67. #define USHORT unsigned short int
  68. #define SHORT signed short int
  69. #define DOUBLE double
  70.  
  71. #define K_BACKGROUND_GRAY 220,220,220
  72. //#define K_BACKGROUND_GRAY 144,144,144
  73. #define K_ELECTRO_GRAY    88,88,88
  74. #define K_ELECTRO_GREEN        0,153,0
  75.  
  76.  
  77. #define K_MSG_PLAY    'Play'
  78. #define K_MSG_STOP    'Stop'
  79. #define K_MSG_NEXT    'Next'
  80. #define K_MSG_QUIT    'Quit'
  81. #define K_MSG_LOAD    'Load'
  82. #define K_MSG_SAVE    'Save'
  83. #define K_MSG_RAND    'Rand'
  84. #define K_MSG_ALFA    'Alfa'
  85. #define K_MSG_ABOUT    'Abot'
  86.  
  87. //------------------------------------------------------
  88. // debug stuff
  89.  
  90. FILE *gDevSerial4 = NULL;
  91. void dprintf(char *format, ...);
  92.  
  93. #undef K_ENABLE_LOG
  94. #define OPEN_LOG() gDevSerial4=fopen("/dev/serial4", "wt");
  95. #define CLOSE_LOG() if(gDevSerial4) fclose(gDevSerial4);
  96.  
  97. //------------------------------------------------------
  98.  
  99. //****************
  100. struct SBufferItem
  101. //****************
  102. {
  103.     UBYTE *data;
  104.     long length;
  105. };
  106.  
  107.  
  108. //****************
  109. class CFileItem
  110. //****************
  111. #pragma mark CFileItem
  112. {
  113. public:
  114.     CFileItem(void);
  115.     ~CFileItem(void);
  116.     
  117.     char *mDisplayName;
  118.     char *mFileName;
  119.     BOOL mIsPlaying;
  120.     ULONG mOrder;
  121. };
  122.  
  123.  
  124. //*************************************
  125. class CFileList : public BListView
  126. //*************************************
  127. #pragma mark CFileList
  128. {
  129. public:
  130.     CFileList(BRect frame, char *name,
  131.                         ULONG resizeMode=B_FOLLOW_LEFT|B_FOLLOW_TOP,
  132.                         ULONG flags=B_WILL_DRAW|B_FRAME_EVENTS);
  133.     ~CFileList(void);
  134.     bool MessageDropped(BMessage *msg, BPoint point, BPoint offset);
  135. };
  136.  
  137.  
  138. //****************************
  139. class CBackView : public BView
  140. //****************************
  141. #pragma mark CBackView
  142. {
  143. public:
  144.     CBackView(BRect frame, const char *name,
  145.                                  ULONG resizeMode=B_FOLLOW_LEFT|B_FOLLOW_TOP,
  146.                                  ULONG flags=B_WILL_DRAW)
  147.                         :BView(frame,name,resizeMode,flags) {};
  148.     ~CBackView(void) {};
  149.     void AttachedToWindow(void) {Window()->Lock(); SetViewColor(K_BACKGROUND_GRAY); Window()->Unlock();}
  150. };
  151.  
  152.  
  153. //*********************************
  154. class CElectrogramme : public BView
  155. //*********************************
  156. #pragma mark CElectrogramme
  157. {
  158. public:
  159.     CElectrogramme(BRect frame, const char *name, BOOL rightChannel,
  160.                                  ULONG resizeMode=B_FOLLOW_LEFT|B_FOLLOW_TOP,
  161.                                  ULONG flags=B_WILL_DRAW|B_PULSE_NEEDED|B_FRAME_EVENTS);
  162.     ~CElectrogramme(void);
  163.     void AttachedToWindow(void);
  164.     void Draw(BRect r);
  165.     void Pulse(void);
  166.     void FrameResized(float width, float height);
  167.     
  168.     ULONG mAllocWidth;    // alloc size of the array
  169.     SHORT *mValue;
  170.     BOOL mRightChannel;
  171. };
  172.  
  173.  
  174. //*************************************
  175. class CTrackerWin : public BWindow
  176. //*************************************
  177. #pragma mark CTrackerWin
  178. {
  179. public:
  180.     CTrackerWin(void);
  181.     void MessageReceived(BMessage *msg);
  182.     //bool FilterMessageDropped(BMessage *msg, BPoint point, BView **target);
  183.     bool QuitRequested(void);
  184.  
  185.     void setPlayNames(char *displayName, char *fileName);
  186.     
  187.     CFileList *mFileList;
  188.     BScrollView *mFileScroll;
  189.     BStringView *mDisplayName;
  190.     BStringView *mFileName;
  191.     CElectrogramme *mElectroLeft;
  192.     CElectrogramme *mElectroRight;
  193. };
  194.  
  195.  
  196. //***********************************
  197. class CTrackerLooper : public BLooper
  198. //***********************************
  199. #pragma mark CTrackerLooper
  200. {
  201. public:
  202.     CTrackerLooper(long priority);
  203.     ~CTrackerLooper(void);
  204.     void MessageReceived(BMessage *msg);
  205.     BOOL QuitRequested(void);
  206.  
  207.     BOOL mIsPlaying;
  208. };
  209.  
  210.  
  211. //*************************************
  212. class CTrackerApp : public BApplication
  213. //*************************************
  214. #pragma mark CTrackerApp
  215. {
  216. public:
  217.  
  218.     CTrackerApp(ulong sign);
  219.     ~CTrackerApp(void);
  220.     //thread_id Run(void);
  221.     void ReadyToRun(void);
  222.     void MessageReceived(BMessage *msg);
  223.     bool QuitRequested(void);
  224.     void RefsReceived(BMessage *msg);
  225.  
  226.     void createAppMenu(void);
  227.     void uglyAboutBox(void);
  228.  
  229.     CTrackerLooper *mTrackerLooper;
  230.     CTrackerWin *mWindow;
  231.     BAudioSubscriber *mPlayer;
  232.     BLocker mBufferLock;
  233.     BList mBufferList;    // a list of SBufferItem ptrs to be played
  234.     BList mFileList;        // a list of CFileItem ptrs to be selected
  235.     BPopUpMenu *mMainMenu;
  236.  
  237.     ULONG mInstantRightVolume, mInstantLeftVolume;
  238.  
  239.     void addFileToList(record_ref ref);
  240.     void addDirectoryToList(record_ref ref);
  241.  
  242.     void playList(void);
  243.     void playNext(void);
  244.     void stopPlay(void);
  245.  
  246.     static long trackerTask(void *data);
  247.     static void trackerPlayBuffer(UBYTE *buffer, long length);
  248.     static void trackerFastExit(void);
  249.     static bool trackerStreamPlay(void *user, char *buffer, long count);
  250. };
  251.  
  252.  
  253. //--------------------------------------------------------------------------------
  254. #pragma mark -
  255.  
  256.  
  257. #ifdef __STRDUP_WAS_NOT_DEFINED_IN_BEOS_11DR6_
  258.  
  259. //*************************************
  260. char *strdup(const char *s)
  261. //*************************************
  262. // these loosy DR6 headers doesn't contains strdup !
  263. {
  264.     if (!s) return NULL;
  265.     char *s2 = new char[strlen(s)+1];
  266.     strcpy(s2,s);
  267.     return s2;
  268. }
  269.  
  270. #endif
  271.  
  272. /******************************************************************************/
  273. void dprintf(char *format, ...)
  274. /******************************************************************************/
  275. {
  276.     va_list va;
  277.     
  278.   if (!gDevSerial4) return;
  279.  
  280.     va_start(va, format);
  281.     vfprintf(gDevSerial4, format, va);
  282.     va_end(va);
  283.     
  284. } /* of dprintf */
  285.  
  286.  
  287. //--------------------------------------------------------------------------------
  288. #pragma mark -
  289.  
  290.  
  291. //************************
  292. CFileItem::CFileItem(void)
  293. //************************
  294. {
  295.     mDisplayName = NULL;
  296.     mFileName = NULL;
  297.     mIsPlaying = FALSE;
  298.     mOrder = FALSE;
  299. }
  300.  
  301.  
  302. //*************************
  303. CFileItem::~CFileItem(void)
  304. //*************************
  305. {
  306.     if (mDisplayName) delete mDisplayName;
  307.     if (mFileName) delete mFileName;
  308. }
  309.  
  310.  
  311. //--------------------------------------------------------------------------------
  312. #pragma mark -
  313.  
  314.  
  315. //*************************************
  316. CFileList::CFileList(BRect frame, char *name,
  317.                         ULONG resizeMode,
  318.                         ULONG flags)
  319.                     :BListView(frame,name,resizeMode,flags)
  320. //*************************************
  321. {
  322. }
  323.  
  324. //*************************************
  325. CFileList::~CFileList()
  326. //*************************************
  327. {
  328. }
  329.  
  330.  
  331. //*************************************
  332. bool CFileList::MessageDropped(BMessage *msg, BPoint point, BPoint offset)
  333. //*************************************
  334. {
  335.     if (msg->HasRef("refs"))
  336.     {
  337.         msg->what = B_REFS_RECEIVED;
  338.         be_app->RefsReceived(msg);
  339.         return FALSE;
  340.     }
  341.     return TRUE;
  342. }
  343.  
  344.  
  345.  
  346. //--------------------------------------------------------------------------------
  347. #pragma mark -
  348.  
  349.  
  350. //********************************
  351. CElectrogramme::CElectrogramme(BRect frame, const char *name, BOOL rightChannel,
  352.                                                              ULONG resizeMode, ULONG flags)
  353.                              :BView(frame, name, resizeMode, flags|B_PULSE_NEEDED)
  354. //********************************
  355. {
  356.     mRightChannel = rightChannel;
  357.     mAllocWidth = max(200,frame.Width());
  358.     mValue = new SHORT[mAllocWidth];
  359.     if (!mValue) mAllocWidth = 0;
  360.     else memset(mValue, 0, sizeof(SHORT)*mAllocWidth);
  361. }
  362.  
  363.  
  364. //********************************
  365. CElectrogramme::~CElectrogramme(void)
  366. //********************************
  367. {
  368.     if (mValue) delete mValue;
  369.     mAllocWidth = 0;
  370. }
  371.  
  372.  
  373. //*****************************************
  374. void CElectrogramme::AttachedToWindow(void)
  375. //*****************************************
  376. {
  377.     if (Window() && Window()->Lock())
  378.     {
  379.         SetViewColor(K_ELECTRO_GRAY);
  380.         Window()->Unlock();
  381.     }
  382. }
  383.  
  384.  
  385. //********************************
  386. void CElectrogramme::Pulse(void)
  387. //********************************
  388. {
  389.     if (Window() && Window()->Lock())
  390.     {
  391.         Draw(Bounds());
  392.         Window()->Unlock();
  393.     }
  394. }
  395.  
  396. //********************************
  397. void CElectrogramme::Draw(BRect r)
  398. //********************************
  399. // be sure this is not efficient at all. Ou presque.
  400. {
  401. register ULONG nbuf;
  402. register ULONG w,h;
  403. register ULONG i;
  404. rgb_color backgroundColor = {K_ELECTRO_GRAY};
  405. rgb_color liveColor = {K_ELECTRO_GREEN};
  406. register CTrackerApp *app = (CTrackerApp *)be_app;
  407. register SBufferItem *item;
  408.  
  409.     if (!Window() || !Window()->Lock()) return;
  410.  
  411.     w = min(Bounds().Width(), mAllocWidth);
  412.     h = Bounds().Height();
  413.  
  414.     // first eraase the current data buffer
  415.     memset(mValue, 0, w*sizeof(SHORT));
  416.     
  417.     app->mBufferLock.Lock();
  418.  
  419.     register SHORT *val = mValue;
  420.     register DOUBLE haut= (DOUBLE)h/2/16.0/32768.0;
  421.     for(i=0, nbuf=0; i<w; /* no inc */ )
  422.     {
  423.         item = (SBufferItem *)app->mBufferList.ItemAt(nbuf);
  424.         if (item && item->data)
  425.         {
  426.             register ULONG j;
  427.             register SHORT *ptr = (SHORT *)item->data;
  428.             if (mRightChannel) ptr++;
  429.             for(j=0; j<2048 && i<w; j+=32, ptr+=32, i++)
  430.             {
  431.                 register LONG a;
  432.                 a  = ptr[ 0];
  433.                 a += ptr[ 2];
  434.                 a += ptr[ 4];
  435.                 a += ptr[ 6];
  436.                 a += ptr[ 8];
  437.                 a += ptr[10];
  438.                 a += ptr[12];
  439.                 a += ptr[14];
  440.                 a += ptr[16];
  441.                 a += ptr[18];
  442.                 a += ptr[20];
  443.                 a += ptr[22];
  444.                 a += ptr[24];
  445.                 a += ptr[26];
  446.                 a += ptr[28];
  447.                 a += ptr[30];
  448.                 *(val++) = haut*a;    // division par 16 dans 'haut'
  449.             }
  450.         }
  451.         else break;
  452.         nbuf++;
  453.     }
  454.  
  455.     app->mBufferLock.Unlock();
  456.  
  457.     // first erase old chart
  458.     SetHighColor(backgroundColor);
  459.     FillRect(r);
  460.  
  461.     // second draw new chart
  462.     if (w>0)
  463.     {
  464.         BeginLineArray(w);
  465.         //for(i=0; i<w; i++)
  466.         //    AddLine(BPoint(i,mid), BPoint(i,mid-mValue[i]), liveColor);
  467.         register ULONG mid=h/2;
  468.         register ULONG end=w-1;
  469.         register ULONG i2=1;
  470.         register USHORT a=mid-mValue[0];
  471.         for(i=0;i<end;i++,i2++)
  472.             AddLine(BPoint(i,a), BPoint(i2,(a=mid-mValue[i2])), liveColor);
  473.     }
  474.     EndLineArray();
  475.     Sync();
  476.  
  477.     Window()->Unlock();
  478. }
  479.  
  480.  
  481. //**********************************************************
  482. void CElectrogramme::FrameResized(float width, float height)
  483. //**********************************************************
  484. {
  485. ULONG w=width;
  486.     if (!Window() || !Window()->Lock()) return;
  487.  
  488.     if (w > mAllocWidth)
  489.     {
  490.         SHORT *newPtr = new SHORT[w];
  491.         if (newPtr)
  492.         {
  493.             memset(newPtr, 0, w*sizeof(SHORT));
  494.             if (mValue)
  495.             {
  496.                 memcpy(newPtr, mValue, mAllocWidth*sizeof(SHORT));
  497.                 delete mValue;
  498.             }
  499.             mValue = newPtr;
  500.             mAllocWidth = w;
  501.         }
  502.     }
  503.  
  504.     Window()->Unlock();
  505. }
  506.  
  507.  
  508. //--------------------------------------------------------------------------------
  509. #pragma mark -
  510.  
  511.  
  512. //********************************
  513. CTrackerWin::CTrackerWin(void)
  514.                         :BWindow(BRect(100,100,100+450,100+230), "R'alf Tracker 0.3a", B_TITLED_WINDOW, B_NOT_RESIZABLE|B_NOT_ZOOMABLE)
  515. //********************************
  516. {
  517.     BButton *button;
  518.     ULONG x1=5,    x2=145,        x3=170, x4=445,
  519.                                                 x5=170, x6=250,        x7=255, x8=335,        x9=340, x10=390,        x11=395, x12=445;
  520.     ULONG y1=5, y2=225,        y3=180, y4=200,        y5=205, y6=225;
  521.  
  522.     // background
  523.     CBackView *back = new CBackView(BRect(x1-5,y1-5,x4+5,y2+5), "", B_FOLLOW_ALL, B_WILL_DRAW);
  524.     if (back) AddChild(back);
  525.     else return;    // things are getting harder...
  526.  
  527.     // file scroll list
  528.     mFileList = new CFileList(BRect(x1,y1, x2,y2), "", B_FOLLOW_LEFT|B_FOLLOW_TOP_BOTTOM);
  529.     mFileList->SetInvocationMessage(new BMessage(K_MSG_PLAY));
  530.     mFileScroll = new BScrollView("fileScroll", mFileList, B_FOLLOW_LEFT|B_FOLLOW_TOP_BOTTOM, 0, FALSE, TRUE);
  531.     back->AddChild(mFileScroll);
  532.  
  533.     // stack of buttons
  534.     button = new BButton(BRect(x5, y3, x6, y4), "", "Load list", new BMessage(K_MSG_LOAD), B_FOLLOW_BOTTOM);
  535.     back->AddChild(button);
  536.     button = new BButton(BRect(x7, y3, x8, y4), "", "Alphabetize", new BMessage(K_MSG_ALFA), B_FOLLOW_BOTTOM);
  537.     back->AddChild(button);
  538.     button = new BButton(BRect(x9, y3, x10, y4), "", "Play", new BMessage(K_MSG_PLAY), B_FOLLOW_BOTTOM);
  539.     back->AddChild(button);
  540.     button = new BButton(BRect(x11,y3, x12, y4), "", "Stop", new BMessage(K_MSG_STOP), B_FOLLOW_BOTTOM);
  541.     back->AddChild(button);
  542.  
  543.     button = new BButton(BRect(x5, y5, x6, y6), "", "Save list", new BMessage(K_MSG_SAVE), B_FOLLOW_BOTTOM);
  544.     back->AddChild(button);
  545.     button = new BButton(BRect(x7, y5, x8, y6), "", "Randomize", new BMessage(K_MSG_RAND), B_FOLLOW_BOTTOM);
  546.     back->AddChild(button);
  547.     button = new BButton(BRect(x9, y5, x10, y6), "", "Next", new BMessage(K_MSG_NEXT), B_FOLLOW_BOTTOM);
  548.     back->AddChild(button);
  549.     button = new BButton(BRect(x11,y5, x12, y6), "", "Quit", new BMessage(K_MSG_QUIT), B_FOLLOW_BOTTOM);
  550.     back->AddChild(button);
  551.  
  552.     // strings
  553.     mDisplayName = new BStringView(BRect(x3, 5, x4, 5+13), "", "", B_FOLLOW_LEFT_RIGHT|B_FOLLOW_TOP);
  554.     mFileName = new BStringView(BRect(x3, 25, x4, 25+13), "", "", B_FOLLOW_LEFT_RIGHT|B_FOLLOW_TOP);
  555.     back->AddChild(mDisplayName);
  556.     back->AddChild(mFileName);
  557.  
  558.     // elctrogramme
  559.     mElectroLeft = new CElectrogramme(BRect(x3,45,x4,45+60), "", FALSE, B_FOLLOW_LEFT_RIGHT|B_FOLLOW_TOP);
  560.     mElectroRight = new CElectrogramme(BRect(x3,110,x4,110+60), "", TRUE, B_FOLLOW_LEFT_RIGHT|B_FOLLOW_TOP);
  561.     back->AddChild(mElectroLeft);
  562.     back->AddChild(mElectroRight);
  563.     
  564.     SetPulseRate(60);
  565. }
  566.  
  567.  
  568. //********************************
  569. void CTrackerWin::MessageReceived(BMessage *msg)
  570. //********************************
  571. {
  572.     switch(msg->what)
  573.     {
  574.         case K_MSG_PLAY:
  575.         case K_MSG_STOP:
  576.         case K_MSG_NEXT:
  577.         case K_MSG_QUIT:
  578.         case K_MSG_LOAD:
  579.         case K_MSG_SAVE:
  580.         case K_MSG_RAND:
  581.         case K_MSG_ALFA:
  582.             msg = DetachCurrentMessage();
  583.             be_app->PostMessage(msg);
  584.             break;
  585.         default:
  586.             BWindow::MessageReceived(msg);
  587.     }
  588. }
  589.  
  590. //********************************
  591. bool CTrackerWin::QuitRequested(void)
  592. //********************************
  593. {
  594.     be_app->PostMessage(B_QUIT_REQUESTED);
  595.     return TRUE;
  596. }
  597.  
  598.  
  599. //********************************
  600. void CTrackerWin::setPlayNames(char *display, char *file)
  601. //********************************
  602. {
  603.     Lock();
  604.     mDisplayName->SetText(display);
  605.     mFileName->SetText(file);
  606.     Unlock();
  607. }
  608.  
  609.  
  610. //------------------------------------------------------
  611. #pragma mark -
  612.  
  613.  
  614.  
  615. //********************************
  616. CTrackerApp::CTrackerApp(ulong sign) : BApplication(sign)
  617. //********************************
  618. {
  619.     mTrackerLooper = NULL;
  620.     mWindow = NULL;
  621.     mPlayer = NULL;
  622.     mInstantRightVolume = NULL;
  623.     mInstantLeftVolume = NULL;
  624. }
  625.  
  626.  
  627. //********************************
  628. CTrackerApp::~CTrackerApp(void)
  629. //********************************
  630. {
  631. long i,n;
  632.  
  633.     dprintf("deleting audio subscriber\n");
  634.     if (mPlayer) delete mPlayer;
  635.     mPlayer = NULL;
  636.  
  637.     dprintf("delete tracker task\n");
  638.     if (mTrackerLooper) mTrackerLooper->Quit();
  639.  
  640.     dprintf("Freing buffers...");
  641.     mBufferLock.Lock();
  642.     n = mBufferList.CountItems();
  643.     dprintf("Number of buffers in the list : %d\n", n);
  644.     for(i = 0; i < n; i++)
  645.     {
  646.         SBufferItem *item = (SBufferItem *)mBufferList.ItemAt(i);
  647.         if (!item) continue;
  648.         if (item->data) delete item->data;
  649.         delete item;
  650.     }
  651.     mBufferLock.Unlock();
  652.     dprintf("End of destructor of CTrackerApp\n");
  653. }
  654.  
  655.  
  656. //**********************************************
  657. void CTrackerApp::MessageReceived(BMessage *msg)
  658. //**********************************************
  659. {
  660.     switch(msg->what)
  661.     {
  662.         case K_MSG_PLAY:
  663.             playList();
  664.             break;
  665.         case K_MSG_NEXT:
  666.             playNext();
  667.         case K_MSG_STOP:
  668.             stopPlay();
  669.             break;
  670.         case K_MSG_LOAD:
  671.         case K_MSG_SAVE:
  672.         case K_MSG_RAND:
  673.         case K_MSG_ALFA:
  674.             break;
  675.         case K_MSG_QUIT:
  676.             gBeAudioNextModule = TRUE;
  677.             gBeAudioQuitModule = TRUE;
  678.             PostMessage(B_QUIT_REQUESTED);
  679.             break;
  680.         case K_MSG_ABOUT:
  681.             uglyAboutBox();
  682.             break;;
  683.         default:
  684.             // dprintf...
  685.             break;
  686.     }
  687. }
  688.  
  689.  
  690. //*******************************************
  691. void CTrackerApp::RefsReceived(BMessage *msg)
  692. //*******************************************
  693. {
  694. BOOL succeed = FALSE;
  695. ULONG type, i;
  696. LONG count;
  697. record_ref item;
  698.  
  699.     if (!msg) return;
  700.     msg->GetInfo("refs", &type, &count);
  701.     for(i = 0; i < count; i++)
  702.     {
  703.         item = msg->FindRef("refs", i);
  704.         if (item.database >= 0 && item.record >= 0)
  705.             if (does_ref_conform(item, "File")) addFileToList(item);
  706.             else if (does_ref_conform(item, "Folder")) addDirectoryToList(item);
  707.     }
  708. }
  709.  
  710.  
  711. //********************************
  712. bool CTrackerApp::QuitRequested(void)
  713. //********************************
  714. {
  715.     if (mTrackerLooper) return mTrackerLooper->QuitRequested();
  716.     return TRUE;
  717. }
  718.  
  719.  
  720. #ifdef NO_RUN
  721. //********************************
  722. thread_id CTrackerApp::Run(void)
  723. //********************************
  724. {
  725.     thread_id retVal = BApplication::Run();
  726.     return retVal;
  727. }
  728. #endif
  729.  
  730. //********************************
  731. void CTrackerApp::ReadyToRun(void)
  732. //********************************
  733. {
  734.     // create the playing thread
  735.     mTrackerLooper = new CTrackerLooper(B_REAL_TIME_PRIORITY);
  736.  
  737.     // create the window
  738.     mWindow = new CTrackerWin;
  739.     if (mWindow) mWindow->Show();
  740.  
  741.     createAppMenu();
  742.  
  743.     // create the audio subscriber
  744.     mPlayer = new BAudioSubscriber("TrackerPlayer");
  745.     if (mPlayer)
  746.     {
  747.         long error;
  748.         error = mPlayer->Subscribe(B_DAC_STREAM,B_INVISIBLE_SUBSCRIBER_ID,TRUE);
  749.  
  750.         error = mPlayer->SetDACSampleInfo(2, 2, B_BIG_ENDIAN, B_LINEAR_SAMPLES);
  751.         error = mPlayer->SetSamplingRate(44100);
  752.  
  753.         long bufSize, bufCount, subCount;
  754.         BOOL isRunning;
  755.         subscriber_id clique;
  756.         error = mPlayer->GetStreamParameters(&bufSize, &bufCount, &isRunning, &subCount, &clique);
  757.         
  758.         error = mPlayer->EnterStream(NULL, FALSE, NULL,
  759.                                                                 trackerStreamPlay, NULL, TRUE);
  760.     }
  761. }
  762.  
  763.  
  764. //***********************************
  765. void CTrackerApp::createAppMenu(void)
  766. //***********************************
  767. {
  768. BMenuItem *item;
  769.  
  770.     mMainMenu = new BPopUpMenu("", FALSE, FALSE);
  771.     if (!mMainMenu) return;
  772.  
  773.     item = new BMenuItem("About...", new BMessage(K_MSG_ABOUT));                            mMainMenu->AddItem(item);
  774.     mMainMenu->AddSeparatorItem();
  775.     item = new BMenuItem("Load list...", new BMessage(K_MSG_LOAD), 'O');    mMainMenu->AddItem(item);
  776.     item = new BMenuItem("Save list...", new BMessage(K_MSG_SAVE), 'S');    mMainMenu->AddItem(item);
  777.     item = new BMenuItem("Alphabetize", new BMessage(K_MSG_ALFA),  'A');    mMainMenu->AddItem(item);
  778.     item = new BMenuItem("Randomize",        new BMessage(K_MSG_RAND),  'R');    mMainMenu->AddItem(item);
  779.     mMainMenu->AddSeparatorItem();
  780.     item = new BMenuItem("Play", new BMessage(K_MSG_PLAY), 'P');                    mMainMenu->AddItem(item);
  781.     item = new BMenuItem("Next", new BMessage(K_MSG_NEXT), 'N');                    mMainMenu->AddItem(item);
  782.     item = new BMenuItem("Stop", new BMessage(K_MSG_STOP), 'S');                    mMainMenu->AddItem(item);
  783.     mMainMenu->AddSeparatorItem();
  784.     item = new BMenuItem("Quit", new BMessage(K_MSG_QUIT), 'Q');                    mMainMenu->AddItem(item);
  785.  
  786.     SetMainMenu(mMainMenu);
  787. }
  788.  
  789.  
  790. //***********************************
  791. void CTrackerApp::uglyAboutBox(void)
  792. //***********************************
  793. {
  794.     BAlert *about;
  795.  
  796.     about = new BAlert(    "R'alf Tracker",
  797.                                             "R'alf Tracker 0.3alpha\n\n"
  798.                                             "A simple interface wrapped around Marc Espie's tracker player 3.19.\n\n"
  799.                                             "Freeware by Raphael MOLL (moll@linux.utc.fr)",
  800.                                             "OK");
  801.     if (about) about->Go();
  802.  
  803. } // end of uglyAboutBox
  804.  
  805.  
  806. //------------------------------------------------------
  807. #pragma mark -
  808.  
  809.  
  810. //********************************
  811. void CTrackerApp::addFileToList(record_ref ref)
  812. //********************************
  813. {
  814.     if (does_ref_conform(ref, "Folder"))
  815.     {
  816.         addDirectoryToList(ref);
  817.         return;
  818.     }
  819.  
  820.     if (!mWindow || !mWindow->mFileList) return;
  821.  
  822.     // and why does CodeWarior 8 refuses to call _register_auto_objects here ?
  823.     // this is the brute force answer !
  824.     BFile *file = new BFile;
  825.     BDirectory *dir = new BDirectory;
  826.     BDirectory *dir2 = new BDirectory;
  827.  
  828.     if (!file || !dir || !dir2) return;
  829.  
  830.     // create the file instance...
  831.     file->SetRef(ref);
  832.  
  833.     // create a new file item for the list
  834.     CFileItem *item = new CFileItem();
  835.     if (!item) return;    // critical. Should not occur.
  836.     
  837.     // extract the name to be displayed
  838.     item->mDisplayName = new char[256];
  839.     file->GetName(item->mDisplayName);
  840.  
  841.     // check if that name already exists in the list...
  842.     ULONG i,n;
  843.     n = mFileList.CountItems();
  844.     for(i=0;i<n;i++)
  845.     {
  846.         CFileItem *item2 = (CFileItem *)mFileList.ItemAt(i);
  847.         if (item2
  848.                 && item2->mDisplayName
  849.                 && strcmp(item2->mDisplayName, item->mDisplayName) == 0)
  850.         {
  851.             // then remove the old item
  852.             mFileList.RemoveItem(item2);
  853.             mWindow->mFileList->RemoveItem(item2->mDisplayName);
  854.             delete item2;
  855.         }
  856.     }
  857.  
  858.     // extract the directory path
  859.     LONG error;
  860.     char s1[512]="";
  861.     char s2[512]="";
  862.     file->GetName(s2);
  863.     error = file->GetParent(dir);
  864.     while(error == B_NO_ERROR)
  865.     {
  866.         dir->GetName(s1);
  867.         if (strlen(s2))
  868.         {
  869.             strcat(s1, "/");
  870.             strcat(s1, s2);
  871.         }
  872.         strcpy(s2, s1);
  873.         error = dir->GetParent(dir2);
  874.         if (error == B_NO_ERROR) dir->SetRef(dir2->Record()->Ref());
  875.     }
  876.     strcpy(s1, "/");
  877.     strcat(s1, s2);
  878.     strcpy(s2, s1);
  879.  
  880.     item->mFileName = strdup(s2);
  881.     mFileList.AddItem(item);    // add the item to the list of the app
  882.     mWindow->mFileList->AddItem(item->mDisplayName);    // add the name to be displayed
  883.     mWindow->mFileList->Select(mWindow->mFileList->CountItems()-1);
  884.  
  885.     delete file;
  886.     delete dir;
  887.     delete dir2;
  888. }
  889.  
  890.  
  891. //********************************
  892. void CTrackerApp::addDirectoryToList(record_ref ref)
  893. //********************************
  894. {
  895.     if (does_ref_conform(ref, "File"))
  896.     {
  897.         addFileToList(ref);
  898.         return;
  899.     }
  900.  
  901.     // and why does CodeWarior 8 refuses to call _register_auto_objects here ?
  902.     BFile *file = new BFile;
  903.     BDirectory *dir = new BDirectory;
  904.     BDirectory *dir2 = new BDirectory;
  905.     long i,n;
  906.     long error;
  907.  
  908.     if (!file || !dir || !dir2) return;
  909.  
  910.     dir->SetRef(ref);
  911.  
  912.     // first load every file
  913.     n = dir->CountFiles();
  914.     for(i=0; i<n; i++)
  915.     {
  916.         error = dir->GetFile(i, file);
  917.         if (error == B_NO_ERROR) addFileToList(file->Record()->Ref());
  918.     }
  919.  
  920.     // then load every sub directory
  921.     n = dir->CountDirectories();
  922.     for(i=0; i<n; i++)
  923.     {
  924.         error = dir->GetDirectory(i, dir2);
  925.         if (error == B_NO_ERROR) addDirectoryToList(dir2->Record()->Ref());
  926.     }
  927.  
  928.     delete file;
  929.     delete dir;
  930.     delete dir2;
  931. }
  932.  
  933.  
  934. //------------------------------------------------------
  935. #pragma mark -
  936.  
  937. //********************************
  938. void CTrackerApp::playList(void)
  939. //********************************
  940. {
  941. ULONG index = mWindow->mFileList->CurrentSelection();
  942. CFileItem *item;
  943.  
  944.     stopPlay();
  945.  
  946.     item = (CFileItem *)mFileList.ItemAt(index);
  947.     if (item && item->mFileName && item->mDisplayName)
  948.     {
  949.         BMessage *msg = new BMessage(K_MSG_PLAY);
  950.         msg->AddString("filename", item->mFileName);
  951.         msg->AddString("displayname", item->mDisplayName);
  952.         mTrackerLooper->PostMessage(msg);
  953.     }
  954. }
  955.  
  956.  
  957. //********************************
  958. void CTrackerApp::playNext(void)
  959. //********************************
  960. {
  961. ULONG index;
  962.  
  963.     index = mWindow->mFileList->CurrentSelection()+1;
  964.     if (index >= mWindow->mFileList->CountItems()) index = 0;
  965.     mWindow->mFileList->Select(index);
  966.     playList();
  967. }
  968.  
  969.  
  970. //********************************
  971. void CTrackerApp::stopPlay(void)
  972. //********************************
  973. {
  974.     if (mTrackerLooper->mIsPlaying)
  975.     {
  976.         gBeAudioNextModule = TRUE;
  977.         gBeAudioQuitModule = TRUE;
  978.     }
  979. }
  980.  
  981.  
  982. //------------------------------------------------------
  983. #pragma mark -
  984.  
  985. //********************************
  986. void CTrackerApp::trackerFastExit(void)
  987. //********************************
  988. {
  989.     dprintf("Fast exit from Tracker Task requested\n");
  990.     be_app->PostMessage(B_QUIT_REQUESTED);
  991. }
  992.  
  993.  
  994.  
  995. //********************************
  996. void CTrackerApp::trackerPlayBuffer(UBYTE *buffer, long length)
  997. //********************************
  998. {
  999. CTrackerApp *app = (CTrackerApp *)be_app;
  1000. SBufferItem *item;
  1001. long n;
  1002.  
  1003.     //dprintf("play buffer : length %8d, ptr %p\n", length, buffer);
  1004.  
  1005.     item = new SBufferItem;
  1006.     if (!item) return; // can't alloc item
  1007.     item->data = new UBYTE[length];
  1008.     item->length = length;
  1009.     memcpy(item->data, buffer, length);
  1010.  
  1011.     app->mBufferLock.Lock();
  1012.     app->mBufferList.AddItem(item);
  1013.     n = app->mBufferList.CountItems();
  1014.     app->mBufferLock.Unlock();
  1015.  
  1016.     // each buffer of 4096 bytes takes approximately 23 ms to play.
  1017.     // if we have more than 50 buffer, give enougth time to suppress 30 buffers
  1018.     // from the list.
  1019.     if (n > 50) snooze(23000*30);
  1020. }
  1021.  
  1022.  
  1023. //********************************
  1024. bool CTrackerApp::trackerStreamPlay(void *user, char *buffer, long count)
  1025. //********************************
  1026. {
  1027. CTrackerApp *app = (CTrackerApp *)be_app;
  1028. SBufferItem *item;
  1029. long n;
  1030.  
  1031.     app->mBufferLock.Lock();
  1032.     item = (SBufferItem *)app->mBufferList.RemoveItem(0L);
  1033.     n = app->mBufferList.CountItems();
  1034.     app->mBufferLock.Unlock();
  1035.     if (item)
  1036.     {
  1037.         if (item->data)
  1038.         {
  1039.             //dprintf("buffer %08p, count %6d, data %08p, length %6d, items %d\n", buffer, count,item->data, item->length,n);
  1040.             memcpy(buffer, item->data, min(count, item->length));
  1041.             delete item->data;
  1042.         }
  1043.         delete item;
  1044.     }
  1045.  
  1046.     return TRUE;
  1047. }
  1048.  
  1049.  
  1050. //------------------------------------------------------
  1051. #pragma mark -
  1052.  
  1053.  
  1054. //*******************************************
  1055. CTrackerLooper::CTrackerLooper(long priority)
  1056.                              :BLooper("player", priority)
  1057. //*******************************************
  1058. {
  1059.     dprintf("Tracker Task launched\n");
  1060.  
  1061.     gBeAudioBufSize = 4096;
  1062.     gBeAudioPlayBuffer = CTrackerApp::trackerPlayBuffer;
  1063.     gBeAudioExit = CTrackerApp::trackerFastExit;
  1064.     mIsPlaying = FALSE;
  1065.     setup_play_track(FALSE, TRUE);
  1066.  
  1067.     Run();    // launch the thread and run separately...
  1068. }
  1069.  
  1070. //***********************************
  1071. CTrackerLooper::~CTrackerLooper(void)
  1072. //***********************************
  1073. {
  1074.     gBeAudioNextModule = TRUE;
  1075.     gBeAudioQuitModule = TRUE;
  1076.     mIsPlaying = FALSE;
  1077.     close_play_track();
  1078. }
  1079.  
  1080. //**************************************
  1081. BOOL CTrackerLooper::QuitRequested(void)
  1082. //**************************************
  1083. {
  1084.     gBeAudioNextModule = TRUE;
  1085.     gBeAudioQuitModule = TRUE;
  1086.     mIsPlaying = FALSE;
  1087.     return TRUE;
  1088. }
  1089.  
  1090. //*************************************************
  1091. void CTrackerLooper::MessageReceived(BMessage *msg)
  1092. //*************************************************
  1093. {
  1094.     if (msg && !mIsPlaying)
  1095.     {
  1096.         CTrackerApp *app = (CTrackerApp *)be_app;
  1097.         mIsPlaying = TRUE;
  1098.         gBeAudioNextModule = FALSE;
  1099.         gBeAudioQuitModule = FALSE;
  1100.  
  1101.         char displayname[256] = "Playing ";
  1102.         strcat(displayname, (char *)msg->FindString("displayname"));
  1103.         char *filename = (char *)msg->FindString("filename");
  1104.         app->mWindow->setPlayNames(displayname, filename);
  1105.  
  1106.         play_track(filename);
  1107.  
  1108.         app->mWindow->setPlayNames("Stopped", "");
  1109.  
  1110.         mIsPlaying = FALSE;
  1111.         if (!gBeAudioQuitModule) app->PostMessage(K_MSG_NEXT);
  1112.     }
  1113. }
  1114.  
  1115.  
  1116. //------------------------------------------------------
  1117. #pragma mark -
  1118.  
  1119.  
  1120. //******************************
  1121. void main(int argc, char **argv)
  1122. //******************************
  1123. {
  1124. #ifdef K_ENABLE_LOG
  1125.     OPEN_LOG();
  1126. #endif
  1127.  
  1128.     CTrackerApp *theApp;
  1129.     theApp = new CTrackerApp('Trak');
  1130.     if (!theApp) return;
  1131.     theApp->Run();
  1132.     delete theApp;
  1133.     
  1134.     CLOSE_LOG();
  1135. }
  1136.  
  1137. //------------------------------------------------------
  1138.