home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: Multimed / Multimed.zip / lechmp3.zip / leechmp3.rxx < prev    next >
Text File  |  2000-05-13  |  13KB  |  438 lines

  1. /********************************************************************/
  2. /*                                                                  */
  3. /* LEECHMP3: Version 1.0                                            */
  4. /* Author: Michel SUCH. Email: msuch@free.fr                        */
  5. /*                                                                  */
  6. /* Multithreaded conversion from CD to MP3.                         */
  7. /*                                                                  */
  8. /* This program requires several components to be installed         */
  9. /*                                                                  */
  10. /* 1: LEECH 1.20.                                                   */
  11. /* 2: LAME MP3 encoder.                                             */
  12. /* All components may be obtained on HOBBES: http://hobbes.nmsu.edu */
  13. /*                                                                  */
  14. /* LEECH.EXE and LAME.EXE must be located in a directory defined    */
  15. /* in the path variable of the CONFIG.SYS file                      */
  16. /* or in the directory containing the LEECHMP3 program.             */
  17. /********************************************************************/
  18.  
  19.    parse arg parms
  20.    x= pos('-', parms)
  21.    if x > 0 then do
  22.       lameparms = substr(parms, x)
  23.       parms = delstr(parms, x)
  24.    end
  25.    else lameparms = ''
  26.    parse upper value(strip(parms)) with process parms
  27.    call init_prog
  28.    select
  29.       when process = "GRAB" then do /* start grabbing process */
  30.          parse var parms grabber encoder cdrom wavqueue
  31.          call init_cd
  32.          call leech
  33.          call end_cd
  34.       end
  35.       when process = "ENCODE" then  do /* start mp3 encoding process */
  36.          parse var parms encoder qname
  37.          call init_mp3
  38.          call lame
  39.          call end_mp3
  40.       end
  41.       when process = '' | process = "T" then do /* initial process */
  42.          call presentation
  43.  
  44.          /* Check if we have all needed programs */
  45.          grabber = find_prog('LEECH.EXE')
  46.          if grabber = '' then do
  47.             say "Cannot find LEECH.EXE grabber program"
  48.             exit
  49.          end
  50.          say "Grabbing using" grabber
  51.  
  52.          encoder = find_prog('LAME.EXE')
  53.          if encoder = '' then do
  54.             say "Cannot find LAME.EXE encoding program"
  55.             exit
  56.          end
  57.          say "Encoding using" encoder
  58.  
  59.          call get_cdrom
  60.  
  61.          if translate(process) = "T" then do /* tracklist */
  62.          call check_list
  63.          end
  64.          else tracks = "" /* all tracks */
  65.          call get_ntracks
  66.          call sort_trks
  67.          '@START "CD GRABBING THREAD" /C' pgm "GRAB" grabber encoder cdrom wavqueue lameparms
  68.          exit
  69.       end
  70.       otherwise do
  71.          say "invalid parameter" process
  72.          exit
  73.       end
  74.    end
  75. exit
  76.  
  77.  
  78. init_prog:
  79.  
  80.    if rxfuncquery('sysloadfuncs') <> 0 then do
  81.       call rxfuncadd 'sysloadfuncs', 'rexxutil', 'sysloadfuncs'
  82.       call sysloadfuncs
  83.    end
  84.    parse source . . pgm .
  85.    rundir = directory()
  86.    progdir = filespec('D', pgm) || filespec('p', pgm)
  87. return /* init_prog */
  88.  
  89.  
  90. find_prog:
  91. procedure
  92.  
  93.    /* First, search in the program's directory */
  94.    parse source . . me .
  95.    dir = filespec('d', me) || filespec('p', me)
  96.    call sysfiletree dir || arg(1), lst.
  97.    if lst.0 > 0 then  pgm = word(lst.1, 5)
  98.    else do /* search in the path environment variable */
  99.       pgm = syssearchpath( 'path', arg(1))
  100.    end
  101.    drop lst.
  102. return pgm /* get_progs */
  103.  
  104.  
  105. presentation:
  106.  
  107.    parse value(filespec('n', pgm)) with me'.'ext
  108.    say me": Multithreaded CD to MP3, Version 1.0"
  109.    say ""
  110.    say "Author: Michel SUCH. Email: msuch@free.fr"
  111.    say ""
  112. return /* presentation */
  113.  
  114.  
  115. get_cdrom:
  116.  
  117.    /* Determine the unit letter for the CD-ROM */
  118.    cdrom = ''
  119.    list = sysdrivemap('c')
  120.    do i = 1 to words(list)
  121.       dk = word(list, i)
  122.       info = sysdriveinfo(dk)
  123.       free = word(info, 2)
  124.       select
  125.          when info = '' then do
  126.             cdrom = dk
  127.             leave
  128.          end
  129.          when free = 0 then do
  130.             cdrom = dk
  131.             leave
  132.          end
  133.          otherwise nop
  134.       end
  135.    end
  136.    if cdrom = '' then do
  137.       say "Cannot determine your CD-ROM drive letter"
  138.       exit
  139.    end
  140.    say "CD-ROM unit:" cdrom
  141. return /* get_cdrom */
  142.  
  143.  
  144. check_list:
  145. procedure expose parms tracks
  146.  
  147.    /* checks that all track numbers are numeric */
  148.    /* and they are between 1 and 99 */
  149.  
  150.    if parms = '' then do
  151.       say "No track list specified"
  152.       exit
  153.    end
  154.    tracks = ''
  155.    do i = 1 to words(parms)
  156.       trk = strip(word(parms, i), 'l', '0')
  157.       if datatype(trk) <> 'NUM' then do
  158.          say "INVALID TRACK NUMBER" trk
  159.          exit
  160.       end
  161.       if trk < 1 | trk > 99 then do
  162.          say "Track number" trk "out of range"
  163.          exit
  164.       end
  165.       tracks = tracks trk
  166.    end
  167. return /* check_list */
  168.  
  169.  
  170. get_ntracks:
  171. procedure expose grabber cdrom trks trklst. tracks progdir
  172.  
  173.    /* Determines the number of audio tracks on the cd */
  174.    trks = 0
  175.  
  176.    /* make a local queue to prevent conflicts with other process */
  177.    qtrk = rxqueue('create')
  178.    oldq = rxqueue('set', qtrk)
  179.    "@"grabber cdrom "TOC | rxqueue" qtrk
  180.    total = 0
  181.    do queued()
  182.       pull ln
  183.  
  184.       if word(ln, 2) = "PANIC" then do
  185.          rc = rxqueue('set,', oldq)
  186.          rc = rxqueue('delete', qtrk)
  187.          say "Drive" cdrom "not ready or in use"
  188.          call sayfile "notready"
  189.          exit
  190.       end
  191.  
  192.       if wordpos("CDDA", ln) <> 0 then do /* audio track found */
  193.          n = strip(word(ln, 1), 'l', '0') /* track number */
  194.          total = total + 1
  195.          if (tracks = "") | (wordpos(n, tracks) > 0) then do
  196.             trks = trks + 1
  197.             trklst.trks = n strip(word(ln, 8), "T", ")") /* track size in sectors */
  198.          end
  199.       end
  200.    end
  201.    rc = rxqueue('set,', oldq)
  202.    rc = rxqueue('delete', qtrk)
  203.  
  204.    do i = 1 to words(tracks) /* check if all selected tracks exist */
  205.       t = word(tracks, i)
  206.       if t > total then do
  207.          Say "Track" t "Does not exist on this CD"
  208.          exit
  209.       end
  210.    end
  211.  
  212.    trklst.0 = trks
  213.          select
  214.             when trks = 0 then do
  215.                say "No audio track to grab"
  216.                exit
  217.             end
  218.             when trks = 1 then say trks "track will be grabbed"
  219.             otherwise do
  220.             say trks "tracks will be grabbed"
  221.             end
  222.          end
  223. return /* get_ntracks */
  224.  
  225.  
  226. sort_trks:
  227. procedure expose trklst. wavqueue
  228.  
  229.    /* let's sort tracks in ascending size order */
  230.    /* so that the shortest track is grabbed first */
  231.    /* and encoding starts asap */
  232.    wavqueue = rxqueue('create')
  233.    oldq = rxqueue('set', wavqueue)
  234.  
  235.    do while trklst.0 > 0
  236.       minptr = 1
  237.       do i = 2 to trklst.0
  238.          if word(trklst.i, 2) < word(trklst.minptr, 2) then do
  239.             minptr = i
  240.          end
  241.       end
  242.       queue trklst.minptr
  243.       do j = minptr to trklst.0
  244.          k = j + 1
  245.          trklst.j = trklst.k
  246.       end
  247.       trklst.0 = trklst.0 - 1
  248.    end
  249.    oldq = rxqueue('set', oldq)
  250. return /* sort_trks */
  251.  
  252. /**********************************************************************/
  253. /* grabber section.                                                   */
  254. /**********************************************************************/
  255.  
  256. init_cd:
  257.  
  258.    mp3queue = rxqueue('create') /* communication queue with mp3 thread */
  259.    oldq = rxqueue('set', mp3queue)
  260.    '@START "MP3 ENCODING THREAD" /c' pgm "ENCODE" encoder mp3queue lameparms
  261. return /* init_cd */
  262.  
  263.  
  264. get_trklst:
  265. procedure expose wavqueue trklst.
  266.  
  267. say ''
  268.    oldq = rxqueue('set', wavqueue)
  269.    trklst.0 = queued()
  270.    do i = 1 to trklst.0
  271.       pull trklst.i
  272.    end
  273.    oldq = rxqueue('set', oldq)
  274.    rc = rxqueue('delete', wavqueue)
  275. return /* get_trklst */
  276.  
  277.  
  278. leech:
  279.  
  280.    /* grabs tracks and pass them to mp3 process */
  281.    call get_trklst
  282.    do i = 1 to trklst.0
  283.       t = word(trklst.i, 1)
  284.       call sayfile "read"
  285.       call sayfile right(t, 2, ' ')
  286.       /* use a big buffer to improve multitasking */
  287.       "@"grabber cdrom "T" t "-w4096 -s15 -j25 -o -a"
  288.       if rc <> 0 then do /* process killed */
  289.          queue "END" /* abort encoding for next track */
  290.          leave
  291.       end
  292.       queue "TRACK_" || right(t, 2, '0') /* pass file name to encoder */
  293.    end
  294.    queue 'END' /* stop encoder */
  295.    call sayfile "endread"
  296. return /* leech */
  297.  
  298.  
  299. end_cd:
  300.  
  301.   /* finish grabbing process */
  302.    oldq = rxqueue('set', oldq)
  303.    "@EJECT" cdrom
  304. return /* end_cd */
  305.  
  306.  
  307. /**********************************************************************/
  308. /* MP3 encodr section.                                                */
  309. /**********************************************************************/
  310.  
  311. init_mp3:
  312.  
  313.    oldq2 = rxqueue('set', qname) /* setup the input queue */
  314.    say "Waiting for first wave file"
  315. return /* init_mp3 */
  316.  
  317.  
  318. lame:
  319.  
  320.    /* encoding part */
  321.    do forever
  322.       do while queued() = 0 /* wait for something in the queue */
  323.          call syssleep 1
  324.       end
  325.       pull fname
  326.       if fname = "END" then leave
  327.       call sayfile "encode"
  328.       call sayfile strip(right(fname, 2, ' '), 'l', '0')
  329.       wavname = rundir'\'fname'.WAV'
  330.       mp3name = rundir'\'fname'.MP3'
  331.       "@"encoder lameparms wavname  mp3name
  332.       call sysfiledelete wavname
  333.    end
  334.    call sayfile "endenc"
  335. return /* lame */
  336.  
  337.  
  338. end_mp3:
  339.  
  340.    rc = rxqueue('delete', qname)
  341.    do i = 1 to 5 /* make a little noise */
  342.       call beep 440, 100
  343.       call beep 660, 100
  344.    end
  345. return /* end_mp3 */
  346.  
  347. /**********************************************************************/
  348. /* Speech section                                                     */
  349. /**********************************************************************/
  350.  
  351. sayfile:
  352. procedure expose progdir
  353.  
  354.    parse arg fn .
  355.  
  356.    file = progdir"\sounds\"fn".wav"
  357.    call sysfiletree file, lst.
  358.    if lst.0 = 0 then return 1
  359.  
  360.    rc = RXFUNCADD('mciRxInit','MCIAPI','mciRxInit')
  361.    InitRC = mciRxInit()
  362.    MciCmd = "open" file "alias leechmp3 wait"
  363.    do forever
  364.       MacRC = SendString(MciCmd)
  365.       select
  366.          when macrc = 5032 then do /* sound card in use */
  367.             call syssleep 1
  368.             iterate
  369.          end
  370.          when macrc = 0 then leave /* can play */
  371.          otherwise do /* non recoverable error */
  372.             MacRC = mciRxExit()   /* Tell the DLL we're going away        */
  373.             return 1
  374.          end
  375.       end
  376.    end
  377.    MacRC = SendString("capability leechmp3 device type wait")
  378.    if MacRC <> 0 then do
  379.       junk = SendString("close leechmp3 wait")
  380.       junk = SendString("release waveaudio wait")
  381.       MacRC = mciRxExit()   /* Tell the DLL we're going away        */
  382.       return 1
  383.    end
  384.    if TRANSLATE(RetSt) = 'WAVEAUDIO' then do
  385.       MacRC = SendString("status leechmp3 length wait")      /* If length is 0 no file exists */
  386.       if MacRC <> 0 then do
  387.          junk = SendString("close leechmp3 wait")
  388.          junk = SendString("release waveaudio return resource wait")
  389.          MacRC = mciRxExit()   /* Tell the DLL we're going away        */
  390.          return 1
  391.       end
  392.       if RetSt = 0 then do
  393.          junk = SendString("close leechmp3 wait")
  394.          ErrRC = 70555
  395.          macRC = mciRxGetErrorString(ErrRC, 'ErrStVar')
  396. /*       say 'mciRxGetErrorString('ErrRC') =' ErrStVar*/
  397.          junk = SendString("release waveaudio return resource wait")
  398.          MacRC = mciRxExit()   /* Tell the DLL we're going away        */
  399.          return 1
  400.       end
  401.    end
  402.    DeviceID = mciRxGetDeviceID(""leechmp3"")
  403.    MciCmd = 'play leechmp3 wait'
  404.    MacRC = SendString(MciCmd)
  405.    if MacRC <> 0 then do
  406.       junk = SendString("close leechmp3 wait")
  407.       junk = SendString("release waveaudio return resource wait")
  408.       MacRC = mciRxExit()   /* Tell the DLL we're going away        */
  409.       return 1
  410.    end
  411.  
  412.    MacRC = SendString("close leechmp3 wait")
  413.    junk = SendString("release waveaudio return resource wait")
  414.    if MacRC <> 0 then  do
  415.       MacRC = mciRxExit()   /* Tell the DLL we're going away        */
  416.       return 1
  417.    end
  418.    MacRC = mciRxExit()   /* Tell the DLL we're going away        */
  419. return 0
  420.  
  421.  
  422. SendString:
  423.  
  424.    arg CmndTxt
  425.    /* Last two parameters are reserved, must be set to 0           */
  426.    /* Future use of last two parms are for notify window handle    */
  427.    /* and userparm.                                                 */
  428.    MacRC = mciRxSendString(CmndTxt, 'RetSt', '0', '0')
  429.    if MacRC<>0 then do
  430.       ErrRC = MacRC
  431. /*      say 'MciCmd=' CmndTxt*/
  432. /*      say 'Err:mciRxSendString RC=' ErrRC RetSt*/
  433.       MacRC = mciRxGetErrorString(ErrRC, 'ErrStVar')
  434. /*      say 'mciRxGetErrorString('ErrRC') =' ErrStVar*/
  435.       MacRC = ErrRC /* return the error rc */
  436.    end
  437.    return MacRC
  438.