#!/usr/bin/newlisp #------------------------------------------------------------------------------------------ # # Program to play audio CD's on the CDROM drive. First argument may contain CDROM-device. # Device default: /dev/cdrom. # # ---> LINUX ONLY <--- Requires GTK-server 2.0.11 or higher. (c) PvE. License: GPL. # # May 28, 2006 - version 1.0 # - initial release # # June 2, 2006 - version 1.1 # - added eject button # # July 1, 2006 - version 1.2 # - rewrote to embedded GTK :-) # # July 17, 2006 - version 1.3 # - fixed bug when tracks titles are empty # - fixed bug with CDROM ejecting on 2.6 kernels # - added CLOSE_TRAY functionality # - quit is faster now # # September 8, 2007 - version 1.4 # - compliance with GTK-server 2.1.5 and higher # #--------------------------------------------------------------------------------------- GTK (import "libgtk-server.so" "gtk") (set 'cfgfile (open "/etc/gtk-server.cfg" "read")) (cond ((not cfgfile)(println "No GTK-server configfile found! Exiting...")(exit))) (while (read-line cfgfile) (if (starts-with (current-line) "FUNCTION_NAME") (begin (set 'func (chop ((parse (current-line) " ") 2))) (set 'lb (append {(lambda()(setq s "} func {")(dolist (x (args))(setq s (string s " " x)))(get-string (gtk s)))})) (constant (global (sym func)) (eval-string lb)) ) ) ) (close cfgfile) (set 'NULL "NULL") #---------------------------------------------------------------------------------------- GUI (context 'GUI) # Setup XML IDE definition (set 'Cdplayer [text]' 250 90 True CD Player GTK_WINDOW_TOPLEVEL GTK_WIN_POS_NONE False True False True False False GDK_WINDOW_TYPE_HINT_NORMAL GDK_GRAVITY_NORTH_WEST True True False 0 True False 0 True False 0 30 True <b>Status</b>: <i><span foreground="red">STOPPED</span></i> False True GTK_JUSTIFY_CENTER False False 0.5 0.5 0 0 PANGO_ELLIPSIZE_NONE -1 False 0 0 True True True <b>Time:</b> <i><span foreground="blue">00:00:00</span></i> False True GTK_JUSTIFY_RIGHT False False 0.5 0.5 0 0 PANGO_ELLIPSIZE_NONE -1 False 0 0 True True 0 True True True False 0 True Pause / resume True GTK_RELIEF_NORMAL True False False True gtk-media-pause 4 0.5 0.5 0 0 0 True True True Stop playing True GTK_RELIEF_NORMAL True True gtk-media-stop 4 0.5 0.5 0 0 0 True True True Start playing True GTK_RELIEF_NORMAL True True gtk-media-play 4 0.5 0.5 0 0 0 True True True Previous track True GTK_RELIEF_NORMAL True True gtk-media-rewind 4 0.5 0.5 0 0 0 True True True Next track True GTK_RELIEF_NORMAL True True gtk-media-forward 4 0.5 0.5 0 0 0 True True True Eject CD True GTK_RELIEF_NORMAL True True gtk-cdrom 4 0.5 0.5 0 0 0 True True True Quit CD player True GTK_RELIEF_NORMAL True True gtk-quit 4 0.5 0.5 0 0 0 True True 0 True True 0 True True True True False GTK_POS_TOP 1 GTK_UPDATE_CONTINUOUS True 50 0 100 1 0 0 0 False True ' [/text]) # Initialize GTK and load XML string which is surrounded with a ' (important!) (gtk_init) (set 'xml (glade_xml_new_from_buffer Cdplayer (length Cdplayer) "NULL" "NULL")) # Get widgets and connect signals (set 'main_window (glade_xml_get_widget xml "main_window")) (gtk_server_connect main_window "delete_event main_quit") (gtk_server_connect main_window "show main_window") (set 'button_pause (glade_xml_get_widget xml "button_pause")) (gtk_server_connect button_pause "clicked button_pause") (set 'button_stop (glade_xml_get_widget xml "button_stop")) (gtk_server_connect button_stop "clicked button_stop") (set 'button_play (glade_xml_get_widget xml "button_play")) (gtk_server_connect button_play "clicked button_play") (set 'button_prev (glade_xml_get_widget xml "button_prev")) (gtk_server_connect button_prev "clicked button_prev") (set 'button_next (glade_xml_get_widget xml "button_next")) (gtk_server_connect button_next "clicked button_next") (set 'button_quit (glade_xml_get_widget xml "button_quit")) (gtk_server_connect button_quit "clicked button_quit") (set 'button_eject (glade_xml_get_widget xml "button_eject")) (gtk_server_connect button_eject "clicked button_eject") (set 'label_display (glade_xml_get_widget xml "label_display")) (set 'label_time (glade_xml_get_widget xml "label_time")) (set 'volume (glade_xml_get_widget xml "volume")) (gtk_server_connect volume "value-changed volume") (gtk_range_set_value volume 80) # Combobox with titles of CD (set 'vbox (glade_xml_get_widget xml "vbox")) (set 'combo_tracks (gtk_combo_box_new_text)) (gtk_box_pack_end vbox combo_tracks 1 1 1) (gtk_widget_show combo_tracks) # Return every second from GTK main iteration - make sure to connect this signal earlier (gtk_server_timeout 1000 main_window "show") (define (label_text_display txt) (gtk_label_set_markup_with_mnemonic label_display txt) ) (define (label_text_time txt) (gtk_label_set_markup_with_mnemonic label_time txt) ) #--------------------------------------------------------------------------------------------- (context 'CD) # Get IOCTL call (import "libc.so.6" "ioctl") # Get some constants from '/usr/include/linux/cdrom.h' (constant 'CDROMPAUSE 0x5301) (constant 'CDROMRESUME 0x5302) (constant 'CDROMPLAYTRKIND 0x5304) (constant 'CDROMREADTOCHDR 0x5305) (constant 'CDROMREADTOCENTRY 0x5306) (constant 'CDROMSTOP 0x5307) (constant 'CDROMSTART 0x5308) (constant 'CDROMEJECT 0x5309) (constant 'CDROMCLOSETRAY 0x5319) (constant 'CDROM_DRIVE_STATUS 0x5326) (constant 'CDROMSUBCHNL 0x530b) (constant 'CDS_NO_INFO 0) (constant 'CDS_NO_DISC 1) (constant 'CDS_TRAY_OPEN 2) (constant 'CDS_DRIVE_NOT_READY 3) (constant 'CDS_DISC_OK 4) (constant 'CDROM_MSF 0x02) (constant 'CDROM_AUDIO_PLAY 0x11) (constant 'CDROM_AUDIO_PAUSED 0x12) # Find OS mixer (set 'mixer (exec "which rexima 2>/dev/null")) (if (= mixer '()) (set 'mixer (exec "which aumix 2>/dev/null"))) # Find CDDA2WAV for CD recognition (set 'cdda2wav (exec "which cdda2wav 2>/dev/null")) (set 'CD_title "newLisp CD Player 1.4") (set 'Position 0) (set 'Text "\"Status: STOPPED\"") (set 'Device "/dev/cdrom") (set 'Start_Time nil) (set 'Cur_Track nil) (define (find_tracks, tochdr) (set 'tochdr (pack "bb" 0 0)) (ioctl cdrom CDROMREADTOCHDR tochdr) (unpack "bb" tochdr) ) (define (current_track, subchnl) (set 'subchnl (pack "bbbbbb ld ld" CDROM_MSF 0 0 0 0 0 0 0)) (ioctl cdrom CDROMSUBCHNL subchnl) (nth 3 (unpack "bbbbbb ld ld" subchnl)) ) (define (cd_status, subchnl) (set 'subchnl (pack "bbbbbb ld ld" CDROM_MSF 0 0 0 0 0 0 0)) (ioctl cdrom CDROMSUBCHNL subchnl) (nth 1 (unpack "bbbbbb ld ld" subchnl)) ) (define (play_track, ti tracks no x y) (set 'cdrom (open Device "read")) (set 'Track_Range (find_tracks)) (set 'Status true) (set 'ti (pack "bbbb" (first Track_Range) 0 (last Track_Range) 0)) (ioctl cdrom CDROMPLAYTRKIND ti) (set 'Text "\"Status: PLAYING\"") (gtk_toggle_button_set_active GUI:button_pause 0) (if (!= cdda2wav '()) (begin (set 'tracks (exec (append (first cdda2wav) " -D " Device " -J -v toc -L 1 -N -H -g 2>&1"))) (dolist (x tracks) (if (= x "") (begin (set 'x " ") (set 'Text "\"Status: UNKOWN CD - PLAYING\"") ) ) (if (regex "Album" (first (parse x " "))) (begin (replace "\\'" x "`") (replace "\"" x "`") (set 'y (g_locale_to_utf8 (append {"} (slice x (+ (find "'" x) 1)) {"}) -1 "NULL NULL NULL")) (set 'CD_title (slice y 0 (find "'" y)) ) (set 'y (slice y (+ (find "from" y) 6))) (set 'CD_title (append CD_title " by " (slice y 0 (find "'" y)))) ) ) (if (regex "T[0-9]+:" (first (parse x " "))) (begin (set 'no (slice (first (parse x " ")) 1)) (replace "\\'" x "`") (replace "\"" x "`") (set 'y (g_locale_to_utf8 (append {"} (slice x (+ (find "'" x) 1)) {"}) -1 "NULL NULL NULL")) (if (> (length y) 0) (gtk_combo_box_append_text GUI:combo_tracks (append {"} no " " (slice y 0 (find "'" y)) " - " ((parse x " +" 0) 2) {"}))) ) ) ) (gtk_combo_box_set_active GUI:combo_tracks 0) ) ) (if (= (first Track_Range) 0) (begin (set 'Text "\"Status: STOPPED\"") (set 'Status nil) ) ) (set 'Start_Time (date-value)) (if cdrom (close cdrom)) ) (define (stop_playing, x) (set 'cdrom (open Device "read" "n")) (ioctl cdrom CDROMSTOP) (set 'Text "\"Status: STOPPED\"") (if Status (for (x (first Track_Range) (last Track_Range)) (gtk_combo_box_remove_text GUI:combo_tracks 0) ) ) (set 'Track_Range nil) (set 'Status nil) (set 'CD_title "newLisp CD Player") (set 'Start_Time nil) (set 'Cur_Track nil) (gtk_toggle_button_set_active GUI:button_pause 0) (if cdrom (close cdrom)) ) (define (prev_track, ti current) (set 'cdrom (open Device "read")) (set 'current (current_track)) (if (and Status (> current 1)) (begin (set 'ti (pack "bbbb" (- current 1) 0 (last (find_tracks)) 0)) (ioctl cdrom CDROMPLAYTRKIND ti) ) ) (gtk_toggle_button_set_active GUI:button_pause 0) (if cdrom (close cdrom)) ) (define (next_track, ti current) (set 'cdrom (open Device "read")) (set 'current (current_track)) (if (and Status (!= (last Track_Range) -1) (< current (last Track_Range)) ) (begin (set 'ti (pack "bbbb" (+ current 1) 0 (last (find_tracks)) 0)) (ioctl cdrom CDROMPLAYTRKIND ti) ) ) (gtk_toggle_button_set_active GUI:button_pause 0) (if cdrom (close cdrom)) ) (define (cd_pause) (set 'cdrom (open Device "read")) (if (= (cd_status) CDROM_AUDIO_PLAY) (begin (ioctl cdrom CDROMPAUSE) (set 'Text "\"Status: PAUSED\"") (set 'Pause_Time (date-value)) ) (if (= (cd_status) CDROM_AUDIO_PAUSED) (begin (ioctl cdrom CDROMRESUME) (set 'Text "\"Status: PLAYING\"") (set 'Start_Time (+ Start_Time (- (date-value) Pause_Time))) ) ) ) (if cdrom (close cdrom)) ) (define (adjust_volume, vol) (set 'vol (gtk_range_get_value GUI:volume)) (if (= mixer (exec "which rexima 2>/dev/null")) (exec (append (first mixer) " cd " (string (int vol)) ))) (if (= mixer (exec "which aumix 2>/dev/null")) (exec (append (first mixer) " -c " vol))) ) (define (update_gui, ct) (if Status (set 'cdrom (open Device "read"))) (set 'ct (current_track)) (if (= (cd_status) CDROM_AUDIO_PLAY) (gtk_combo_box_set_active GUI:combo_tracks (- ct 1)) ) (GUI:label_text_display Text) # Show elapsed time (if Start_Time (if (= (cd_status) CDROM_AUDIO_PLAY) (GUI:label_text_time (append "\"Time: " (date (- (date-value) Start_Time) -60 "%H:%M:%S") "\""))) (GUI:label_text_time "\"Time: 00:00:00\"") ) # Reset tracktime if needed (if (and (= (cd_status) CDROM_AUDIO_PLAY)(!= Cur_Track ct)) (begin (set 'Cur_Track ct) (set 'Start_Time (date-value)) ) ) (gtk_window_set_title GUI:main_window (append {"} (slice CD_title (integer Position)) " - " CD_title " - " CD_title {"})) (inc 'Position 2) (if (> Position (length CD_title)) (set 'Position 0)) (if cdrom (close cdrom)) ) (define (change_track, ti current) (set 'cdrom (open Device "read")) (set 'current (+ (int (gtk_combo_box_get_active GUI:combo_tracks)) 1)) (if (!= current (current_track)) (begin (set 'ti (pack "bbbb" current 0 (last Track_Range) 0)) (ioctl cdrom CDROMPLAYTRKIND ti) ) ) (if cdrom (close cdrom)) ) (define (cd_eject) (stop_playing) (set 'cdrom (open Device "read" "n")) (if (= (int (ioctl cdrom CDROM_DRIVE_STATUS)) CDS_TRAY_OPEN) (ioctl cdrom CDROMCLOSETRAY) (ioctl cdrom CDROMEJECT) ) (if cdrom (close cdrom)) ) #--------------------------------------------------------------------------------------------- (context 'MAIN) (if (= (length (main-args)) 3) (set 'CD:Device (last (main-args)))) # Mainloop (until (or (= event "button_quit") (= event "main_quit")) (set 'event (gtk_server_callback "wait")) (case event ("button_play" (CD:play_track)) ("button_stop" (CD:stop_playing)) ("button_prev" (CD:prev_track)) ("button_next" (CD:next_track)) ("button_pause" (CD:cd_pause)) ("button_eject" (CD:cd_eject)) ("volume" (CD:adjust_volume)) ("main_window" (CD:update_gui)) ) (if (= event GUI:combo_tracks) (CD:change_track)) ) (CD:stop_playing) (gtk_exit) (exit)