2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
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)
12 #include <findhack.h> // all the abstracted lg_find stuff
24 // Must be last header
27 #define SONG_FILEVERSION 1
30 #define SONGFWRITE(f, x) fwrite (&(x), sizeof(x), 1, (f))
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
41 typedef struct sSongFile
47 class cSongFileNameHash
: public cStrHashSet
<sSongFile
*>
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
)
64 DatapathDir
*pDatapathDir
;
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
);
84 DatapathCloseDir(pDatapathDir
);
85 DatapathFree(&sDatapath
);
88 static void SongFilesRead(fSongRead readFunc
)
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
);
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
];
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
);
125 SongFilesRead(readFunc
);
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
)
139 ISongSection
* pSection
;
140 ISongSample
* pSample
;
144 sSongEventInfo eventInfo
;
145 sSongSectionInfo sectionInfo
;
146 sSongSampleInfo sampleInfo
;
147 sSongGotoInfo gotoInfo
;
151 unsigned count1
, count2
, count3
, i
, j
, k
;
153 // Open file for writing.
154 fp
= fopen (filename
, "wb");
157 Warning (("Failure opening song file \"%s\" for writing.\n", filename
));
161 // Write version number.
162 fileVersion
= SONG_FILEVERSION
;
163 SONGFWRITE (fp
, fileVersion
);
166 pSong
->GetSongInfo (&songInfo
);
167 SONGFWRITE (fp
, songInfo
);
170 count1
= pSong
->CountEvents();
171 SONGFWRITE (fp
, count1
);
172 for (i
= 0; i
< count1
; i
++)
175 pSong
->GetEvent(i
, &pEvent
);
176 pEvent
->GetEventInfo(&eventInfo
);
177 SONGFWRITE (fp
, eventInfo
);
180 count2
= pEvent
->CountGotos();
181 SONGFWRITE (fp
, count2
);
182 for (j
= 0; j
< count2
; j
++)
185 pEvent
->GetGoto(j
, &pGoto
);
186 pGoto
->GetGotoInfo(&gotoInfo
);
187 SONGFWRITE (fp
, gotoInfo
);
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(§ionInfo
);
201 SONGFWRITE (fp
, sectionInfo
);
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
);
216 count2
= pSection
->CountEvents();
217 SONGFWRITE (fp
, count2
);
218 for (j
= 0; j
< count2
; j
++)
221 pSection
->GetEvent(j
, &pEvent
);
222 pEvent
->GetEventInfo(&eventInfo
);
223 SONGFWRITE (fp
, eventInfo
);
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
);
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
;
250 char *pData
, *pDataStart
;
254 ISongSection
* pSection
;
255 ISongSample
* pSample
;
259 sSongEventInfo eventInfo
;
260 sSongSectionInfo sectionInfo
;
261 sSongSampleInfo sampleInfo
;
262 sSongGotoInfo gotoInfo
;
266 unsigned count1
, count2
, count3
, i
, j
, k
;
269 // Set up pSoundPath to point to the sound files
272 pSncPath
= pResMan
->NewSearchPath();
273 pSncPath
->AddPathTrees("song\\", FALSE
);
276 pRes
= pResMan
->Bind (filename
, RESTYPE_BINARY
, pSncPath
);
279 Warning (("Song \"%s\" not found.\n", filename
));
284 pDataStart
= (char*) pRes
->Lock();
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
));
297 SONGREAD (pData
, songInfo
);
298 CreateSong (&pSong
, NULL
);
299 pSong
->SetSongInfo(&songInfo
);
302 SONGREAD (pData
, count1
);
303 for (i
= 0; i
< count1
; i
++)
306 SONGREAD (pData
, eventInfo
);
307 CreateSongEvent (&pEvent
, NULL
);
308 pEvent
->SetEventInfo(&eventInfo
);
311 SONGREAD (pData
, count2
);
312 for (j
= 0; j
< count2
; j
++)
315 SONGREAD (pData
, gotoInfo
);
316 CreateSongGoto (&pGoto
, NULL
);
317 pGoto
->SetGotoInfo(&gotoInfo
);
319 pEvent
->AddGoto(pGoto
);
322 pSong
->AddEvent(pEvent
);
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(§ionInfo
);
336 SONGREAD (pData
, count2
);
337 for (j
= 0; j
< count2
; j
++)
340 SONGREAD (pData
, sampleInfo
);
341 CreateSongSample (&pSample
, NULL
);
342 pSample
->SetSampleInfo(&sampleInfo
);
344 pSection
->AddSample(pSample
);
349 SONGREAD (pData
, count2
);
350 for (j
= 0; j
< count2
; j
++)
353 SONGREAD (pData
, eventInfo
);
354 CreateSongEvent (&pEvent
, NULL
);
355 pEvent
->SetEventInfo(&eventInfo
);
358 SONGREAD (pData
, count3
);
359 for (k
= 0; k
< count3
; k
++)
362 SONGREAD (pData
, gotoInfo
);
363 CreateSongGoto (&pGoto
, NULL
);
364 pGoto
->SetGotoInfo(&gotoInfo
);
366 pEvent
->AddGoto(pGoto
);
369 pSection
->AddEvent(pEvent
);
373 pSong
->AddSection(pSection
);