4 ** Copyright (C) 1994,95,96,97 Bernardo Innocenti
6 ** Internal loader/saver hook for the IFF XMOD module format
9 #include <exec/memory.h>
10 #include <libraries/xmoduleclass.h>
12 #include <proto/exec.h>
13 #include <proto/dos.h>
14 #include <proto/intuition.h>
15 #include <proto/iffparse.h>
16 #include <proto/xmodule.h>
18 #include "XModulePriv.h"
22 /* Local functions prototypes */
24 static HOOKCALL struct XMHook *IdentifyXModule (
26 REG(a0, struct XMHook *loader),
27 REG(a1, ULONG *tags));
28 static HOOKCALL LONG LoadXModule (
30 REG(a0, struct SongInfo *si),
31 REG(a1, struct XMHook *loader),
32 REG(a2, ULONG *tags));
33 static HOOKCALL LONG SaveXModule (
35 REG(a0, struct SongInfo *si),
36 REG(a1, struct XMHook *saver),
37 REG(a2, ULONG *tags));
41 GLOBALCALL void AddXModuleHooks (void)
43 /* Adds XModule loader and saver */
46 XMHOOK_Type, NT_XMLOADER,
47 XMHOOK_Name, (LONG)"XModule",
49 XMHOOK_Descr, (LONG)"XModule internal format",
50 XMHOOK_Author, (LONG)"Bernardo Innocenti",
51 XMHOOK_Flags, XMHF_INTERNAL,
52 XMHOOK_LoadModFunc, LoadXModule,
53 XMHOOK_IdentifyModFunc, IdentifyXModule,
57 XMHOOK_Type, NT_XMSAVER,
58 XMHOOK_Name, (LONG)"XModule",
60 XMHOOK_Descr, (LONG)"XModule Internal format",
61 XMHOOK_Author, (LONG)"Bernardo Innocenti",
62 XMHOOK_Flags, XMHF_INTERNAL | XMHF_EXCLUDE_INSTRUMENTS |
63 XMHF_EXCLUDE_NAMES | XMHF_EXCLUDE_SEQUENCE,
64 XMHOOK_SaveModFunc, SaveXModule,
70 static HOOKCALL struct XMHook *IdentifyXModule (
72 REG(a0, struct XMHook *loader),
75 /* Determine if the given file is an XModule module.
76 * Note: the file position will be changed on exit.
81 Seek (fh, 0, OFFSET_BEGINNING);
82 if (FRead (fh, &id, 12, 1) != 1)
85 if ((id[0] == ID_FORM) && (id[2] == ID_XMOD))
93 static HOOKCALL LONG LoadXModule (
95 REG(a0, struct SongInfo *si),
96 REG(a1, struct XMHook *loader),
99 struct IFFHandle *iff;
100 struct ContextNode *cn;
103 if (iff = AllocIFF())
105 iff->iff_Stream = (ULONG) fh;
109 if (!(err = OpenIFF (iff, IFFF_READ)))
111 struct ModuleHeader mhdr;
113 static LONG stopchunks[] =
120 if (err = StopChunks (iff, stopchunks, 3))
123 if (err = StopOnExit (iff, ID_XMOD, ID_FORM))
130 if (err = ParseIFF (iff, IFFPARSE_SCAN))
132 if (err == IFFERR_EOF || err == IFFERR_EOC) err = RETURN_OK;
133 break; /* Free resources & exit */
136 if (cn = CurrentChunk (iff))
144 ReadChunkBytes (iff, name, min(cn->cn_Size, 127));
145 name[min(cn->cn_Size, 127)] = '\0'; /* Ensure string termination */
153 if ((err = ReadChunkBytes (iff, &mhdr, sizeof (mhdr))) != sizeof(mhdr))
158 if (cn->cn_Type == ID_SONG)
159 if (err = LoadSong (iff, si))
174 else err = ERROR_NO_FREE_STORE;
181 GLOBALCALL LONG LoadSong (struct IFFHandle *iff, struct SongInfo *si)
184 struct ContextNode *cn;
185 struct SongHeader shdr;
187 static LONG stopchunks[] =
199 memset (&shdr, 0, sizeof (shdr));
201 if (err = StopChunks (iff, stopchunks, 7))
204 if (err = StopOnExit (iff, ID_SONG, ID_FORM))
211 if (err = ParseIFF (iff, IFFPARSE_SCAN))
213 if (err == IFFERR_EOF || err == IFFERR_EOC) err = RETURN_OK;
214 break; /* Free resources & exit */
217 if (cn = CurrentChunk (iff))
225 ReadChunkBytes (iff, name, min(cn->cn_Size, 127));
226 name[min(cn->cn_Size, 127)] = '\0'; /* Ensure string termination */
237 ReadChunkBytes (iff, name, min(cn->cn_Size, 127));
238 name[min(cn->cn_Size, 127)] = '\0'; /* Ensure string termination */
249 ReadChunkBytes (iff, name, min(cn->cn_Size, 127));
250 name[min(cn->cn_Size, 127)] = '\0'; /* Ensure string termination */
252 SNGA_Description, name,
259 if ((err = ReadChunkBytes (iff, &shdr, sizeof (shdr))) == 0)
263 SNGA_GlobalSpeed, shdr.GlobalSpeed,
264 SNGA_GlobalTempo, shdr.GlobalTempo,
265 SNGA_RestartPos, shdr.RestartPos,
266 SNGA_CurrentPatt, shdr.CurrentPatt,
267 SNGA_CurrentPos, shdr.CurrentPos,
268 SNGA_CurrentInst, shdr.CurrentInst,
269 SNGA_DefaultTracks, shdr.DefNumTracks ? shdr.DefNumTracks : shdr.MaxTracks,
270 SNGA_DefaultPattLen, shdr.DefPattLen ? shdr.DefPattLen : DEF_PATTLEN,
271 SNGA_CreationDate, shdr.CreationDate,
272 SNGA_LastChanged, shdr.LastChanged,
273 SNGA_TotalChanges, shdr.TotalChanges,
278 len = min (cn->cn_Size / 2, MAXPOSITIONS);
280 if (xmSetSongLen (si, len))
282 if ((err = ReadChunkBytes (iff, si->Sequence, si->Length * 2))
286 else return ERROR_NO_FREE_STORE;
291 if (cn->cn_Type == ID_PATT)
293 if (!si->NumPatterns)
294 xmDisplayMessageA (XMDMF_USECATALOG | XMDMF_ACTION,
295 (APTR)MSG_READING_PATTS, NULL);
297 if (xmDisplayProgress (si->NumPatterns, shdr.NumPatterns))
300 if (!LoadPattern (si, si->NumPatterns, iff))
303 else if (cn->cn_Type == ID_8SVX)
305 if (!si->LastInstrument)
306 xmDisplayMessageA (XMDMF_USECATALOG | XMDMF_ACTION,
307 (APTR)MSG_READING_INSTS, NULL);
309 if (xmDisplayProgress (si->LastInstrument, shdr.LastInstrument))
312 if (err = Load8SVXInstrument (si, 0, iff, NULL))
329 GLOBALCALL struct Pattern *LoadPattern (struct SongInfo *si, ULONG num, struct IFFHandle *iff)
332 struct Pattern *patt = NULL;
333 struct ContextNode *cn;
334 struct PatternHeader phdr;
338 static LONG stopchunks[] =
347 if (err = StopChunks (iff, stopchunks, 3))
353 if (err = StopOnExit (iff, ID_PATT, ID_FORM))
363 if (err = ParseIFF (iff, IFFPARSE_SCAN))
365 if (err == IFFERR_EOF || err == IFFERR_EOC) err = RETURN_OK;
366 break; /* Free resources & exit */
369 if ((cn = CurrentChunk (iff)) && (cn->cn_Type == ID_PATT))
375 ReadChunkBytes (iff, name, min(cn->cn_Size, 63));
376 name[min(cn->cn_Size, 63)] = '\0'; /* Ensure string termination */
381 if ((err = ReadChunkBytes (iff, &phdr, sizeof (phdr))) != sizeof(phdr))
387 if (!(patt = xmAddPattern (si,
388 PATTA_Lines, phdr.Lines,
389 PATTA_Tracks, phdr.Tracks,
393 SetIoErr (ERROR_NO_FREE_STORE);
397 tracksize = phdr.Lines * sizeof (struct Note);
405 SetIoErr (IFFERR_SYNTAX);
409 for (i = 0; i < patt->Tracks; i++)
411 if ((err = ReadChunkBytes (iff, patt->Notes[i], tracksize)) != tracksize)
428 xmSetPattern (si, si->NumPatterns - 1,
433 err = ERROR_OBJECT_NOT_FOUND;
435 if (err) SetIoErr (err);
442 static HOOKCALL LONG SaveXModule (
444 REG(a0, struct SongInfo *si),
445 REG(a1, struct XMHook *saver),
446 REG(a2, ULONG *tags))
448 struct IFFHandle *iff;
451 if (iff = AllocIFF())
453 iff->iff_Stream = (ULONG) fh;
457 if (!(err = OpenIFF (iff, IFFF_WRITE)))
461 if (err = PushChunk (iff, ID_XMOD, ID_FORM, IFFSIZE_UNKNOWN))
464 /* Write module NAME */
465 if (err = WriteStringChunk (iff, FilePart (si->Path), ID_NAME))
468 /* Write module ANNO */
469 if (err = WriteStringChunk (iff, VERS, ID_ANNO))
472 /* Write Module Header (MHDR) */
474 struct ModuleHeader mhdr;
476 mhdr.XModuleVersion = VERSION;
477 mhdr.XModuleRevision = REVISION;
480 mhdr.MasterVolume = 0xFFFF;
481 mhdr.MixingRate = 44100;
483 if (err = PushChunk (iff, ID_XMOD, ID_MHDR, sizeof (mhdr)))
485 if ((err = WriteChunkBytes (iff, &mhdr, sizeof (mhdr))) != sizeof(mhdr))
487 if (err = PopChunk (iff)) goto error; /* Pop MHDR */
490 if (err = SaveSong (iff, si))
493 err = PopChunk (iff); /* Pop FORM XMOD */
498 else err = IFFERR_NOTIFF;
502 else err = ERROR_NO_FREE_STORE;
509 GLOBALCALL LONG SaveSong (struct IFFHandle *iff, struct SongInfo *si)
513 if (err = PushChunk (iff, ID_SONG, ID_FORM, IFFSIZE_UNKNOWN))
516 /* Write Song Name */
517 WriteStringChunk (iff, si->Title, ID_NAME);
519 /* Write Author Name */
520 WriteStringChunk (iff, si->Author, ID_AUTH);
522 /* Write Annotations */
523 WriteStringChunk (iff, si->Description, ID_ANNO);
525 /* Write Song Header (SHDR) */
527 struct SongHeader shdr;
529 if (err = PushChunk (iff, ID_SONG, ID_SHDR, IFFSIZE_UNKNOWN))
533 /* Set last changed date */
536 CurrentTime (&si->LastChanged, &dummy);
539 shdr.Length = si->Length;
540 shdr.MaxTracks = si->MaxTracks;
541 shdr.NumPatterns = si->NumPatterns;
542 shdr.LastInstrument = si->LastInstrument;
543 shdr.GlobalSpeed = si->GlobalSpeed;
544 shdr.GlobalTempo = si->GlobalTempo;
545 shdr.RestartPos = si->RestartPos;
546 shdr.CurrentPatt = si->CurrentPatt;
547 shdr.CurrentLine = si->CurrentLine;
548 shdr.CurrentTrack = si->CurrentTrack;
549 shdr.CurrentPos = si->CurrentPos;
550 shdr.CurrentInst = si->CurrentInst;
551 shdr.DefNumTracks = si->DefNumTracks;
552 shdr.DefPattLen = si->DefPattLen;
553 shdr.TotalChanges = si->TotalChanges + si->Changes;
554 shdr.CreationDate = si->CreationDate;
555 shdr.LastChanged = si->LastChanged;
558 if ((err = WriteChunkBytes (iff, &shdr, sizeof (shdr))) != sizeof (shdr))
561 if (err = PopChunk (iff)) /* Pop SHDR */
566 if (err = SaveSequence (iff, si))
568 if (err = SavePatterns (iff, si))
570 if (err = SaveInstruments (iff, si))
573 err = PopChunk (iff); /* Pop FORM SONG */
580 GLOBALCALL LONG SaveSequence (struct IFFHandle *iff, struct SongInfo *si)
584 if (err = PushChunk (iff, 0, ID_SEQN, si->Length * 2))
587 if ((err = WriteChunkBytes (iff, si->Sequence, si->Length * 2)) != si->Length * 2)
590 err = PopChunk (iff);
597 GLOBALCALL LONG SavePatterns (struct IFFHandle *iff, struct SongInfo *si)
602 xmDisplayMessageA (XMDMF_USECATALOG | XMDMF_ACTION,
603 (APTR)MSG_WRITING_PATTS, NULL);
606 for (i = 0; i < si->NumPatterns; i++)
608 if (xmDisplayProgress (i, si->NumPatterns))
612 if (err = SavePattern (iff, si->Patt[i]))
621 GLOBALCALL LONG SaveInstruments (struct IFFHandle *iff, struct SongInfo *si)
626 xmDisplayMessageA (XMDMF_USECATALOG | XMDMF_ACTION,
627 (APTR)MSG_WRITING_INSTS, NULL);
629 for (i = 1; i <= si->LastInstrument; i++)
631 if (!(si->Instr[i])) continue;
633 if (xmDisplayProgress (i - 1, si->LastInstrument))
636 if (err = Save8SVXInstrument (si->Instr[i], i, iff))
645 GLOBALCALL LONG SavePattern (struct IFFHandle *iff, struct Pattern *patt)
649 if (err = PushChunk (iff, ID_PATT, ID_FORM, IFFSIZE_UNKNOWN))
652 /* Write pattern NAME */
654 if (err = WriteStringChunk (iff, patt->Name, ID_NAME))
657 /* Write pattern header (PHDR) */
659 struct PatternHeader phdr;
661 phdr.Lines = patt->Lines;
662 phdr.Tracks = patt->Tracks;
664 if (err = PushChunk (iff, 0, ID_PHDR, sizeof (struct PatternHeader)))
667 if ((err = WriteChunkBytes (iff, &phdr, sizeof (phdr))) != sizeof (phdr))
670 if (err = PopChunk (iff)) /* PHDR */
674 /* Write pattern BODY */
676 ULONG tracksize = sizeof (struct Note) * patt->Lines;
679 if (err = PushChunk (iff, 0, ID_BODY, tracksize * patt->Tracks))
682 for (i = 0; i < patt->Tracks; i++)
684 if ((err = WriteChunkBytes (iff, patt->Notes[i], tracksize)) != tracksize)
688 if (err = PopChunk (iff)) /* BODY */
692 err = PopChunk (iff); /* PATT */
699 GLOBALCALL LONG WriteStringChunk (struct IFFHandle *iff, CONST_STRPTR str, ULONG id)
704 if (!str || !str[0] || !SaveSwitches.SaveNames)
707 if (err = PushChunk (iff, 0, id, len = strlen (str)))
710 if ((err = WriteChunkBytes (iff, str, len)) != len)
713 err = PopChunk (iff);