comparison src/sid/xmms-sid.c @ 1574:e566e18e9e3d

Huge cleanup and some bugfixes. Temporarily breaks / removes sub-tune changing.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 03 Sep 2007 06:28:17 +0300
parents 5e4393a4c099
children a5725f7f1a5e
comparison
equal deleted inserted replaced
1573:82548d92c922 1574:e566e18e9e3d
36 #include "xs_filter.h" 36 #include "xs_filter.h"
37 #include "xs_fileinfo.h" 37 #include "xs_fileinfo.h"
38 #include "xs_interface.h" 38 #include "xs_interface.h"
39 #include "xs_glade.h" 39 #include "xs_glade.h"
40 #include "xs_player.h" 40 #include "xs_player.h"
41 #include "xs_slsup.h"
42
41 43
42 /* 44 /*
43 * Include player engines 45 * Include player engines
44 */ 46 */
45 #ifdef HAVE_SIDPLAY1 47 #ifdef HAVE_SIDPLAY1
84 */ 86 */
85 t_xs_status xs_status; 87 t_xs_status xs_status;
86 XS_MUTEX(xs_status); 88 XS_MUTEX(xs_status);
87 static XS_THREAD_T xs_decode_thread; 89 static XS_THREAD_T xs_decode_thread;
88 90
89 static GtkWidget *xs_subctrl = NULL;
90 static GtkObject *xs_subctrl_adj = NULL;
91 XS_MUTEX(xs_subctrl);
92
93 void xs_subctrl_close(void);
94 void xs_subctrl_update(void);
95
96 static t_xs_sldb *xs_sldb_db = NULL;
97 XS_MUTEX(xs_sldb_db);
98
99 gint xs_songlen_init(void);
100 void xs_songlen_close(void);
101 t_xs_sldb_node *xs_songlen_get(const gchar *);
102
103 91
104 /* 92 /*
105 * Error messages 93 * Error messages
106 */ 94 */
107 void xs_error(const char *fmt, ...) 95 void xs_error(const char *fmt, ...)
108 { 96 {
109 va_list ap; 97 va_list ap;
110 fprintf(stderr, "XMMS-SID: "); 98 fprintf(stderr, "AUD-SID: ");
111 va_start(ap, fmt); 99 va_start(ap, fmt);
112 vfprintf(stderr, fmt, ap); 100 vfprintf(stderr, fmt, ap);
113 va_end(ap); 101 va_end(ap);
114 } 102 }
115 103
292 /* Check the filename */ 280 /* Check the filename */
293 if (pcFilename == NULL) 281 if (pcFilename == NULL)
294 return FALSE; 282 return FALSE;
295 283
296 return xs_status.sidPlayer->plrProbe(f); 284 return xs_status.sidPlayer->plrProbe(f);
297 }
298
299
300 static gboolean xs_schedule_subctrl_update(gpointer unused)
301 {
302 (void) unused;
303 gboolean isPlaying;
304
305 XS_MUTEX_LOCK(xs_status);
306 isPlaying = xs_status.isPlaying;
307 XS_MUTEX_UNLOCK(xs_status);
308
309 if (isPlaying)
310 xs_subctrl_update();
311
312 return FALSE;
313 } 285 }
314 286
315 287
316 /* 288 /*
317 * Main playing thread loop 289 * Main playing thread loop
409 XS_MUTEX_UNLOCK(xs_status); 381 XS_MUTEX_UNLOCK(xs_status);
410 XS_MUTEX_UNLOCK(xs_cfg); 382 XS_MUTEX_UNLOCK(xs_cfg);
411 383
412 XSDEBUG("subtune #%i selected, initializing...\n", myStatus.currSong); 384 XSDEBUG("subtune #%i selected, initializing...\n", myStatus.currSong);
413 385
414 g_idle_add_full( G_PRIORITY_HIGH_IDLE , xs_schedule_subctrl_update , NULL , NULL );
415
416 /* Check minimum playtime */ 386 /* Check minimum playtime */
417 songLength = myTune->subTunes[myStatus.currSong-1].tuneLength; 387 songLength = myTune->subTunes[myStatus.currSong-1].tuneLength;
418 if (xs_cfg.playMinTimeEnable && (songLength >= 0)) { 388 if (xs_cfg.playMinTimeEnable && (songLength >= 0)) {
419 if (songLength < xs_cfg.playMinTime) 389 if (songLength < xs_cfg.playMinTime)
420 songLength = xs_cfg.playMinTime; 390 songLength = xs_cfg.playMinTime;
616 { 586 {
617 (void) pb; 587 (void) pb;
618 588
619 XSDEBUG("stop requested\n"); 589 XSDEBUG("stop requested\n");
620 590
621 /* Close the sub-tune control window, if any */
622 xs_subctrl_close();
623
624 /* Lock xs_status and stop playing thread */ 591 /* Lock xs_status and stop playing thread */
625 XS_MUTEX_LOCK(xs_status); 592 XS_MUTEX_LOCK(xs_status);
626 if (xs_status.isPlaying) { 593 if (xs_status.isPlaying) {
627 XSDEBUG("stopping...\n"); 594 XSDEBUG("stopping...\n");
628 xs_status.isPlaying = FALSE; 595 xs_status.isPlaying = FALSE;
632 XS_MUTEX_UNLOCK(xs_status); 599 XS_MUTEX_UNLOCK(xs_status);
633 } 600 }
634 601
635 XSDEBUG("done, updating status\n"); 602 XSDEBUG("done, updating status\n");
636 603
637 /* Status is now stopped, update the sub-tune
638 * controller in fileinfo window (if open)
639 */
640 xs_fileinfo_update();
641
642 /* Free tune information */ 604 /* Free tune information */
643 XS_MUTEX_LOCK(xs_status); 605 XS_MUTEX_LOCK(xs_status);
644 xs_status.sidPlayer->plrDeleteSID(&xs_status); 606 xs_status.sidPlayer->plrDeleteSID(&xs_status);
645 xs_tuneinfo_free(xs_status.tuneInfo); 607 xs_tuneinfo_free(xs_status.tuneInfo);
646 xs_status.tuneInfo = NULL; 608 xs_status.tuneInfo = NULL;
652 /* 614 /*
653 * Pause/unpause the playing 615 * Pause/unpause the playing
654 */ 616 */
655 void xs_pause(InputPlayback *pb, short pauseState) 617 void xs_pause(InputPlayback *pb, short pauseState)
656 { 618 {
657 xs_subctrl_close();
658 xs_fileinfo_update();
659 pb->output->pause(pauseState); 619 pb->output->pause(pauseState);
660 } 620 }
661 621
662 622
663 /* 623 /*
664 * Pop-up subtune selector 624 * A stub seek function (Audacious will crash if seek is NULL)
665 */
666 void xs_subctrl_setsong(void)
667 {
668 gint n;
669
670 XS_MUTEX_LOCK(xs_status);
671 XS_MUTEX_LOCK(xs_subctrl);
672
673 if (xs_status.tuneInfo && xs_status.isPlaying) {
674 n = (gint) GTK_ADJUSTMENT(xs_subctrl_adj)->value;
675 if ((n >= 1) && (n <= xs_status.tuneInfo->nsubTunes))
676 xs_status.currSong = n;
677 }
678
679 XS_MUTEX_UNLOCK(xs_subctrl);
680 XS_MUTEX_UNLOCK(xs_status);
681 }
682
683
684 void xs_subctrl_prevsong(void)
685 {
686 XS_MUTEX_LOCK(xs_status);
687
688 if (xs_status.tuneInfo && xs_status.isPlaying) {
689 if (xs_status.currSong > 1)
690 xs_status.currSong--;
691 }
692
693 XS_MUTEX_UNLOCK(xs_status);
694
695 xs_subctrl_update();
696 }
697
698
699 void xs_subctrl_nextsong(void)
700 {
701 XS_MUTEX_LOCK(xs_status);
702
703 if (xs_status.tuneInfo && xs_status.isPlaying) {
704 if (xs_status.currSong < xs_status.tuneInfo->nsubTunes)
705 xs_status.currSong++;
706 }
707
708 XS_MUTEX_UNLOCK(xs_status);
709
710 xs_subctrl_update();
711 }
712
713
714 void xs_subctrl_update(void)
715 {
716 GtkAdjustment *tmpAdj;
717
718 XS_MUTEX_LOCK(xs_status);
719 XS_MUTEX_LOCK(xs_subctrl);
720
721 /* Check if control window exists, we are currently playing and have a tune */
722 if (xs_subctrl) {
723 if (xs_status.tuneInfo && xs_status.isPlaying) {
724 tmpAdj = GTK_ADJUSTMENT(xs_subctrl_adj);
725
726 tmpAdj->value = xs_status.currSong;
727 tmpAdj->lower = 1;
728 tmpAdj->upper = xs_status.tuneInfo->nsubTunes;
729 XS_MUTEX_UNLOCK(xs_status);
730 XS_MUTEX_UNLOCK(xs_subctrl);
731 gtk_adjustment_value_changed(tmpAdj);
732 } else {
733 XS_MUTEX_UNLOCK(xs_status);
734 XS_MUTEX_UNLOCK(xs_subctrl);
735 xs_subctrl_close();
736 }
737 } else {
738 XS_MUTEX_UNLOCK(xs_subctrl);
739 XS_MUTEX_UNLOCK(xs_status);
740 }
741
742 xs_fileinfo_update();
743 }
744
745
746 void xs_subctrl_close(void)
747 {
748 XS_MUTEX_LOCK(xs_subctrl);
749
750 if (xs_subctrl) {
751 gtk_widget_destroy(xs_subctrl);
752 xs_subctrl = NULL;
753 }
754
755 XS_MUTEX_UNLOCK(xs_subctrl);
756 }
757
758
759 gboolean xs_subctrl_keypress(GtkWidget * win, GdkEventKey * ev)
760 {
761 (void) win;
762
763 if (ev->keyval == GDK_Escape)
764 xs_subctrl_close();
765
766 return FALSE;
767 }
768
769
770 void xs_subctrl_open(void)
771 {
772 GtkWidget *frame25, *hbox15, *subctrl_prev, *subctrl_current, *subctrl_next;
773
774 XS_MUTEX_LOCK(xs_subctrl);
775 if (!xs_status.tuneInfo || !xs_status.isPlaying ||
776 xs_subctrl || (xs_status.tuneInfo->nsubTunes <= 1)) {
777 XS_MUTEX_UNLOCK(xs_subctrl);
778 return;
779 }
780
781 /* Create the pop-up window */
782 xs_subctrl = gtk_window_new (GTK_WINDOW_TOPLEVEL);
783 gtk_window_set_type_hint(GTK_WINDOW(xs_subctrl), GDK_WINDOW_TYPE_HINT_DIALOG);
784 gtk_widget_set_name(xs_subctrl, "xs_subctrl");
785 g_object_set_data(G_OBJECT(xs_subctrl), "xs_subctrl", xs_subctrl);
786
787 gtk_window_set_title(GTK_WINDOW(xs_subctrl), _("Subtune Control"));
788 gtk_window_set_position(GTK_WINDOW(xs_subctrl), GTK_WIN_POS_MOUSE);
789 gtk_container_set_border_width(GTK_CONTAINER(xs_subctrl), 0);
790 gtk_window_set_policy(GTK_WINDOW(xs_subctrl), FALSE, FALSE, FALSE);
791
792 g_signal_connect(G_OBJECT(xs_subctrl), "destroy", G_CALLBACK(gtk_widget_destroyed), &xs_subctrl);
793
794 g_signal_connect(G_OBJECT(xs_subctrl), "focus_out_event", G_CALLBACK(xs_subctrl_close), NULL);
795
796 gtk_widget_realize(xs_subctrl);
797 gdk_window_set_decorations(xs_subctrl->window, (GdkWMDecoration) 0);
798
799
800 /* Create the control widgets */
801 frame25 = gtk_frame_new(NULL);
802 gtk_container_add(GTK_CONTAINER(xs_subctrl), frame25);
803 gtk_container_set_border_width(GTK_CONTAINER(frame25), 2);
804 gtk_frame_set_shadow_type(GTK_FRAME(frame25), GTK_SHADOW_OUT);
805
806 hbox15 = gtk_hbox_new(FALSE, 4);
807 gtk_container_add(GTK_CONTAINER(frame25), hbox15);
808
809 subctrl_prev = gtk_button_new_with_label(" < ");
810 gtk_widget_set_name(subctrl_prev, "subctrl_prev");
811 gtk_box_pack_start(GTK_BOX(hbox15), subctrl_prev, FALSE, FALSE, 0);
812
813 xs_subctrl_adj = gtk_adjustment_new(xs_status.currSong, 1, xs_status.tuneInfo->nsubTunes, 1, 1, 0);
814 g_signal_connect(G_OBJECT(xs_subctrl_adj), "value_changed", G_CALLBACK(xs_subctrl_setsong), NULL);
815
816 subctrl_current = gtk_hscale_new(GTK_ADJUSTMENT(xs_subctrl_adj));
817 gtk_widget_set_size_request(subctrl_current, 80, -1);
818 gtk_widget_set_name(subctrl_current, "subctrl_current");
819 gtk_box_pack_start(GTK_BOX(hbox15), subctrl_current, FALSE, TRUE, 0);
820 gtk_scale_set_digits(GTK_SCALE(subctrl_current), 0);
821 gtk_range_set_update_policy(GTK_RANGE(subctrl_current), GTK_UPDATE_DELAYED);
822 gtk_widget_grab_focus(subctrl_current);
823
824 subctrl_next = gtk_button_new_with_label(" > ");
825 gtk_widget_set_name(subctrl_next, "subctrl_next");
826 gtk_box_pack_start(GTK_BOX(hbox15), subctrl_next, FALSE, FALSE, 0);
827
828 g_signal_connect(G_OBJECT(subctrl_prev), "clicked", G_CALLBACK(xs_subctrl_prevsong), NULL);
829
830 g_signal_connect(G_OBJECT(subctrl_next), "clicked", G_CALLBACK(xs_subctrl_nextsong), NULL);
831
832 g_signal_connect(G_OBJECT(xs_subctrl), "key_press_event", G_CALLBACK(xs_subctrl_keypress), NULL);
833
834 gtk_widget_show_all(xs_subctrl);
835
836 XS_MUTEX_UNLOCK(xs_subctrl);
837 }
838
839
840 /*
841 * Set the time-seek position
842 * The playing thread will do the "seeking", which means sub-tune
843 * changing in XMMS-SID's case. iTime argument is time in seconds,
844 * in contrast to milliseconds used in other occasions.
845 *
846 * This function is called whenever position slider is clicked or
847 * other method of seeking is used (keyboard, etc.)
848 */ 625 */
849 void xs_seek(InputPlayback *pb, gint iTime) 626 void xs_seek(InputPlayback *pb, gint iTime)
850 { 627 {
851 /* Check status */
852 XS_MUTEX_LOCK(xs_status);
853 if (!xs_status.tuneInfo || !xs_status.isPlaying) {
854 XS_MUTEX_UNLOCK(xs_status);
855 return;
856 }
857
858 /* Act according to settings */
859 switch (xs_cfg.subsongControl) {
860 case XS_SSC_SEEK:
861 if (iTime < xs_status.lastTime) {
862 if (xs_status.currSong > 1)
863 xs_status.currSong--;
864 } else if (iTime > xs_status.lastTime) {
865 if (xs_status.currSong < xs_status.tuneInfo->nsubTunes)
866 xs_status.currSong++;
867 }
868 break;
869
870 case XS_SSC_POPUP:
871 xs_subctrl_open();
872 break;
873
874 /* If we have song-position patch, check settings */
875 #ifdef HAVE_SONG_POSITION
876 case XS_SSC_PATCH:
877 if ((iTime > 0) && (iTime <= xs_status.tuneInfo->nsubTunes))
878 xs_status.currSong = iTime;
879 break;
880 #endif
881 }
882
883 XS_MUTEX_UNLOCK(xs_status);
884 } 628 }
885 629
886 630
887 /* 631 /*
888 * Return the playing "position/time" 632 * Return the playing "position/time"
910 if (!xs_status.isPlaying) { 654 if (!xs_status.isPlaying) {
911 XS_MUTEX_UNLOCK(xs_status); 655 XS_MUTEX_UNLOCK(xs_status);
912 return -1; 656 return -1;
913 } 657 }
914 658
915 /* Let's see what we do */
916 switch (xs_cfg.subsongControl) {
917 case XS_SSC_SEEK:
918 xs_status.lastTime = (pb->output->output_time() / 1000);
919 break;
920
921 #ifdef HAVE_SONG_POSITION
922 case XS_SSC_PATCH:
923 set_song_position(xs_status.currSong, 1, xs_status.tuneInfo->nsubTunes);
924 break;
925 #endif
926 }
927
928 XS_MUTEX_UNLOCK(xs_status); 659 XS_MUTEX_UNLOCK(xs_status);
929 660
930 /* Return output time reported by audio output plugin */ 661 /* Return output time reported by audio output plugin */
931 return pb->output->output_time(); 662 return pb->output->output_time();
932 } 663 }
933 664
934 665
935 #ifndef AUDACIOUS_PLUGIN 666 /* Return song information Tuple
936 /* Return song information: called by XMMS when initially loading the playlist. 667 */
937 * Subsequent changes to information are made by the player thread,
938 * which uses xs_plugin_ip.set_info();
939 */
940 void xs_get_song_info(gchar * songFilename, gchar ** songTitle, gint * songLength)
941 {
942 t_xs_tuneinfo *pInfo;
943
944 XS_MUTEX_LOCK(xs_status);
945
946 /* Get tune information from emulation engine */
947 pInfo = xs_status.sidPlayer->plrGetSIDInfo(songFilename);
948 if (!pInfo) {
949 XS_MUTEX_UNLOCK(xs_status);
950 return;
951 }
952
953 /* Get sub-tune information, if available */
954 if ((pInfo->startTune > 0) && (pInfo->startTune <= pInfo->nsubTunes)) {
955 gint tmpInt;
956
957 (*songTitle) = xs_make_titlestring(pInfo, pInfo->startTune);
958
959 tmpInt = pInfo->subTunes[pInfo->startTune-1].tuneLength;
960 if (tmpInt < 0)
961 (*songLength) = -1;
962 else
963 (*songLength) = (tmpInt * 1000);
964 }
965
966 /* Free tune information */
967 xs_tuneinfo_free(pInfo);
968 XS_MUTEX_UNLOCK(xs_status);
969 }
970
971 #else
972
973 Tuple * xs_get_song_tuple(gchar *songFilename) 668 Tuple * xs_get_song_tuple(gchar *songFilename)
974 { 669 {
975 t_xs_tuneinfo *pInfo; 670 t_xs_tuneinfo *pInfo;
976 Tuple *pResult; 671 Tuple *pResult;
977 gchar *tmpStr; 672 gchar *tmpStr;
1005 700
1006 /* Get sub-tune information, if available */ 701 /* Get sub-tune information, if available */
1007 if ((pInfo->startTune > 0) && (pInfo->startTune <= pInfo->nsubTunes)) { 702 if ((pInfo->startTune > 0) && (pInfo->startTune <= pInfo->nsubTunes)) {
1008 gint tmpInt = pInfo->subTunes[pInfo->startTune-1].tuneLength; 703 gint tmpInt = pInfo->subTunes[pInfo->startTune-1].tuneLength;
1009 tuple_associate_int(pResult, "length", (tmpInt < 0) ? -1 : tmpInt * 1000); 704 tuple_associate_int(pResult, "length", (tmpInt < 0) ? -1 : tmpInt * 1000);
1010
1011 } 705 }
1012 706
1013 /* Free tune information */ 707 /* Free tune information */
1014 xs_tuneinfo_free(pInfo); 708 xs_tuneinfo_free(pInfo);
1015 XS_MUTEX_UNLOCK(xs_status); 709 XS_MUTEX_UNLOCK(xs_status);
1016 return pResult; 710 return pResult;
1017 } 711 }
1018 #endif
1019
1020
1021 /* Allocate a new tune information structure
1022 */
1023 t_xs_tuneinfo *xs_tuneinfo_new(const gchar * pcFilename,
1024 gint nsubTunes, gint startTune, const gchar * sidName,
1025 const gchar * sidComposer, const gchar * sidCopyright,
1026 gint loadAddr, gint initAddr, gint playAddr,
1027 gint dataFileLen, const gchar *sidFormat, gint sidModel)
1028 {
1029 t_xs_tuneinfo *pResult;
1030 t_xs_sldb_node *tmpLength;
1031 gint i;
1032
1033 /* Allocate structure */
1034 pResult = (t_xs_tuneinfo *) g_malloc0(sizeof(t_xs_tuneinfo));
1035 if (!pResult) {
1036 xs_error(_("Could not allocate memory for t_xs_tuneinfo ('%s')\n"),
1037 pcFilename);
1038 return NULL;
1039 }
1040
1041 pResult->sidFilename = g_filename_to_utf8(pcFilename, -1, NULL, NULL, NULL);
1042 if (!pResult->sidFilename) {
1043 xs_error(_("Could not allocate sidFilename ('%s')\n"),
1044 pcFilename);
1045 g_free(pResult);
1046 return NULL;
1047 }
1048
1049 /* Allocate space for subtune information */
1050 pResult->subTunes = g_malloc0(sizeof(t_xs_subtuneinfo) * (nsubTunes + 1));
1051 if (!pResult->subTunes) {
1052 xs_error(_("Could not allocate memory for t_xs_subtuneinfo ('%s', %i)\n"),
1053 pcFilename, nsubTunes);
1054
1055 g_free(pResult->sidFilename);
1056 g_free(pResult);
1057 return NULL;
1058 }
1059
1060 /* The following allocations don't matter if they fail */
1061 pResult->sidName = XS_CS_SID(sidName);
1062 pResult->sidComposer = XS_CS_SID(sidComposer);
1063 pResult->sidCopyright = XS_CS_SID(sidCopyright);
1064
1065 pResult->nsubTunes = nsubTunes;
1066 pResult->startTune = startTune;
1067
1068 pResult->loadAddr = loadAddr;
1069 pResult->initAddr = initAddr;
1070 pResult->playAddr = playAddr;
1071 pResult->dataFileLen = dataFileLen;
1072 pResult->sidFormat = XS_CS_SID(sidFormat);
1073
1074 pResult->sidModel = sidModel;
1075
1076 /* Get length information (NOTE: Do not free this!) */
1077 tmpLength = xs_songlen_get(pcFilename);
1078
1079 /* Fill in sub-tune information */
1080 for (i = 0; i < pResult->nsubTunes; i++) {
1081 if (tmpLength && (i < tmpLength->nLengths))
1082 pResult->subTunes[i].tuneLength = tmpLength->sLengths[i];
1083 else
1084 pResult->subTunes[i].tuneLength = -1;
1085
1086 pResult->subTunes[i].tuneSpeed = -1;
1087 }
1088
1089 return pResult;
1090 }
1091
1092
1093 /* Free given tune information structure
1094 */
1095 void xs_tuneinfo_free(t_xs_tuneinfo * pTune)
1096 {
1097 if (!pTune) return;
1098
1099 g_free(pTune->subTunes);
1100 g_free(pTune->sidFilename);
1101 g_free(pTune->sidName);
1102 g_free(pTune->sidComposer);
1103 g_free(pTune->sidCopyright);
1104 g_free(pTune->sidFormat);
1105 g_free(pTune);
1106 }
1107
1108
1109 /* Song length database handling glue
1110 */
1111 gint xs_songlen_init(void)
1112 {
1113 XS_MUTEX_LOCK(xs_cfg);
1114
1115 if (!xs_cfg.songlenDBPath) {
1116 XS_MUTEX_UNLOCK(xs_cfg);
1117 return -1;
1118 }
1119
1120 XS_MUTEX_LOCK(xs_sldb_db);
1121
1122 /* Check if already initialized */
1123 if (xs_sldb_db)
1124 xs_sldb_free(xs_sldb_db);
1125
1126 /* Allocate database */
1127 xs_sldb_db = (t_xs_sldb *) g_malloc0(sizeof(t_xs_sldb));
1128 if (!xs_sldb_db) {
1129 XS_MUTEX_UNLOCK(xs_cfg);
1130 XS_MUTEX_UNLOCK(xs_sldb_db);
1131 return -2;
1132 }
1133
1134 /* Read the database */
1135 if (xs_sldb_read(xs_sldb_db, xs_cfg.songlenDBPath) != 0) {
1136 xs_sldb_free(xs_sldb_db);
1137 xs_sldb_db = NULL;
1138 XS_MUTEX_UNLOCK(xs_cfg);
1139 XS_MUTEX_UNLOCK(xs_sldb_db);
1140 return -3;
1141 }
1142
1143 /* Create index */
1144 if (xs_sldb_index(xs_sldb_db) != 0) {
1145 xs_sldb_free(xs_sldb_db);
1146 xs_sldb_db = NULL;
1147 XS_MUTEX_UNLOCK(xs_cfg);
1148 XS_MUTEX_UNLOCK(xs_sldb_db);
1149 return -4;
1150 }
1151
1152 XS_MUTEX_UNLOCK(xs_cfg);
1153 XS_MUTEX_UNLOCK(xs_sldb_db);
1154 return 0;
1155 }
1156
1157
1158 void xs_songlen_close(void)
1159 {
1160 XS_MUTEX_LOCK(xs_sldb_db);
1161 xs_sldb_free(xs_sldb_db);
1162 xs_sldb_db = NULL;
1163 XS_MUTEX_UNLOCK(xs_sldb_db);
1164 }
1165
1166
1167 t_xs_sldb_node *xs_songlen_get(const gchar * pcFilename)
1168 {
1169 t_xs_sldb_node *pResult;
1170
1171 XS_MUTEX_LOCK(xs_sldb_db);
1172
1173 if (xs_cfg.songlenDBEnable && xs_sldb_db)
1174 pResult = xs_sldb_get(xs_sldb_db, pcFilename);
1175 else
1176 pResult = NULL;
1177
1178 XS_MUTEX_UNLOCK(xs_sldb_db);
1179
1180 return pResult;
1181 }