1 /*
2    gnauralXML.c
3    code for managing XML data-styled data in the Gnaural context
4    Depends on:
5    main.h
6    gnauralXML.h
7    gnauralnet.h
8 
9    Copyright (C) 20100608  Bret Logan
10 
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15 
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20 
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  */
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 
29 #include <string.h>     //needed for strcpy
30 #include "main.h"
31 #include "gnauralnet.h"
32 #include "ScheduleXML.h"
33 #include "gnauralXML.h"
34 #include "voiceGUI.h"
35 #include "gnauralRecentMenu.h"
36 
37 int gxml_ParserXML_VoiceCount = 0;      //this is a *true* count of Voices (as opposed to listed count in file) taken from  pre-reads of the XML file; has priority
38 int gxml_ParserXML_EntryCount = 0;      //this is a *true* count of Entries (as opposed to listed count in file) taken from  pre-reads of the XML file; has priority
39 int gxml_GnauralFile = 0;       //just a way to know internally if a file being opened isn't a valid Gnaurl2 file
40 
41 /////////////////////////////////////////////////////
42 //Writes a Gnaural format XML file
gxml_XMLWriteFile(char * filename)43 void gxml_XMLWriteFile (char *filename)
44 {
45  //First count how many DPs to copy. One reason to do this first is to be sure
46  //there really are selected DPs before throwing away the old buffer:
47  SG_DataPoint *curDP;
48  int DP_count = 0;
49  int voice_count = 0;
50  SG_Voice *curVoice = SG_FirstVoice;
51 
52  while (curVoice != NULL)
53  {
54   curDP = curVoice->FirstDataPoint;
55   ++voice_count;
56   while (curDP != NULL)
57   {
58    ++DP_count;
59    //all list loops need this:
60    curDP = curDP->NextDataPoint;
61   }
62   curVoice = curVoice->NextVoice;
63  }
64 
65  SG_DBGOUT_INT ("WriteFileXML: DataPoints to copy:", DP_count);
66  SG_DBGOUT_INT ("WriteFileXML: Total Voices:", voice_count);
67 
68  //if there are no selected DPs, don't do anything:
69  if (DP_count < 1)
70   return;
71 
72  //prepare file access:
73  FILE *stream;
74 
75  if ((stream = fopen (filename, "w")) == NULL)
76  {
77   SG_ERROUT ("Failed to open file for writing!");
78   return;
79  }
80 
81  gchar strbuf[G_ASCII_DTOSTR_BUF_SIZE];
82 
83  const int strsize = sizeof (strbuf);
84 
85  fprintf (stream, "<?xml version=\"1.0\"?>\n"); //added 20101010 to keep browswers from seeing datafiles as webpages
86  fprintf (stream, "<!-- See http://gnaural.sourceforge.net -->\n");
87  fprintf (stream, "<schedule>\n");
88  fprintf (stream, "<gnauralfile_version>%s</gnauralfile_version>\n", gxml_VERSION_GNAURAL_XMLFILE);     //always keep this first
89  fprintf (stream, "<gnaural_version>%s</gnaural_version>\n", VERSION);
90  time_t curtime;
91 
92  struct tm *loctime;
93 
94  curtime = time (NULL);
95  loctime = (struct tm *) localtime (&curtime);
96  fprintf (stream, "<date>%s</date>\n", asctime (loctime));
97  fprintf (stream, "<title>%s</title>\n",
98           main_Info_Title == NULL ? "[none]" : main_Info_Title);
99  fprintf (stream, "<schedule_description>%s</schedule_description>\n",
100           main_Info_Description == NULL ? "[none]" : main_Info_Description);
101  fprintf (stream, "<author>%s</author>\n",
102           main_Info_Author == NULL ? "[none]" : main_Info_Author);
103  fprintf (stream, "<totaltime>%s</totaltime>\n",
104           g_ascii_formatd (strbuf, strsize, "%g", SG_TotalScheduleDuration));
105  fprintf (stream, "<voicecount>%d</voicecount>\n", voice_count);
106  fprintf (stream, "<totalentrycount>%d</totalentrycount>\n", DP_count);
107  fprintf (stream, "<loops>%d</loops>\n", BB_Loops);
108  fprintf (stream, "<overallvolume_left>%s</overallvolume_left>\n",
109           g_ascii_formatd (strbuf, strsize, "%g", BB_VolumeOverall_left));
110  fprintf (stream, "<overallvolume_right>%s</overallvolume_right>\n",
111           g_ascii_formatd (strbuf, strsize, "%g", BB_VolumeOverall_right));
112  fprintf (stream, "<stereoswap>%d</stereoswap>\n", BB_StereoSwap);
113  fprintf (stream, "<graphview>%d</graphview>\n", SG_GraphType);
114 
115  //#define GXML_MAKEARRAYS
116 #ifdef GXML_MAKEARRAYS
117  //this is for making a schedule internal:
118  FILE *array = fopen ("VoiceArray.h", "w");
119 #endif
120 
121  // Now put all the selected DPs in to the copy buffer:
122  DP_count = 0;
123  voice_count = 0;
124  curVoice = SG_FirstVoice;
125  while (curVoice != NULL)
126  {
127   //first count the number of DP's in this voice:
128   curDP = curVoice->FirstDataPoint;
129   int dpcount_local = 0;
130 
131   while (curDP != NULL)
132   {
133    ++dpcount_local;
134    //all list loops need this:
135    curDP = curDP->NextDataPoint;
136   }
137 
138 #ifdef GXML_MAKEARRAYS
139   fprintf (array,
140            "/* First three Type, Count, Mono,\nrest are Dur, VolL, VolR, Beat, Base */\n");
141   fprintf (array, "static final float BB_ScheduleArray%d[] = {\n%d,%d,%d",
142            voice_count, curVoice->type, dpcount_local, curVoice->mono);
143 #endif
144 
145   //now do it again with that info:
146   curDP = curVoice->FirstDataPoint;
147   fprintf (stream, "<voice>\n");
148   fprintf (stream, "<description>%s</description>\n",
149            curVoice->description == NULL ? "[none]" : curVoice->description);
150   fprintf (stream, "<id>%d</id>\n", voice_count);
151   fprintf (stream, "<type>%d</type>\n", curVoice->type);
152   fprintf (stream, "<voice_state>%d</voice_state>\n", curVoice->state);
153   fprintf (stream, "<voice_hide>%d</voice_hide>\n", curVoice->hide);
154   fprintf (stream, "<voice_mute>%d</voice_mute>\n", curVoice->mute);
155   fprintf (stream, "<voice_mono>%d</voice_mono>\n", curVoice->mono);
156   fprintf (stream, "<entrycount>%d</entrycount>\n", dpcount_local);
157   fprintf (stream, "<entries>\n");
158 
159   while (curDP != NULL)
160   {
161 #ifdef GXML_MAKEARRAYS
162    fprintf (array, ",\n%gf,%gf,%gf,%gf,%gf",
163             curDP->duration,
164             curDP->volume_left,
165             curDP->volume_right, curDP->beatfreq, curDP->basefreq);
166 #endif
167 
168    //NEW STYLE FORMAT
169    //START entry writing:
170    fprintf (stream, "<entry parent=\"%d\" duration=\"%s\" ", voice_count,
171             g_ascii_formatd (strbuf, strsize, "%g", curDP->duration));
172    fprintf (stream, "volume_left=\"%s\" ",
173             g_ascii_formatd (strbuf, strsize, "%g", curDP->volume_left));
174    fprintf (stream, "volume_right=\"%s\" ",
175             g_ascii_formatd (strbuf, strsize, "%g", curDP->volume_right));
176    fprintf (stream, "beatfreq=\"%s\" ",
177             g_ascii_formatd (strbuf, strsize, "%g", curDP->beatfreq));
178    fprintf (stream, "basefreq=\"%s\" state=\"%d\"/>\n",
179             g_ascii_formatd (strbuf, strsize, "%g", curDP->basefreq),
180             curDP->state);
181    //END entry writing:
182    //END NEW STYLE FORMAT
183    ++DP_count;
184    //all list loops need this:
185    curDP = curDP->NextDataPoint;
186   }
187   curVoice = curVoice->NextVoice;
188   fprintf (stream, "</entries>\n");
189   fprintf (stream, "</voice>\n");
190   ++voice_count;
191 
192 #ifdef GXML_MAKEARRAYS
193   fprintf (array, "};\n\n");
194 #endif
195 
196  }
197  fprintf (stream, "</schedule>\n");
198  fclose (stream);
199  SG_DBGOUT_INT ("Wrote DataPoints:", DP_count);
200 
201 #ifdef GXML_MAKEARRAYS
202  fclose (array);
203 #endif
204 }
205 
206 ///////////////////////////////////////////////
207 //this is only called by main_XMLParser; don't call yerself.
208 //point of this is to keep Event data separate, since it is the
209 //most numerous and thus should probably be done with Attributes
gxml_XMLEventDataParser(const gchar * DataType,const gchar * Value,const int internal_EntryCount)210 int gxml_XMLEventDataParser (const gchar * DataType,
211                              const gchar * Value,
212                              const int internal_EntryCount)
213 {
214  //==START OF EVENT PROPERTIES
215  if (!strcmp (DataType, "parent"))
216  {
217   //must add 1, because 0 would look to Restore() like a NULL pointer:
218   SG_UndoRedo.DPdata[internal_EntryCount].parent =
219    (void *) (atoi (Value) + 1);
220   SG_DBGOUT_PNT ("parent:", SG_UndoRedo.DPdata[internal_EntryCount].parent);
221   return 0;
222  }
223 
224  if (!strcmp (DataType, "duration"))
225  {
226   SG_UndoRedo.DPdata[internal_EntryCount].duration =
227    g_ascii_strtod (Value, NULL);
228   SG_DBGOUT_FLT ("duration:",
229                  SG_UndoRedo.DPdata[internal_EntryCount].duration);
230   return 0;
231  }
232 
233  if (!strcmp (DataType, "volume_left"))
234  {
235   SG_UndoRedo.DPdata[internal_EntryCount].volume_left =
236    g_ascii_strtod (Value, NULL);
237   SG_DBGOUT_FLT ("volume_left:",
238                  SG_UndoRedo.DPdata[internal_EntryCount].volume_left);
239   return 0;
240  }
241 
242  if (!strcmp (DataType, "volume_right"))
243  {
244   SG_UndoRedo.DPdata[internal_EntryCount].volume_right =
245    g_ascii_strtod (Value, NULL);
246   SG_DBGOUT_FLT ("volume_right:",
247                  SG_UndoRedo.DPdata[internal_EntryCount].volume_right);
248   return 0;
249  }
250 
251  if (!strcmp (DataType, "beatfreq"))
252  {
253   SG_UndoRedo.DPdata[internal_EntryCount].beatfreq =
254    g_ascii_strtod (Value, NULL);
255   SG_DBGOUT_FLT ("beatfreq:",
256                  SG_UndoRedo.DPdata[internal_EntryCount].beatfreq);
257   return 0;
258  }
259 
260  if (!strcmp (DataType, "basefreq"))
261  {
262   SG_UndoRedo.DPdata[internal_EntryCount].basefreq =
263    g_ascii_strtod (Value, NULL);
264   SG_DBGOUT_FLT ("basefreq:",
265                  SG_UndoRedo.DPdata[internal_EntryCount].basefreq);
266   return 0;
267  }
268 
269  if (!strcmp (DataType, "state"))
270  {
271   SG_UndoRedo.DPdata[internal_EntryCount].state = atoi (Value);
272   SG_DBGOUT_INT ("state:", SG_UndoRedo.DPdata[internal_EntryCount].state);
273   return 0;
274  }
275  //==END OF EVENT PROPERTIES
276  //=========================
277  return 1;
278 }
279 
280 ///////////////////////////////////////////////
281 //this is only called by main_XMLReadFile; don't call
gxml_XMLParser(const gchar * CurrentElement,const gchar * Attribute,const gchar * Value)282 void gxml_XMLParser (const gchar * CurrentElement,      //this must always be a valid string
283                      const gchar * Attribute,   //beware: this will equal NULL if there are none
284                      const gchar * Value)
285 {       //beware: this will equal NULL to announce end of CurrnetElement
286  //Essential to do things in this order:
287  // 1) Check if this call represents the end of CurrentElement; if so, increment counter vars then return
288  // 2) See if there are Attributes with this CurrentElement; if so, assign them, then return;
289  // 3) If I got here, just slog through Elements and Values to assign to vars
290  static int internal_EntryCount = 0;
291 
292  static int internal_VoiceCount = 0;
293 
294  //See if this is the end of CurrentElement:
295  if (Value == NULL)
296  {
297   if (0 == strcmp (CurrentElement, "entry"))
298   {
299    ++internal_EntryCount;
300    SG_DBGOUT_STR ("==END ", CurrentElement);
301   }
302   else if (0 == strcmp (CurrentElement, "voice"))
303   {
304    ++internal_VoiceCount;
305    SG_DBGOUT_STR ("==END ", CurrentElement);
306   }
307   return;
308  }
309 
310  //Now deal with Attributes if there are any:
311  if (Attribute != NULL)
312  {
313   // ParserXML_AbortFlag = TRUE;
314   // SG_DBGOUT_STR(Attribute, Value);
315   gxml_XMLEventDataParser (Attribute, Value, internal_EntryCount);
316   return;
317  }
318 
319  //got here, so must slog through assigning vars Element-by-Element (the old way).
320  //The first line exists in order to allow old pre-Attribute file versions to
321  //still be openable:
322  if (0 ==
323      gxml_XMLEventDataParser (CurrentElement, Value, internal_EntryCount))
324  {
325  }
326  else if (!strcmp (CurrentElement, "description"))
327  {
328   //20070627: fixed bug here if user had no desc. (because Value would equal NULL)
329   //  SG_UndoRedo.Voice[internal_VoiceCount].description =
330   SG_StringAllocateAndCopy (&
331                             (SG_UndoRedo.Voice[internal_VoiceCount].
332                              description), Value);
333   SG_DBGOUT_STR ("description:",
334                  SG_UndoRedo.Voice[internal_VoiceCount].description);
335  }
336  else if (!strcmp (CurrentElement, "type"))
337  {
338   SG_UndoRedo.Voice[internal_VoiceCount].type = atoi (Value);
339   SG_DBGOUT_INT ("voicetype:", SG_UndoRedo.Voice[internal_VoiceCount].type);
340  }
341  else if (!strcmp (CurrentElement, "voice_state"))
342  {
343   SG_UndoRedo.Voice[internal_VoiceCount].state = atoi (Value);
344   SG_DBGOUT_INT ("voice_state:",
345                  SG_UndoRedo.Voice[internal_VoiceCount].state);
346  }
347  else if (!strcmp (CurrentElement, "voice_hide"))
348  {
349   SG_UndoRedo.Voice[internal_VoiceCount].hide = atoi (Value);
350   SG_DBGOUT_INT ("voice_hide:", SG_UndoRedo.Voice[internal_VoiceCount].hide);
351  }
352  else if (!strcmp (CurrentElement, "voice_mute"))
353  {
354   SG_UndoRedo.Voice[internal_VoiceCount].mute = atoi (Value);
355   SG_DBGOUT_INT ("voice_mute:", SG_UndoRedo.Voice[internal_VoiceCount].mute);
356  }
357  else if (!strcmp (CurrentElement, "voice_mono"))
358  {
359   SG_UndoRedo.Voice[internal_VoiceCount].mono = atoi (Value);
360   SG_DBGOUT_INT ("voice_mono:", SG_UndoRedo.Voice[internal_VoiceCount].mono);
361  }
362  //By the totalentrycount entry, I have all the info needed to make the critical memory allotments:
363  else if (!strcmp (CurrentElement, "totalentrycount"))
364  {
365   int listedcount = atoi (Value);
366 
367   if (listedcount > gxml_ParserXML_EntryCount)
368   {
369    SG_ERROUT_INT ("Listed entry count larger than actual count by",
370                   listedcount - gxml_ParserXML_EntryCount);
371    SG_DBGOUT_INT ("  Listed count:", listedcount);
372    SG_DBGOUT_INT ("  Actual count:", gxml_ParserXML_EntryCount);
373   }
374   else if (listedcount < gxml_ParserXML_EntryCount)
375   {
376    SG_ERROUT_INT ("Listed entry count smaller than actual count by",
377                   gxml_ParserXML_EntryCount - listedcount);
378    SG_DBGOUT_INT ("  Listed count:", listedcount);
379    SG_DBGOUT_INT ("  Actual count:", gxml_ParserXML_EntryCount);
380   }
381   else
382   {
383    SG_DBGOUT_INT ("Listed entry count matched actual count:",
384                   gxml_ParserXML_EntryCount);
385   }
386 
387   //  SG_UndoRedo.TotalDataPoints = atoi (Value);   //this is weak, as this number could be wrong (I need to count myself)
388   SG_UndoRedo.TotalDataPoints = gxml_ParserXML_EntryCount;      //I trust the read count more than listed
389   SG_AllocateBackupData (&SG_UndoRedo, SG_UndoRedo.TotalVoices,
390                          SG_UndoRedo.TotalDataPoints);
391   SG_DBGOUT_INT ("TotalEntryCount:", SG_UndoRedo.TotalDataPoints);
392   SG_DBGOUT ("==Allocated Loadup Data==");
393  }
394  else if (!strcmp (CurrentElement, "voicecount"))
395  {
396   int listedcount = atoi (Value);
397 
398   if (listedcount > gxml_ParserXML_VoiceCount)
399   {
400    SG_ERROUT_INT ("Listed voice count larger than actual count by",
401                   listedcount - gxml_ParserXML_VoiceCount);
402    SG_DBGOUT_INT ("  Listed count:", listedcount);
403    SG_DBGOUT_INT ("  Actual count:", gxml_ParserXML_VoiceCount);
404   }
405   else if (listedcount < gxml_ParserXML_VoiceCount)
406   {
407    SG_ERROUT_INT ("Listed voice count smaller than actual count by",
408                   gxml_ParserXML_VoiceCount - listedcount);
409    SG_DBGOUT_INT ("  Listed count:", listedcount);
410    SG_DBGOUT_INT ("  Actual count:", gxml_ParserXML_VoiceCount);
411   }
412   else
413   {
414    SG_DBGOUT_INT ("Listed voice count matched actual count:",
415                   gxml_ParserXML_VoiceCount);
416   }
417   SG_UndoRedo.TotalVoices = gxml_ParserXML_VoiceCount;  // I trust the real count more than listed
418  }
419 
420  //finally the rarely called, low-priority global entries:
421  else if (!strcmp (CurrentElement, "title"))
422  {
423   SG_StringAllocateAndCopy (&main_Info_Title, Value);
424  }
425  else if (!strcmp (CurrentElement, "schedule_description"))
426  {
427   SG_StringAllocateAndCopy (&main_Info_Description, Value);
428  }
429  else if (!strcmp (CurrentElement, "author"))
430  {
431   SG_StringAllocateAndCopy (&main_Info_Author, Value);
432  }
433  else if (!strcmp (CurrentElement, "loops"))
434  {
435   main_SetLoops (atoi (Value));
436   SG_DBGOUT_INT ("Loops:", BB_Loops);
437  }
438  else if (!strcmp (CurrentElement, "overallvolume_left"))
439  {
440   BB_VolumeOverall_left = g_ascii_strtod (Value, NULL);
441   SG_DBGOUT_FLT ("BB_VolumeOverall_left", BB_VolumeOverall_left);
442  }
443  else if (!strcmp (CurrentElement, "overallvolume_right"))
444  {
445   BB_VolumeOverall_right = g_ascii_strtod (Value, NULL);
446   SG_DBGOUT_FLT ("BB_VolumeOverall_right", BB_VolumeOverall_right);
447  }
448  else if (!strcmp (CurrentElement, "stereoswap"))
449  {
450   BB_StereoSwap = atoi (Value);
451   SG_DBGOUT_INT ("BB_StereoSwap", BB_StereoSwap);
452  }
453  else if (!strcmp (CurrentElement, "graphview"))
454  {
455   SG_GraphType = atoi (Value);
456   SG_DBGOUT_INT ("SG_GraphType", SG_GraphType);
457  }
458  else if (!strcmp (CurrentElement, "gnauralfile_version"))
459  {
460   gxml_GnauralFile = ~0;
461   SG_DBGOUT ("Zeroing running voice and entry counts");
462   internal_EntryCount = internal_VoiceCount = 0;
463   SG_DBGOUT_STR ("File Version:", Value);
464   if (strcmp (gxml_VERSION_GNAURAL_XMLFILE, Value))
465   {
466    //SG_ERROUT("File format version too old: Aborting!");
467    //ParserXML_AbortFlag = 1;
468    SG_ERROUT ("Unknown File Version:");
469    SG_ERROUT ("Expected:");
470    SG_ERROUT (gxml_VERSION_GNAURAL_XMLFILE);
471    SG_ERROUT ("Got:");
472    SG_ERROUT (Value);
473    //    if (0 == main_MessageDialogBox ("Unknown Gnaural file version or format. Is this a Gnaural 1 file?", GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO)) { }
474   }
475   else
476   {
477    SG_DBGOUT ("Useable file version, continuing:");
478   }
479  }
480 }
481 
482 /////////////////////////////////////////////////////
483 //Returns 0 on success
484 //widget refers to main_drawing_area, BTW
485 //To maximize reusing code, this procedure actually fills
486 //ScheduleGUI's variable "SG_UndoRedo" with the incoming
487 //data, then treats that data like any ordinary restore.
488 //RETURNS 0 on success;
489 //20070705: changed a lot of address bugs with console mode
490 //trying to update a non-existent GUI.
491 //NOTE: if MergeRestore == TRUE, adds restore to whatever is already
492 //in SG; if FALSE, erases everything currently in SG
gxml_XMLReadFile(char * filename,GtkWidget * widget,gboolean MergeRestore)493 int gxml_XMLReadFile (char *filename,
494                       GtkWidget * widget, gboolean MergeRestore)
495 {
496  if (filename == NULL)
497  {
498   return -1;
499  }
500 
501  //to check if maybe it is a Gnaural1 file:
502  gxml_GnauralFile = 0;
503 
504  //Set a few things in case they're skipped later:
505  main_SetLoops (1);
506  main_Info_Author[0] = '\0';
507  main_Info_Title[0] = '\0';
508  main_Info_Description[0] = '\0';
509  BB_ResetAllVoices ();  //never hurts to do this, and might help a lot
510  //  BB_LoopCount = 1;
511 
512  //to parse a Gnaural file:
513  // 1) zero any SG internal variables used to count voice/event progress (ESSENTIAL)
514  // 2) Give ParserXML SG's internal callback function
515  // 3) call ParserXML_parse_file_xml:
516  //Mustn't forget this:
517  gxml_ParserXML_VoiceCount = 0;
518  gxml_ParserXML_EntryCount = 0;
519  SetUserParserXMLHandler (gxml_XMLParser_counter);
520  SG_DBGOUT ("Parsing XML file for true voice and entry counts");
521  if (0 == ParserXML_parse_file_xml (filename))
522  {
523   SG_DBGOUT_INT ("Total new Voice count: ", gxml_ParserXML_VoiceCount);
524   SG_DBGOUT_INT ("Total new Entry count: ", gxml_ParserXML_EntryCount);
525  }
526  else
527  {
528   SG_DBGOUT ("Something's wrong with the XML file, can't count");
529  }
530  SetUserParserXMLHandler (gxml_XMLParser);
531  SG_DBGOUT ("Starting with real XML file parse:");
532  if (0 == ParserXML_parse_file_xml (filename))
533  {
534   SG_DBGOUT ("XML file parsed, putting data in engine:");
535   SG_DBGOUT_INT ("Total new Voice count: ", gxml_ParserXML_VoiceCount);
536   SG_DBGOUT_INT ("Total new Entry count: ", gxml_ParserXML_EntryCount);
537   SG_RestoreDataPoints (widget, MergeRestore);
538   SG_DrawGraph (widget);
539   SG_DBGOUT_STR ("Title:", main_Info_Title);
540   SG_DBGOUT_STR ("Author:", main_Info_Author);
541   SG_DBGOUT_STR ("Description:", main_Info_Description);
542   main_UpdateGUI_UserDataInfo ();
543   gnauralRecentMenu_add_utf8_filename (filename);       //a20101014
544 
545  }
546  else
547  {
548   if (gxml_GnauralFile == 0)
549   {
550    SG_DBGOUT ("No Gnaural format file found");
551    //try to open a Gnaural1 file:
552    if (main_gnaural_guiflag == TRUE ||  //BUG20100928: was "FALSE"
553        0 != main_MessageDialogBox ("Write default file?)",      //Is this a pre-2007 Gnaural file?",
554                                    GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO))
555    {
556     main_WriteDefaultFile ();
557    }
558    else
559    {
560     SG_DBGOUT ("Processing as a pre-2006 Gnaural file");
561     main_GNAURAL1FILE_SchedFilenameToSchedule (filename);
562     //       SG_GetScheduleLimits();
563     SG_ConvertDataToXY (widget);
564     //    SG_DrawGraph (widget);
565     SG_DataHasChanged = SG_GraphHasChanged = TRUE;
566    }
567   }
568   else
569   {
570    return -1;   //THIS SHOULD BE CLEANED UP; it is confusing
571   }
572  }
573 
574  //Got here, so file is valid, so load BB and set main_sCurrentGnauralFilenameAndPath:
575  strcpy (main_sCurrentGnauralFilenameAndPath, filename);
576  main_LoadBinauralBeatSoundEngine ();
577 
578  //Loaded BB engine, so can get schedule fingerprint for file:
579  GN_Running_GetScheduleFingerprint ();
580  GN_DBGOUT_INT ("Full Schedule Fingerprint:", GN_ScheduleFingerprint);
581 
582  //if we have a GUI, might as well do this here:
583  if (main_gnaural_guiflag == TRUE)
584  {
585   main_SetGraphToggle (main_drawing_area);
586   main_UpdateGUI_FileInfo (filename);
587   VG_DestroyTreeView ();        //20100624
588   main_UpdateGUI_Voices (main_vboxVoices);
589   main_OnButton_Stop (NULL);
590  }
591  return 0;
592 }
593 
594 ///////////////////////////////////////////////
595 //this is only called by ParserXML; don't call it has one job:
596 //to count the number of voices and number of datapoints
gxml_XMLParser_counter(const gchar * CurrentElement,const gchar * Attribute,const gchar * Value)597 void gxml_XMLParser_counter (const gchar * CurrentElement,      //this must always be a valid string
598                              const gchar * Attribute,   //beware: this will equal NULL if there are none
599                              const gchar * Value)       //beware: this will equal NULL to announce end of CurrnetElement
600 {
601  //See if this is the end of CurrentElement:
602  if (Value == NULL)
603  {
604   if (0 == strcmp (CurrentElement, "entry"))
605   {
606    ++gxml_ParserXML_EntryCount;
607   }
608   else if (0 == strcmp (CurrentElement, "voice"))
609   {
610    ++gxml_ParserXML_VoiceCount;
611   }
612   return;
613  }
614 }
615