1 /* flac.c
2  * Copyright (C) 2004, 2005 Sylvain Cresto <scresto@gmail.com>
3  *
4  * This file is part of graveman!
5  *
6  * graveman! is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or
9  * (at your option) any later version.
10  *
11  * graveman! is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with program; see the file COPYING. If not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19  * MA 02111-1307, USA.
20  *
21  * URL: http://www.nongnu.org/graveman/
22  *
23  */
24 
25 #include "graveman.h"
26 
27 #ifdef ENABLE_FLAC
28 #include <FLAC/metadata.h>
29 
30 #define FLAC_ERROR_OPEN "An error occurred opening the input file"
31 #define FLAC_ERROR "ERROR"
32 
33 /* extraction de la duree d'un fichier flac */
getFlacInfo(gchar * Afilename,guint32 * Alength,GError ** Aerror)34 gboolean getFlacInfo(gchar *Afilename, guint32 *Alength, GError **Aerror)
35 {
36   FLAC__StreamMetadata *Lblock;
37   FLAC__Metadata_Chain *Lchain = FLAC__metadata_chain_new();
38   FLAC__Metadata_Iterator *Literator = FLAC__metadata_iterator_new();
39 
40   (*Alength)=0;
41 
42   if (! Lchain) {
43     g_set_error(Aerror, GRAVEMAN_ERROR, _ERR_OUTOFMEMORY, _("FLAC: out of memory !"));
44     return FALSE;
45   }
46 
47   if(!FLAC__metadata_chain_read(Lchain, Afilename)) {
48     g_set_error(Aerror, GRAVEMAN_ERROR, _ERR_INAPPROPRIATE_DATA, _("%s is not a valid .flac file !"), Afilename);
49     return FALSE;
50   }
51 
52   FLAC__metadata_iterator_init(Literator, Lchain);
53   Lblock = FLAC__metadata_iterator_get_block(Literator);
54 
55   if (Lblock->data.stream_info.sample_rate) {
56     (*Alength) = Lblock->data.stream_info.total_samples / Lblock->data.stream_info.sample_rate;
57   }
58 
59   FLAC__metadata_iterator_delete(Literator);
60   FLAC__metadata_chain_delete(Lchain);
61 
62   return TRUE;
63 }
64 
65 
66 /* transformation fichier son vers piste audio */
67 
68 /* pour le moment on ne fais pas grand chose dans le callback ...
69  * plus tard il y aura une meilleur gestion des erreurs ! */
flac_callback(GIOChannel * Astd,GIOCondition Acond,gpointer Adata)70 gboolean flac_callback(GIOChannel *Astd, GIOCondition Acond, gpointer Adata)
71 {
72   GIOStatus Lstatus;
73   Tgrave *Lg = (Tgrave *)Adata;
74   gchar *Lbuffer = NULL;
75   gchar *s;
76   gint *Lcont = (gint *) sc_grave_get_data(Lg, "cont"); /* on traite encore des donnees ? */
77   GError **Lerreur = (GError **) sc_grave_get_data(Lg, "gerror"); /* pointeur erreur */
78 
79 
80   /* fin du callback lorsque l'on recoi un signal comme quoi le pipe est ferme */
81   if (Acond == G_IO_HUP || Acond == G_IO_ERR) {
82     *Lcont = 1;
83     return FALSE;
84   }
85 
86   Lstatus = g_io_channel_read_line(Astd, &Lbuffer, NULL, NULL, NULL);
87   _DEB("%s\n", Lbuffer);
88   if (Lbuffer) {
89     if (!strncmp(Lbuffer, FLAC_ERROR_OPEN, strlen(FLAC_ERROR_OPEN))) {
90       g_set_error(Lerreur, GRAVEMAN_ERROR, _ERR_FLAC, _("An error occurred opening the input FLAC file, disk full ?"));
91       g_free(Lbuffer);
92       return FALSE;
93     } else if (strstr(Lbuffer, FLAC_ERROR)) {
94       g_set_error(Lerreur, GRAVEMAN_ERROR, _ERR_FLAC, s+strlen(FLAC_ERROR));
95       g_free(Lbuffer);
96       return FALSE;
97     }
98   }
99 
100   g_free(Lbuffer);
101 
102   return TRUE;
103 }
104 
FlacToWav(Tgrave * Ag,gchar * AFichier,gchar * AVers,GError ** Aerror)105 gboolean FlacToWav(Tgrave *Ag, gchar *AFichier, gchar *AVers, GError **Aerror)
106 {
107   gchar *Lcommandline;
108   gchar **Lcmd;
109   gint *Lpid = (gint *) sc_grave_get_data(Ag, "pid");
110   gboolean *Labort = (gboolean *)sc_grave_get_data(Ag, "gabort");
111   gint *Lcont = (gint *) sc_grave_get_data(Ag, "cont");
112   gint g_out, g_err, Lnbrarg;
113   gchar *Lfic;
114   gchar *Lvers;
115   GIOChannel *Lcom, *Lcomerr;
116   GIOStatus Lstatus;
117   gboolean Lbolstatus;
118   guint Lcomevent, Lcomerrevent;
119 
120   Lfic = sc_strescape(AFichier);
121   Lvers = sc_strescape(AVers);
122   Lcommandline = g_strdup_printf("%s %s -d \"%s\" -o \"%s\"", conf_get_string("flac"), conf_get_string("flacpara"), Lfic, Lvers);
123   g_free(Lvers); g_free(Lfic);
124   _DEB("execution [%s]\n", Lcommandline);
125 
126   Lstatus = g_shell_parse_argv(Lcommandline, &Lnbrarg, &Lcmd, Aerror);
127   g_free(Lcommandline);
128   if (Lstatus == FALSE) {
129     return FALSE;
130   }
131 
132   Lbolstatus = g_spawn_async_with_pipes(NULL, Lcmd, NULL, /* env argument */
133       (GSpawnFlags ) (G_SPAWN_DO_NOT_REAP_CHILD),
134       NULL, NULL, Lpid, NULL, &g_out, &g_err, Aerror);
135   g_strfreev(Lcmd);
136 
137   if (Lbolstatus == FALSE) {
138     g_warning("ERROR EXECUTION !\n");
139     return FALSE;
140   }
141   Lcom = g_io_channel_unix_new( g_out );
142   g_io_channel_set_encoding (Lcom, NULL, NULL);
143   g_io_channel_set_flags( Lcom, G_IO_FLAG_NONBLOCK, NULL );
144   Lcomevent = g_io_add_watch (Lcom, (G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI),
145 					     flac_callback,
146 					     Ag);
147 
148   Lcomerr = g_io_channel_unix_new( g_err );
149   g_io_channel_set_encoding (Lcomerr, NULL, NULL);
150   g_io_channel_set_flags( Lcomerr, G_IO_FLAG_NONBLOCK, NULL );
151   Lcomerrevent = g_io_add_watch (Lcomerr, (G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI),
152 					     flac_callback,
153 					     Ag);
154 
155   while (*Lcont > 1 && *Labort == FALSE) {
156     gtk_main_iteration();
157   }
158   exit_prog(*Lpid, *Labort, Aerror, NULL);
159 
160   g_source_remove(Lcomerrevent);
161   g_source_remove(Lcomevent);
162 
163   g_io_channel_shutdown(Lcomerr, FALSE, NULL);
164   g_io_channel_unref(Lcomerr);
165   g_io_channel_shutdown(Lcom, FALSE, NULL);
166   g_io_channel_unref(Lcom);
167   g_spawn_close_pid(*Lpid);
168   *Lpid = 0;
169 
170   /* l'utilisateur a annule l'operation */
171   if (*Labort==TRUE || *Aerror) return FALSE;
172 
173   return TRUE;
174 }
175 
176 #endif
177 
178 /*
179  * vim:et:ts=8:sts=2:sw=2
180  */
181