convert line ends
[canaan.git] / prj / cam / src / sound / songfile.cpp
blobd6109f8154e51c3eec3dc4e8b395d01140bfc147
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 // $Header: r:/t2repos/thief2/src/sound/songfile.cpp,v 1.2 1999/05/12 18:16:31 mwhite Exp $
8 // (MRW : Stolen from schfile.cpp)
10 #include <song.h>
11 #include <songfile.h>
12 #include <findhack.h> // all the abstracted lg_find stuff
13 #include <hashset.h>
14 #include <hshsttem.h>
15 #include <str.h>
16 #include <datapath.h>
17 #include <config.h>
18 #include <cfgdbg.h>
19 #include <appagg.h>
20 #include <resapi.h>
21 #include <storeapi.h>
22 #include <binrstyp.h>
24 // Must be last header
25 #include <dbmem.h>
27 #define SONG_FILEVERSION 1
29 #ifdef EDITOR
30 #define SONGFWRITE(f, x) fwrite (&(x), sizeof(x), 1, (f))
31 #endif // EDITOR
33 //#define SONGFREAD(f, x) fread (&(x), sizeof(x), 1, (f))
34 #define SONGREAD(p, x) { memcpy (&x, p, sizeof(x)); p += sizeof(x); }
37 // Everything but load (binary) is editor-only
39 #ifdef EDITOR
41 typedef struct sSongFile
43 cStr fileName;
44 cStr pathName;
45 } sSongFile;
47 class cSongFileNameHash: public cStrHashSet<sSongFile *>
49 private:
50 tHashSetKey GetKey(tHashSetNode node) const;
53 tHashSetKey cSongFileNameHash::GetKey(tHashSetNode node) const
55 return (tHashSetKey)((const char*)(((sSongFile*)node)->fileName));
58 static cSongFileNameHash fileNameHash;
61 static void SongFilesGet(const char *pszDataPath, const char *pszWhat)
63 Datapath sDatapath;
64 DatapathDir *pDatapathDir;
65 char *pszFileName;
66 sSongFile *pSongFile;
68 DatapathClear(&sDatapath);
69 DatapathAdd(&sDatapath, (char*)pszDataPath);
70 pDatapathDir = DatapathOpenDir(&sDatapath, (char*)pszWhat, DP_SCREEN_DOT);
71 while (NULL!=(pszFileName = DatapathReadDir(pDatapathDir)))
73 pSongFile = new sSongFile;
74 pSongFile->fileName = pszFileName;
75 (pSongFile->fileName).MakeLower();
76 if (!fileNameHash.Search((const char*)(pSongFile->fileName)))
78 pSongFile->pathName = pszDataPath;
79 fileNameHash.Insert(pSongFile);
81 else
82 delete pSongFile;
84 DatapathCloseDir(pDatapathDir);
85 DatapathFree(&sDatapath);
88 static void SongFilesRead(fSongRead readFunc)
90 cStr fullName;
91 sSongFile *pSongFile;
92 tHashSetHandle handle;
94 pSongFile = (sSongFile*)(fileNameHash.GetFirst(handle));
95 while (pSongFile != NULL)
97 fullName.FmtStr("%s\\%s", (const char*)(pSongFile->pathName),
98 (const char*)(pSongFile->fileName));
99 fileNameHash.Remove(pSongFile);
100 delete pSongFile;
101 ConfigSpew("SongFiles", ("Loading file %s\n", (const char*)fullName));
102 (*readFunc)((char*)((const char*)fullName));
103 pSongFile = (sSongFile*)fileNameHash.GetFirst(handle);
108 // read all files from res path and local dir that match "what" string
109 void SongFilesLoadFromDir(const char *where, const char *what, fSongRead readFunc)
111 static char szDataPath[PATH_MAX];
112 cStr resSongPath;
114 // open stuff in your current dir
115 resSongPath.FmtStr(".\\%s",where);
116 SongFilesGet((const char*)resSongPath, what);
118 // get stuff from res path
119 if (config_get_raw("song_source_path", szDataPath, sizeof(szDataPath)))
121 resSongPath.FmtStr("%s\\%s", szDataPath, where);
122 SongFilesGet((const char*)resSongPath, what);
124 // read it all
125 SongFilesRead(readFunc);
129 // Song save/load
131 // These might be nicer if the objects themselves knew about how to save themselves.
132 // As it is, modifications to the binary format must be carefully matched in the
133 // SongSave and SongLoad.
134 void SongSave (ISong* pSong, char* filename)
136 FILE* fp;
138 ISongEvent* pEvent;
139 ISongSection* pSection;
140 ISongSample* pSample;
141 ISongGoto* pGoto;
143 sSongInfo songInfo;
144 sSongEventInfo eventInfo;
145 sSongSectionInfo sectionInfo;
146 sSongSampleInfo sampleInfo;
147 sSongGotoInfo gotoInfo;
149 long fileVersion;
151 unsigned count1, count2, count3, i, j, k;
153 // Open file for writing.
154 fp = fopen (filename, "wb");
155 if (NULL == fp)
157 Warning (("Failure opening song file \"%s\" for writing.\n", filename));
158 return;
161 // Write version number.
162 fileVersion = SONG_FILEVERSION;
163 SONGFWRITE (fp, fileVersion);
165 // Write songInfo.
166 pSong->GetSongInfo (&songInfo);
167 SONGFWRITE (fp, songInfo);
169 // Write events.
170 count1 = pSong->CountEvents();
171 SONGFWRITE (fp, count1);
172 for (i = 0; i < count1; i++)
174 // Write event info.
175 pSong->GetEvent(i, &pEvent);
176 pEvent->GetEventInfo(&eventInfo);
177 SONGFWRITE (fp, eventInfo);
179 // Write gotos.
180 count2 = pEvent->CountGotos();
181 SONGFWRITE (fp, count2);
182 for (j = 0; j < count2; j++)
184 // Write goto info.
185 pEvent->GetGoto(j, &pGoto);
186 pGoto->GetGotoInfo(&gotoInfo);
187 SONGFWRITE (fp, gotoInfo);
188 pGoto->Release();
190 pEvent->Release();
193 // Write sections.
194 count1 = pSong->CountSections();
195 SONGFWRITE (fp, count1);
196 for (i = 0; i < count1; i++)
198 // Write section info.
199 pSong->GetSection(i, &pSection);
200 pSection->GetSectionInfo(&sectionInfo);
201 SONGFWRITE (fp, sectionInfo);
203 // Write samples.
204 count2 = pSection->CountSamples();
205 SONGFWRITE (fp, count2);
206 for (j = 0; j < count2; j++)
208 // Write sample info.
209 pSection->GetSample(j, &pSample);
210 pSample->GetSampleInfo(&sampleInfo);
211 SONGFWRITE (fp, sampleInfo);
212 pSample->Release();
215 // Write Events.
216 count2 = pSection->CountEvents();
217 SONGFWRITE (fp, count2);
218 for (j = 0; j < count2; j++)
220 // Write event info.
221 pSection->GetEvent(j, &pEvent);
222 pEvent->GetEventInfo(&eventInfo);
223 SONGFWRITE (fp, eventInfo);
225 // Write gotos.
226 count3 = pEvent->CountGotos();
227 SONGFWRITE (fp, count3);
228 for (k = 0; k < count3; k++)
230 pEvent->GetGoto(k, &pGoto);
231 pGoto->GetGotoInfo(&gotoInfo);
232 SONGFWRITE (fp, gotoInfo);
233 pGoto->Release();
235 pEvent->Release();
237 pSection->Release();
240 fclose (fp);
242 #endif // EDITOR
244 ISong* SongLoad (char* filename)
246 // SongLoad loads a .snc file into memory using namedres and then
247 // fits it into our data structures.
248 ISearchPath* pSncPath;
249 IRes* pRes;
250 char *pData, *pDataStart;
252 ISong* pSong;
253 ISongEvent* pEvent;
254 ISongSection* pSection;
255 ISongSample* pSample;
256 ISongGoto* pGoto;
258 sSongInfo songInfo;
259 sSongEventInfo eventInfo;
260 sSongSectionInfo sectionInfo;
261 sSongSampleInfo sampleInfo;
262 sSongGotoInfo gotoInfo;
264 long fileVersion;
266 unsigned count1, count2, count3, i, j, k;
269 // Set up pSoundPath to point to the sound files
271 AutoAppIPtr(ResMan);
272 pSncPath = pResMan->NewSearchPath();
273 pSncPath->AddPathTrees("song\\", FALSE);
274 pSncPath->Ready();
276 pRes = pResMan->Bind (filename, RESTYPE_BINARY, pSncPath);
277 if (NULL == pRes)
279 Warning (("Song \"%s\" not found.\n", filename));
280 pSncPath->Release();
281 return NULL;
284 pDataStart = (char*) pRes->Lock();
285 pData = pDataStart;
287 // Read version.
288 SONGREAD (pData, fileVersion);
289 // Simple version control : warn if not the expected version.
290 if (fileVersion != SONG_FILEVERSION)
292 Warning (("Loading song \"%s\", file version is %d, expecting %d.\n",
293 filename, fileVersion, (long) SONG_FILEVERSION));
296 // Read song.
297 SONGREAD (pData, songInfo);
298 CreateSong (&pSong, NULL);
299 pSong->SetSongInfo(&songInfo);
301 // Read events.
302 SONGREAD (pData, count1);
303 for (i = 0; i < count1; i++)
305 // Read event info.
306 SONGREAD (pData, eventInfo);
307 CreateSongEvent (&pEvent, NULL);
308 pEvent->SetEventInfo(&eventInfo);
310 // Read gotos.
311 SONGREAD (pData, count2);
312 for (j = 0; j < count2; j++)
314 // Read goto info.
315 SONGREAD (pData, gotoInfo);
316 CreateSongGoto (&pGoto, NULL);
317 pGoto->SetGotoInfo(&gotoInfo);
319 pEvent->AddGoto(pGoto);
320 pGoto->Release();
322 pSong->AddEvent(pEvent);
323 pEvent->Release();
326 // Read sections.
327 SONGREAD (pData, count1);
328 for (i = 0; i < count1; i++)
330 // Read section info.
331 SONGREAD (pData, sectionInfo);
332 CreateSongSection (&pSection, NULL);
333 pSection->SetSectionInfo(&sectionInfo);
335 // Read samples.
336 SONGREAD (pData, count2);
337 for (j = 0; j < count2; j++)
339 // Read sample info.
340 SONGREAD (pData, sampleInfo);
341 CreateSongSample (&pSample, NULL);
342 pSample->SetSampleInfo(&sampleInfo);
344 pSection->AddSample(pSample);
345 pSample->Release();
348 // Read events.
349 SONGREAD (pData, count2);
350 for (j = 0; j < count2; j++)
352 // Read event info.
353 SONGREAD (pData, eventInfo);
354 CreateSongEvent (&pEvent, NULL);
355 pEvent->SetEventInfo(&eventInfo);
357 // Read gotos.
358 SONGREAD (pData, count3);
359 for (k = 0; k < count3; k++)
361 // Read goto info.
362 SONGREAD (pData, gotoInfo);
363 CreateSongGoto (&pGoto, NULL);
364 pGoto->SetGotoInfo(&gotoInfo);
366 pEvent->AddGoto(pGoto);
367 pGoto->Release();
369 pSection->AddEvent(pEvent);
370 pEvent->Release();
373 pSong->AddSection(pSection);
374 pSection->Release();
377 pRes->Unlock();
378 pRes->Release();
379 pSncPath->Release();
381 return pSong;