diff --git a/CHANGELOG.TXT b/CHANGELOG.TXT index 60ff44b..3a30569 100644 --- a/CHANGELOG.TXT +++ b/CHANGELOG.TXT @@ -1,3 +1,8 @@ +Version MOD 1.1.1 +----------------- +-Fixed bugs by STAS (many thanks) + + Version MOD 1.1.0 ----------------- -Added: VFPU Math Library libpspmath version 4 by MrMr[iCE] diff --git a/Makefile b/Makefile index e4dd2c7..6de7e58 100644 --- a/Makefile +++ b/Makefile @@ -22,8 +22,12 @@ PSP_FW_VERSION=371 # Project folders # --------------- -SOURCE_DIR := -INCLUDE_DIR := +#<-- STAS: pack all the necessary MikMod stuff directly into libosl.a +# in order to avoid conflict with the newest libmikmod releases. +SOURCE_DIR := ./ +MM_DIR := $(SOURCE_DIR)mikmod +INCLUDE_DIR := $(MM_DIR) +#<-- STAS END --> #---------------------------------------------------------------------------- # Source to make @@ -76,11 +80,32 @@ PSPMATHOBJS := $(SOURCE_DIR)libpspmath/printMatrixFloat.o \ $(SOURCE_DIR)libpspmath/vfpu_quaternion_sample_hermite.o \ $(SOURCE_DIR)libpspmath/vfpu_quaternion_hermite_tangent.o +MMLoaderObjs := $(MM_DIR)/mloader.o $(MM_DIR)/mlreg.o $(MM_DIR)/npertab.o \ + $(MM_DIR)/sloader.o $(MM_DIR)/load_uni.o $(MM_DIR)/mwav.o \ + $(MM_DIR)/load_mod.o $(MM_DIR)/load_m15.o $(MM_DIR)/load_mtm.o \ + $(MM_DIR)/load_s3m.o $(MM_DIR)/load_stm.o $(MM_DIR)/load_669.o \ + $(MM_DIR)/load_far.o $(MM_DIR)/load_dsm.o $(MM_DIR)/load_med.o \ + $(MM_DIR)/load_xm.o $(MM_DIR)/load_ult.o $(MM_DIR)/load_it.o \ + $(MM_DIR)/s3m_it.o $(MM_DIR)/load_wav.o + +MMDriverObjs := $(MM_DIR)/mdriver.o $(MM_DIR)/mdreg.o $(MM_DIR)/drv_nos.o + +MMPlayerObjs := $(MM_DIR)/mplayer.o + +MMIOOBJS := $(MM_DIR)/mmio/mmalloc.o \ + $(MM_DIR)/mmio/mmerror.o $(MM_DIR)/mmio/mmio.o + +MIKMODLIBOBJS := $(MM_DIR)/stream.o \ + $(MM_DIR)/virtch.o $(MM_DIR)/munitrk.o \ + $(MMLoaderObjs) $(MMDriverObjs) $(MMPlayerObjs) + LIBOBJS := $(SFONTOBJS) \ - $(PSPMATHOBJS) \ - $(SOURCE_DIR)oslib.o \ - $(SOURCE_DIR)vfpu.o \ - $(SOURCE_DIR)drawing.o \ + $(PSPMATHOBJS) \ + $(MMIOOBJS) \ + $(MIKMODLIBOBJS) \ + $(SOURCE_DIR)oslib.o \ + $(SOURCE_DIR)vfpu.o \ + $(SOURCE_DIR)drawing.o \ $(SOURCE_DIR)image.o \ $(SOURCE_DIR)palette.o \ $(SOURCE_DIR)shape.o \ @@ -117,7 +142,8 @@ LIBOBJS := $(SFONTOBJS) \ $(SOURCE_DIR)image/oslSetDrawBuffer.o \ $(SOURCE_DIR)image/oslResetImageProperties.o \ $(SOURCE_DIR)image/oslScaleImage.o \ - $(SOURCE_DIR)gif/dev2gif.o $(SOURCE_DIR)gif/dgif_lib.o $(SOURCE_DIR)gif/egif_lib.o $(SOURCE_DIR)gif/gif_err.o $(SOURCE_DIR)gif/gifalloc.o $(SOURCE_DIR)gif/quantize.o \ + $(SOURCE_DIR)gif/dev2gif.o $(SOURCE_DIR)gif/dgif_lib.o $(SOURCE_DIR)gif/egif_lib.o \ + $(SOURCE_DIR)gif/gif_err.o $(SOURCE_DIR)gif/gifalloc.o $(SOURCE_DIR)gif/quantize.o \ $(SOURCE_DIR)Special/oslLoadImageFilePNG.o \ $(SOURCE_DIR)Special/oslWriteImageFilePNG.o \ $(SOURCE_DIR)Special/oslLoadImageFileJPG.o \ @@ -127,8 +153,8 @@ LIBOBJS := $(SFONTOBJS) \ $(SOURCE_DIR)splash/oslShowSplashScreen1.o \ $(SOURCE_DIR)splash/oslShowSplashScreen2.o \ $(SOURCE_DIR)mem/oslGetRamStatus.o \ - $(SOURCE_DIR)intraFont/intraFont.o \ - $(SOURCE_DIR)intraFont/libccc.o + $(SOURCE_DIR)intraFont/intraFont.o \ + $(SOURCE_DIR)intraFont/libccc.o OBJS := $(LIBOBJS) @@ -154,7 +180,7 @@ SDK_LIBS := -lpspsdk \ -lpsputility \ -lpspssl -lpsphttp -lpspwlan -EXTERN_LIBS := -lpng \ +EXTERN_LIBS := -lpng -ljpeg \ -lz LIBS := $(EXTERN_LIBS) \ @@ -172,7 +198,7 @@ DEFINES := -D_DEBUG \ # Compiler settings # ----------------- -CFLAGS := $(DEFINES) -O2 -G0 -g -Wall -DHAVE_AV_CONFIG_H -fno-strict-aliasing -fverbose-asm +CFLAGS := $(DEFINES) -O2 -G0 -ggdb -Wall -DHAVE_AV_CONFIG_H -fno-strict-aliasing -fverbose-asm #CFLAGS := $(DEFINES) -O2 -G0 -g -frename-registers -ffast-math -fomit-frame-pointer -Wall -DHAVE_AV_CONFIG_H -fno-strict-aliasing CXXFLAGS := $(CFLAGS) -fno-exceptions -fno-rtti ASFLAGS := $(CFLAGS) @@ -185,15 +211,18 @@ LDFLAGS := # PBP parameters # -------------- -EXTRA_TARGETS := EBOOT.PBP +#EXTRA_TARGETS := EBOOT.PBP #PSP_EBOOT_ICON := ../ICON0.PNG #PSP_EBOOT_PIC1 := ../PIC1.PNG -PSP_EBOOT_TITLE := Oldschool Library for PSP +#PSP_EBOOT_TITLE := Oldschool Library for PSP #---------------------------------------------------------------------------- # Default build settings # ---------------------- +#test: +# echo $(OBJS) + PSPSDK := $(shell psp-config --pspsdk-path) include $(PSPSDK)/lib/build.mak @@ -202,26 +231,8 @@ include $(PSPSDK)/lib/build.mak # Copy to PSP # ----------- -oslDrawMap.o: oslDrawMap.c - $(CC) $(addprefix -I,$(INCDIR)) $(CFLAGS) -O3 -c -o $@ $< - lib: $(STATICLIB) $(STATICLIB): $(LIBOBJS) $(AR) rcs $@ $(LIBOBJS) $(RANLIB) $@ - -ifneq ($VS_PATH),) -CC = psp-gcc -endif - -kx-install: kxploit -ifeq ($(PSP_MOUNT),) - @echo '*** Error: $$(PSP_MOUNT) undefined. Please set it to for example /cygdrive/e' - @echo if your PSP is mounted to E: in cygwin. -else - cp -r $(TARGET) $(PSP_MOUNT)/PSP/GAME/ - cp -r $(TARGET)% $(PSP_MOUNT)/PSP/GAME/ - cp $(TARGET).elf $(PSP_MOUNT)/PSP/GAME/$(TARGET) - cp -r -u "../Data" $(PSP_MOUNT)/PSP/GAME/$(TARGET) -endif diff --git a/README.TXT b/README.TXT index d50e2c0..775dbb2 100644 --- a/README.TXT +++ b/README.TXT @@ -35,6 +35,7 @@ copy the oslib directory (containing header files) in $PSPSDK/include/ THANKS ------ +STAS for tha patch fixing many bugs pspZorba for his adhoc sample MrMr[iCE] for libpspmath InsertWittyName for all the sdk's dialog samples diff --git a/browser.c b/browser.c index dbc54ba..05cf759 100755 --- a/browser.c +++ b/browser.c @@ -1,101 +1,103 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "oslib.h" -#include "browser.h" - -#define BROWSER_MEMORY (10*1024*1024) - -static SceUID vpl; -static pspUtilityHtmlViewerParam params; -static int browserIsActive = 0; - -int oslBrowserInit(char *url, char *downloadDir, int browserMemory, unsigned int displaymode, unsigned int options, unsigned int interfacemode, unsigned int connectmode){ - int res; - if (browserMemory <= 0) - browserMemory = BROWSER_MEMORY; - - vpl = sceKernelCreateVpl("BrowserVpl", PSP_MEMORY_PARTITION_USER, 0, browserMemory + 256, NULL); - if (vpl < 0) - return OSL_BROWSER_ERROR_MEMORY; - - memset(¶ms, 0, sizeof(pspUtilityHtmlViewerParam)); - - params.base.size = sizeof(pspUtilityHtmlViewerParam); - - sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_LANGUAGE, ¶ms.base.language); - sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_UNKNOWN, ¶ms.base.buttonSwap); - - params.base.graphicsThread = 17; - params.base.accessThread = 19; - params.base.fontThread = 18; - params.base.soundThread = 16; - params.memsize = browserMemory; - params.initialurl = url; - params.numtabs = 1; - params.cookiemode = PSP_UTILITY_HTMLVIEWER_COOKIEMODE_DEFAULT; - params.homeurl = url; - params.textsize = PSP_UTILITY_HTMLVIEWER_TEXTSIZE_NORMAL; - params.displaymode = displaymode; - params.options = options; - params.interfacemode = interfacemode; - params.connectmode = connectmode; - - // WITHOUT 'ms0:' on the paths - params.dldirname = downloadDir; - - res = sceKernelAllocateVpl(vpl, params.memsize, ¶ms.memaddr, NULL); - if (res < 0) - return OSL_BROWSER_ERROR_MEMORY; - - res = sceUtilityHtmlViewerInitStart(¶ms); - if (res < 0) - return OSL_BROWSER_ERROR_INIT; - - browserIsActive = 1; - return 0; -} - - -void oslDrawBrowser() -{ - switch (sceUtilityHtmlViewerGetStatus()){ - case PSP_UTILITY_DIALOG_INIT: - case PSP_UTILITY_DIALOG_VISIBLE: - sceGuFinish(); - sceGuSync(0,0); - sceUtilityHtmlViewerUpdate(1); - sceGuStart(GU_DIRECT, osl_list); - oslSetAlpha(OSL_FX_RGBA, 0xff); - break; - case PSP_UTILITY_DIALOG_QUIT: - sceUtilityHtmlViewerShutdownStart(); - break; - case PSP_UTILITY_DIALOG_NONE: - case PSP_UTILITY_DIALOG_FINISHED: - break; - } -} - - -int oslGetBrowserStatus(){ - return sceUtilityHtmlViewerGetStatus(); -} - -int oslBrowserIsActive(){ - return browserIsActive; -} - -void oslEndBrowser(){ - sceKernelFreeVpl(vpl, params.memaddr); - sceKernelDeleteVpl(vpl); - browserIsActive = 0; -} +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "oslib.h" +#include "browser.h" + +#define BROWSER_MEMORY (10*1024*1024) + +static SceUID vpl; +static pspUtilityHtmlViewerParam params; +static int browserIsActive = 0; + +int oslBrowserInit(char *url, char *downloadDir, int browserMemory, unsigned int displaymode, unsigned int options, unsigned int interfacemode, unsigned int connectmode){ + int res; + if (browserMemory <= 0) + browserMemory = BROWSER_MEMORY; + + vpl = sceKernelCreateVpl("BrowserVpl", PSP_MEMORY_PARTITION_USER, 0, browserMemory + 256, NULL); + if (vpl < 0) + return OSL_BROWSER_ERROR_MEMORY; + + memset(¶ms, 0, sizeof(pspUtilityHtmlViewerParam)); + + params.base.size = sizeof(pspUtilityHtmlViewerParam); + + sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_LANGUAGE, ¶ms.base.language); + sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_UNKNOWN, ¶ms.base.buttonSwap); + + params.base.graphicsThread = 17; + params.base.accessThread = 19; + params.base.fontThread = 18; + params.base.soundThread = 16; + params.memsize = browserMemory; + params.initialurl = url; + params.numtabs = 1; + params.cookiemode = PSP_UTILITY_HTMLVIEWER_COOKIEMODE_DEFAULT; + params.homeurl = url; + params.textsize = PSP_UTILITY_HTMLVIEWER_TEXTSIZE_NORMAL; + params.displaymode = displaymode; + params.options = options; + params.interfacemode = interfacemode; + params.connectmode = connectmode; + + // WITHOUT 'ms0:' on the paths + params.dldirname = downloadDir; + + res = sceKernelAllocateVpl(vpl, params.memsize, ¶ms.memaddr, NULL); + if (res < 0) + return OSL_BROWSER_ERROR_MEMORY; + + res = sceUtilityHtmlViewerInitStart(¶ms); + if (res < 0) + return res; //<-- STAS: Such a return value is more informative... +// return OSL_BROWSER_ERROR_INIT; + + browserIsActive = 1; + return 0; +} + + +void oslDrawBrowser() +{ + switch (sceUtilityHtmlViewerGetStatus()){ + case PSP_UTILITY_DIALOG_INIT: + break; //<-- STAS: We shouldn't show the browser in its INIT status! + case PSP_UTILITY_DIALOG_VISIBLE: + sceGuFinish(); + sceGuSync(0,0); + sceUtilityHtmlViewerUpdate(1); + sceGuStart(GU_DIRECT, osl_list); + oslSetAlpha(OSL_FX_RGBA, 0xff); + break; + case PSP_UTILITY_DIALOG_QUIT: + sceUtilityHtmlViewerShutdownStart(); + break; + case PSP_UTILITY_DIALOG_NONE: + case PSP_UTILITY_DIALOG_FINISHED: + break; + } +} + + +int oslGetBrowserStatus(){ + return sceUtilityHtmlViewerGetStatus(); +} + +int oslBrowserIsActive(){ + return browserIsActive; +} + +void oslEndBrowser(){ + sceKernelFreeVpl(vpl, params.memaddr); + sceKernelDeleteVpl(vpl); + browserIsActive = 0; +} diff --git a/dialog.c b/dialog.c index f7cd424..f5df782 100644 --- a/dialog.c +++ b/dialog.c @@ -1,149 +1,201 @@ -#include -#include -#include -#include -#include -#include - -#include "oslib.h" -#include "dialog.h" - -pspUtilityMsgDialogParams dialog; -pspUtilityNetconfData netConf; -int dialogType = OSL_DIALOG_NONE; - -void ConfigureDialog(pspUtilityMsgDialogParams *inDialog, size_t dialog_size) -{ - memset(inDialog, 0, dialog_size); - - inDialog->base.size = dialog_size; - sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_LANGUAGE, - &inDialog->base.language); // Prompt language - sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_UNKNOWN, - &inDialog->base.buttonSwap); // X/O button swap - - inDialog->base.graphicsThread = 0x11; - inDialog->base.accessThread = 0x13; - inDialog->base.fontThread = 0x12; - inDialog->base.soundThread = 0x10; -} - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//Public API -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void oslInitMessageDialog(const char *message, int enableYesno){ - ConfigureDialog(&dialog, sizeof(dialog)); - dialog.mode = PSP_UTILITY_MSGDIALOG_MODE_TEXT; - dialog.options = PSP_UTILITY_MSGDIALOG_OPTION_TEXT; - - if(enableYesno) - dialog.options |= PSP_UTILITY_MSGDIALOG_OPTION_YESNO_BUTTONS|PSP_UTILITY_MSGDIALOG_OPTION_DEFAULT_NO; - - strcpy(dialog.message, message); - sceUtilityMsgDialogInitStart(&dialog); - dialogType = OSL_DIALOG_MESSAGE; -} - - -void oslInitErrorDialog(const unsigned int error) -{ - ConfigureDialog(&dialog, sizeof(dialog)); - dialog.mode = PSP_UTILITY_MSGDIALOG_MODE_ERROR; - dialog.options = PSP_UTILITY_MSGDIALOG_OPTION_ERROR; - dialog.errorValue = error; - - sceUtilityMsgDialogInitStart(&dialog); - dialogType = OSL_DIALOG_ERROR; -} - - -void oslInitNetDialog() -{ - memset(&netConf, 0, sizeof(netConf)); - netConf.base.size = sizeof(netConf); - sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_LANGUAGE, &netConf.base.language); - sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_UNKNOWN, &netConf.base.buttonSwap); - netConf.base.graphicsThread = 17; - netConf.base.accessThread = 19; - netConf.base.fontThread = 18; - netConf.base.soundThread = 16; - netConf.action = PSP_NETCONF_ACTION_CONNECTAP; - - struct pspUtilityNetconfAdhoc adhocparam; - memset(&adhocparam, 0, sizeof(adhocparam)); - netConf.adhocparam = &adhocparam; - - sceUtilityNetconfInitStart(&netConf); - dialogType = OSL_DIALOG_NETCONF; -} - - -int oslDialogGetResult(){ - if (dialogType == OSL_DIALOG_MESSAGE || dialogType == OSL_DIALOG_ERROR) - return dialog.base.result; - else if (dialogType == OSL_DIALOG_NETCONF) - return netConf.base.result; - return OSL_DIALOG_CANCEL; -} - -void oslDrawDialog() -{ - if (dialogType == OSL_DIALOG_MESSAGE || dialogType == OSL_DIALOG_ERROR){ - switch(sceUtilityMsgDialogGetStatus()) { - case PSP_UTILITY_DIALOG_INIT: - case PSP_UTILITY_DIALOG_VISIBLE: - sceGuFinish(); - sceGuSync(0,0); - sceUtilityMsgDialogUpdate(1); - sceGuStart(GU_DIRECT, osl_list); - oslSetAlpha(OSL_FX_RGBA, 0xff); - break; - case PSP_UTILITY_DIALOG_QUIT: - sceUtilityMsgDialogShutdownStart(); - break; - case PSP_UTILITY_DIALOG_NONE: - break; - } - }else if (dialogType == OSL_DIALOG_NETCONF){ - switch(sceUtilityNetconfGetStatus()){ - case PSP_UTILITY_DIALOG_INIT: - case PSP_UTILITY_DIALOG_VISIBLE: - sceGuFinish(); - sceGuSync(0,0); - sceUtilityNetconfUpdate(1); - sceGuStart(GU_DIRECT, osl_list); - oslSetAlpha(OSL_FX_RGBA, 0xff); - break; - case PSP_UTILITY_DIALOG_QUIT: - sceUtilityNetconfShutdownStart(); - break; - case PSP_UTILITY_DIALOG_NONE: - case PSP_UTILITY_DIALOG_FINISHED: - break; - } - } -} - - -int oslGetDialogType(){ - return dialogType; -} - - -int oslGetDialogStatus(){ - if (dialogType == OSL_DIALOG_MESSAGE || dialogType == OSL_DIALOG_ERROR) - return sceUtilityMsgDialogGetStatus(); - else if (dialogType == OSL_DIALOG_NETCONF) - return sceUtilityNetconfGetStatus(); - return PSP_UTILITY_DIALOG_NONE; -} - - -int oslGetDialogButtonPressed(){ - return dialog.buttonPressed; -} - -void oslEndDialog(){ - dialogType = OSL_DIALOG_NONE; -} +#include +#include +#include +#include +#include +#include + +#include "oslib.h" +#include "dialog.h" + +pspUtilityMsgDialogParams dialog; +pspUtilityNetconfData netConf; +int dialogType = OSL_DIALOG_NONE; + +void ConfigureDialog(pspUtilityMsgDialogParams *inDialog, size_t dialog_size) +{ + memset(inDialog, 0, dialog_size); + + inDialog->base.size = dialog_size; + sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_LANGUAGE, + &inDialog->base.language); // Prompt language + sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_UNKNOWN, + &inDialog->base.buttonSwap); // X/O button swap + + inDialog->base.graphicsThread = 0x11; + inDialog->base.accessThread = 0x13; + inDialog->base.fontThread = 0x12; + inDialog->base.soundThread = 0x10; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//Public API +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +int oslInitMessageDialog(const char *message, int enableYesno){ + ConfigureDialog(&dialog, sizeof(dialog)); + dialog.mode = PSP_UTILITY_MSGDIALOG_MODE_TEXT; + dialog.options = PSP_UTILITY_MSGDIALOG_OPTION_TEXT; + + if(enableYesno) + dialog.options |= PSP_UTILITY_MSGDIALOG_OPTION_YESNO_BUTTONS|PSP_UTILITY_MSGDIALOG_OPTION_DEFAULT_NO; + + strcpy(dialog.message, message); + int res = sceUtilityMsgDialogInitStart(&dialog); //<-- STAS: The error code shouldn't be ignored ! + if (!res) dialogType = OSL_DIALOG_MESSAGE; + return res; //<-- STAS END --> +} + + +int oslInitErrorDialog(const unsigned int error) +{ + ConfigureDialog(&dialog, sizeof(dialog)); + dialog.mode = PSP_UTILITY_MSGDIALOG_MODE_ERROR; + dialog.options = PSP_UTILITY_MSGDIALOG_OPTION_ERROR; + dialog.errorValue = error; + + int res = sceUtilityMsgDialogInitStart(&dialog); //<-- STAS: The error code shouldn't be ignored ! + if (!res) dialogType = OSL_DIALOG_ERROR; + return res; //<-- STAS END --> +} + + +int oslInitNetDialog() +{ + memset(&netConf, 0, sizeof(netConf)); + netConf.base.size = sizeof(netConf); + sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_LANGUAGE, &netConf.base.language); + sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_UNKNOWN, &netConf.base.buttonSwap); + netConf.base.graphicsThread = 17; + netConf.base.accessThread = 19; + netConf.base.fontThread = 18; + netConf.base.soundThread = 16; + netConf.action = PSP_NETCONF_ACTION_CONNECTAP; + + struct pspUtilityNetconfAdhoc adhocparam; + memset(&adhocparam, 0, sizeof(adhocparam)); + netConf.adhocparam = &adhocparam; + + int res = sceUtilityNetconfInitStart(&netConf); //<-- STAS: The error code shouldn't be ignored ! + if (!res) dialogType = OSL_DIALOG_NETCONF; + return res; //<-- STAS END --> +} + + +int oslDialogGetResult(){ + if (dialogType == OSL_DIALOG_MESSAGE || dialogType == OSL_DIALOG_ERROR) + return dialog.base.result; + else if (dialogType == OSL_DIALOG_NETCONF) + return netConf.base.result; + return OSL_DIALOG_CANCEL; +} + +void oslDrawDialog() +{ + if (dialogType == OSL_DIALOG_MESSAGE || dialogType == OSL_DIALOG_ERROR){ + switch(sceUtilityMsgDialogGetStatus()) { + case PSP_UTILITY_DIALOG_INIT: + case PSP_UTILITY_DIALOG_VISIBLE: + sceGuFinish(); + sceGuSync(0,0); + sceUtilityMsgDialogUpdate(1); + sceGuStart(GU_DIRECT, osl_list); + oslSetAlpha(OSL_FX_RGBA, 0xff); + break; + case PSP_UTILITY_DIALOG_QUIT: + sceUtilityMsgDialogShutdownStart(); + break; + case PSP_UTILITY_DIALOG_NONE: + break; + } + }else if (dialogType == OSL_DIALOG_NETCONF){ + switch(sceUtilityNetconfGetStatus()){ + case PSP_UTILITY_DIALOG_INIT: + case PSP_UTILITY_DIALOG_VISIBLE: + sceGuFinish(); + sceGuSync(0,0); + sceUtilityNetconfUpdate(1); + sceGuStart(GU_DIRECT, osl_list); + oslSetAlpha(OSL_FX_RGBA, 0xff); + break; + case PSP_UTILITY_DIALOG_QUIT: + sceUtilityNetconfShutdownStart(); + break; + case PSP_UTILITY_DIALOG_NONE: + case PSP_UTILITY_DIALOG_FINISHED: + break; + } + } +} + + +int oslGetDialogType(){ + return dialogType; +} + + +int oslGetDialogStatus(){ + if (dialogType == OSL_DIALOG_MESSAGE || dialogType == OSL_DIALOG_ERROR) + return sceUtilityMsgDialogGetStatus(); + else if (dialogType == OSL_DIALOG_NETCONF) + return sceUtilityNetconfGetStatus(); + return PSP_UTILITY_DIALOG_NONE; +} + + +int oslGetDialogButtonPressed(){ + return dialog.buttonPressed; +} + +void oslEndDialog(){ + dialogType = OSL_DIALOG_NONE; +} + +//<-- STAS: --> +int oslDialogDrawAndWait(int dialogType) { + int status = OSL_DIALOG_STATUS_INIT; + OSL_IMAGE* img = oslCreateImage(480, 272, OSL_IN_RAM, OSL_PF_8888); + + oslSyncDrawing(); + oslCopyImageTo(img, OSL_DEFAULT_BUFFER); // Save the currently drawn image + + while((status >= 0) && (status != OSL_DIALOG_STATUS_NONE) && !osl_quit) { + if (!oslSyncFrameEx(0,0,1)) { + oslStartDrawing(); + oslCopyImageTo(OSL_DEFAULT_BUFFER, img); // Restore the image drawn by the user app + + switch (dialogType) { + case OSL_DIALOG_MESSAGE: + case OSL_DIALOG_ERROR: + case OSL_DIALOG_NETCONF: + oslDrawDialog(); + status = oslGetDialogStatus(); + break; + case OSL_DIALOG_OSK: + oslDrawOsk(); + status = oslGetOskStatus(); + break; + case OSL_DIALOG_SAVELOAD: + oslDrawSaveLoad(); + status = oslGetLoadSaveStatus(); + break; + case OSL_DIALOG_BROWSER: + oslDrawBrowser(); + status = oslGetBrowserStatus(); + break; + } + + oslEndDrawing(); + } + oslEndFrame(); + } + + oslDeleteImage(img); + return (status < 0)? status : 0; +} + + +int oslDialogIsActive() { + return (dialogType != OSL_DIALOG_NONE); +} +//<-- STAS END --> diff --git a/dialog.h b/dialog.h index 47f512b..9f3342c 100644 --- a/dialog.h +++ b/dialog.h @@ -1,73 +1,92 @@ -#ifndef DIALOG_H -#define DIALOG_H - -/** @defgroup Dialogs - - Functions to display Sony's dialogs - @{ -*/ - -#define OSL_DIALOG_CANCEL 1 -#define OSL_DIALOG_OK 0 - -/**No dialog*/ -#define OSL_DIALOG_NONE 0 -/**Message dialog*/ -#define OSL_DIALOG_MESSAGE 1 -/**Error dialog*/ -#define OSL_DIALOG_ERROR 2 -/**Net conf dialog*/ -#define OSL_DIALOG_NETCONF 3 - -/**Initializes a Message Dialog - \param *message - Text shown in the message dialog - \param enableYesno - if 1 the dialog will have Yes/No option -*/ -void oslInitMessageDialog(const char *message, int enableYesno); - -/**Initializes an Error Dialog - \param error - Error code -*/ -void oslInitErrorDialog(const unsigned int error); - -/**Draws the current dialog to screen. -After drawing it you should check if the user closed it. Remember to call oslEndDialog. -\code -oslDrawDialog(); -if (oslGetDialogStatus() == PSP_UTILITY_DIALOG_NONE){ - //The user closed the dialog - oslEndDialog(); -} -\endcode -*/ -void oslDrawDialog(); - -/**Returns the current dialog type -*/ -int oslGetDialogType(); - -/**Returns the current dialog status -*/ -int oslGetDialogStatus(); - -/**Returns the button pressed in the dialog (only for message dialog with enableYesno == 1) -*/ -int oslGetDialogButtonPressed(); - -/**Initializes the net conf dialog -*/ -void oslInitNetDialog(); - -/**Gets the dialog result (OSL_DIALOG_CANCEL or OSL_DIALOG_OK) -*/ -int oslDialogGetResult(); - -/**Ends the current dialog -*/ -void oslEndDialog(); - -/** @} */ // end of dialog -#endif +#ifndef DIALOG_H +#define DIALOG_H + +/** @defgroup Dialogs + + Functions to display Sony's dialogs + @{ +*/ + +#define OSL_DIALOG_CANCEL 1 +#define OSL_DIALOG_OK 0 + +/**No dialog*/ +#define OSL_DIALOG_NONE 0 +/**Message dialog*/ +#define OSL_DIALOG_MESSAGE 1 +/**Error dialog*/ +#define OSL_DIALOG_ERROR 2 +/**Net conf dialog*/ +#define OSL_DIALOG_NETCONF 3 +//<-- STAS: another dialog types --> +#define OSL_DIALOG_OSK 4 +#define OSL_DIALOG_SAVELOAD 5 +#define OSL_DIALOG_BROWSER 6 + +/**Universal routine which draws the current dialog (of the given dialog type) + and waits for the user finish work with it. Returns 0 or ErrorCode (<0). +*/ +int oslDialogDrawAndWait(int dialogType); + +/**Tests whether any of ERROR,MESSAGE or NETCONF dialogs is currently active +*/ +int oslDialogIsActive(); +//<-- STAS END --> +#define OSL_DIALOG_STATUS_NONE PSP_UTILITY_DIALOG_NONE /**< No dialog is currently active */ +#define OSL_DIALOG_STATUS_INIT PSP_UTILITY_DIALOG_INIT /**< The dialog is currently being initialized */ +#define OSL_DIALOG_STATUS_VISIBLE PSP_UTILITY_DIALOG_VISIBLE /**< The dialog is visible and ready for use */ +#define OSL_DIALOG_STATUS_QUIT PSP_UTILITY_DIALOG_QUIT /**< The dialog has been canceled and should be shut down */ +#define OSL_DIALOG_STATUS_FINISHED PSP_UTILITY_DIALOG_FINISHED /**< The dialog has successfully shut down */ + +/**Initializes a Message Dialog + \param *message + Text shown in the message dialog + \param enableYesno + if 1 the dialog will have Yes/No option +*/ +int oslInitMessageDialog(const char *message, int enableYesno); + +/**Initializes an Error Dialog + \param error + Error code +*/ +int oslInitErrorDialog(const unsigned int error); + +/**Draws the current dialog to screen. +After drawing it you should check if the user closed it. Remember to call oslEndDialog. +\code +oslDrawDialog(); +if (oslGetDialogStatus() == PSP_UTILITY_DIALOG_NONE){ + //The user closed the dialog + oslEndDialog(); +} +\endcode +*/ +void oslDrawDialog(); + +/**Returns the current dialog type +*/ +int oslGetDialogType(); + +/**Returns the current dialog status +*/ +int oslGetDialogStatus(); + +/**Returns the button pressed in the dialog (only for message dialog with enableYesno == 1) +*/ +int oslGetDialogButtonPressed(); + +/**Initializes the net conf dialog +*/ +int oslInitNetDialog(); + +/**Gets the dialog result (OSL_DIALOG_CANCEL or OSL_DIALOG_OK) +*/ +int oslDialogGetResult(); + +/**Ends the current dialog +*/ +void oslEndDialog(); + +/** @} */ // end of dialog +#endif diff --git a/drawing.c b/drawing.c index 2b32673..559e325 100644 --- a/drawing.c +++ b/drawing.c @@ -1,473 +1,498 @@ -#include "oslib.h" - -#ifdef PSP -// unsigned int __attribute__((aligned(64))) osl_list[262144]; -#else -// unsigned int osl_list[262144]; -#endif -unsigned int *osl_list = NULL; -//unsigned char *osl_vMemPtr = (u8*)(0x04088000); -//unsigned short *g_vMemPtr = (void*)(0x00100000); -//unsigned long osl_temp_texture[8*8]; -//int osl_gradientTextureSampling=16; -void *osl_curTexture=NULL, *osl_curPalette=NULL; -//Remplacer par des defines? -//int osl_currentResolutionBPP=32, osl_currentPixelFormat=GU_PSM_8888; -void *osl_curDrawBuf = (void*)0, *osl_curDispBuf = (void*)0; -int osl_bilinearFilterEnabled, osl_ditheringEnabled, osl_isDrawingStarted=0; -int osl_currentAlphaEffect; -OSL_COLOR osl_currentAlphaCoeff, osl_currentAlphaCoeff2; -int osl_colorKeyEnabled, osl_colorKeyValue; -OSL_IMAGE osl_defaultBufferImage, osl_secondaryBufferImage, *osl_curBuf; -//Peut être mis à 0 pour gagner de la place, mais ce n'est pas garanti que tout fonctionne (particulièrement si le mode de texture n'est pas repeat). -int osl_alignBuffer = 3; -int osl_doubleBuffer=1; -int osl_textureEnabled = 1; -int osl_alphaTestEnabled = 0; -//ScePspFMatrix4 osl_matOrthoProjection, osl_matOrthoView, osl_matOrthoModel; -int osl_currentTexWrapU, osl_currentTexWrapV; - -const int osl_pixelWidth[] = {16, 16, 16, 32, 4, 8}; -//Taille des palettes (2^n) -const u8 osl_paletteSizes[]= { - 0, //16 bits - 0, //16 bits - 0, //16 bits - 0, //32 bits - 4, //4 bits - 8, //8 bits -}; - - -void oslSetAlpha2(u32 effect, u32 coeff1, u32 coeff2) { - int effet; - osl_currentAlphaEffect = effect | OSL_FX_COLOR; - if (effect > OSL_FX_NONE) { - effet = effect & ~OSL_FX_COLOR; - - if (effet == OSL_FX_RGBA) { - sceGuBlendFunc(GU_ADD,GU_SRC_ALPHA,GU_ONE_MINUS_SRC_ALPHA,0,0); - sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); - sceGuAmbientColor(0xffffffff); - osl_currentAlphaCoeff = 0xffffffff; - sceGuEnable(GU_BLEND); - return; - } - - if (!(effect & OSL_FX_COLOR)) - coeff1 = (coeff1 << 24) | 0xffffff; - - if (effet == OSL_FX_ALPHA) { //fxCoeff=0 -> transparent, fxCoeff=255 -> opaque - sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); - sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); - sceGuAmbientColor(coeff1); - osl_currentAlphaCoeff = coeff1; - } - else if (effet == OSL_FX_ADD) { //fxCoeff: opacité de l'objet, fxCoeffSrc: modifie la source - sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA,GU_FIX, 0, coeff2); - sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); - sceGuAmbientColor(coeff1); - osl_currentAlphaCoeff = coeff1; - osl_currentAlphaCoeff2 = coeff2; - } - else if (effet == OSL_FX_SUB) { //fxCoeff: opacité de l'objet, fxCoeffSrc: modifie la source - sceGuBlendFunc(GU_REVERSE_SUBTRACT, GU_SRC_ALPHA,GU_FIX, 0, coeff2); - sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); - sceGuAmbientColor(coeff1); - osl_currentAlphaCoeff = coeff1; - osl_currentAlphaCoeff2 = coeff2; - } - -/* if (effet == OSL_FX_FLAT) { - sceGuAlphaFunc(GU_GREATER, 0, 0xff); - sceGuEnable(GU_ALPHA_TEST); - sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); - sceGuAmbientColor(0xffffffff); - sceGuDisable(GU_BLEND); - } - else { - sceGuDisable(GU_ALPHA_TEST); - sceGuEnable(GU_BLEND); - }*/ - sceGuEnable(GU_BLEND); - } - else { - osl_currentAlphaCoeff = 0xffffffff; - sceGuDisable(GU_BLEND); - } -} - -void oslSetAlphaWrite(int action, int value1, int value2) { -#ifdef PSP - if (action == OSL_FXAW_SET) { - sceGuStencilFunc(GU_ALWAYS, value1, 0xff); - sceGuStencilOp(GU_KEEP, GU_REPLACE, GU_REPLACE); - sceGuEnable(GU_STENCIL_TEST); -// sceGuAlphaFunc(GU_NOTEQUAL, value2, 0xff); -// sceGuEnable(GU_ALPHA_TEST); - } - else if (action == OSL_FXAW_NONE) { - sceGuDisable(GU_STENCIL_TEST); -// sceGuDisable(GU_ALPHA_TEST); - } -#endif -} - - -void oslDisableTransparentColor() { - osl_colorKeyEnabled = 0; - sceGuDisable(GU_COLOR_TEST); -} - -void oslSetTransparentColor(OSL_COLOR color) { - osl_colorKeyEnabled = 1; - osl_colorKeyValue = color; -// sceGuColorFunc(GU_NOTEQUAL,0,0xffffffff); - sceGuColorFunc(GU_NOTEQUAL, color, 0xffffffff); - sceGuEnable(GU_COLOR_TEST); -} - - -int oslConvertColor(int pfDst, int pfSrc, int color) { - int r=0, g=0, b=0, a=0; - if (pfSrc == pfDst) - return color; - if (pfSrc == OSL_PF_8888) - oslRgbaGet8888(color, r, g, b, a); - else if (pfSrc == OSL_PF_5650) - oslRgbGet5650f(color, r, g, b), a = 0xff; - else if (pfSrc == OSL_PF_5551) - oslRgbaGet5551f(color, r, g, b, a); - else if (pfSrc == OSL_PF_4444) - oslRgbaGet4444f(color, r, g, b, a); - if (pfDst == OSL_PF_8888) - color = RGBA(r, g, b, a); - else if (pfDst == OSL_PF_5650) - color = RGB16(r, g, b); - else if (pfDst == OSL_PF_5551) - color = RGBA15(r, g, b, a); - else if (pfDst == OSL_PF_4444) - color = RGBA12(r, g, b, a); - return color; -} - -int oslConvertColorEx(OSL_PALETTE *p, int pfDst, int pfSrc, int color) { - int r=0, g=0, b=0, a=0; - - if (pfSrc == pfDst) - return color; - if (!p) - return oslConvertColor(pfDst, pfSrc, color); - - if (pfSrc == OSL_PF_8888) - oslRgbaGet8888(color, r, g, b, a); - else if (pfSrc == OSL_PF_5650) - oslRgbGet5650f(color, r, g, b), a = 0xff; - else if (pfSrc == OSL_PF_5551) - oslRgbaGet5551f(color, r, g, b, a); - else if (pfSrc == OSL_PF_4444) - oslRgbaGet4444f(color, r, g, b, a); - else if (pfSrc == OSL_PF_8BIT || pfSrc == OSL_PF_4BIT) - //Convert to a true color - color = oslConvertColor(OSL_PF_8888, p->pixelFormat, oslGetPaletteColor(p, color)); - - if (pfDst == OSL_PF_8888) - color = RGBA(r, g, b, a); - else if (pfDst == OSL_PF_5650) - color = RGB16(r, g, b); - else if (pfDst == OSL_PF_5551) - color = RGBA15(r, g, b, a); - else if (pfDst == OSL_PF_4444) - color = RGBA12(r, g, b, a); - else if (pfDst == OSL_PF_8BIT || pfDst == OSL_PF_4BIT) { - u32 i; - for (i=0;inElements;i++) { - //Is it the real palette color? - if (oslGetPaletteColor(p, i) == color) - return i; - } - } - - return color; -} - - -//Dessine une tile de la texture sélectionnée. Eviter d'utiliser à l'extérieur. - NOT USED ANYMORE -void oslDrawTile(int u, int v, int x, int y, int tX, int tY) -{ - OSL_FAST_VERTEX *vertices; - vertices = (OSL_FAST_VERTEX*)sceGuGetMemory(2 * sizeof(OSL_FAST_VERTEX)); - - vertices[0].u = u; - vertices[0].v = v; - vertices[0].x = x; - vertices[0].y = y; - vertices[0].z = 0; - - vertices[1].u = u+tX; - vertices[1].v = v+tY; - vertices[1].x = x+tX; - vertices[1].y = y+tY; - vertices[1].z = 0; - - sceGuDrawArray(GU_SPRITES,GU_TEXTURE_16BIT|GU_VERTEX_16BIT|GU_TRANSFORM_2D,2,0,vertices); -} - - - -void oslStartDrawing() { - //Dessin déjà commencé? - if (osl_isDrawingStarted) - return; - osl_isDrawingStarted = 1; - osl_curTexture = NULL; - osl_curPalette=NULL; - sceGuStart(GU_DIRECT, osl_list); - /*SAKYA */ - if (osl_intraInit){ - sceGumMatrixMode(GU_PROJECTION); - sceGumLoadIdentity(); - sceGumPerspective( 75.0f, 16.0f/9.0f, 0.5f, 1000.0f); - - sceGumMatrixMode(GU_VIEW); - sceGumLoadIdentity(); - - sceGumMatrixMode(GU_MODEL); - sceGumLoadIdentity(); - - sceGuClearColor(0xFF000000); - sceGuClearDepth(0); - sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT); - } - /*END SAKYA */ - oslSetAlpha(OSL_FX_RGBA, 0xff); -} - -void oslEndDrawing() { - if (!osl_isDrawingStarted) - return; - sceGuFinish(); - sceGuSync(0,0); - osl_isDrawingStarted = 0; -} - -void oslSyncDrawing() { - if (osl_isDrawingStarted) { - sceGuFinish(); - sceGuSync(0,0); - sceGuStart(GU_DIRECT,osl_list); - } -} - -void oslSetSysDisplayListSize(int newSize) { - //Ensure we're not dealing with the GPU! - oslEndDrawing(); - if (osl_list) - free(osl_list); - //This function can cause random crashes. - //osl_list = (unsigned int*)memalign(64, newSize); - osl_list = (unsigned int*)memalign(16, newSize); -} - -void oslInitGfx(int pixelFormat, int bDoubleBuffer) { - u8 *baseAdr; - bool alreadyInited = (osl_list != NULL); - - osl_doubleBuffer = bDoubleBuffer; -// osl_currentPixelFormat = pixelFormat; -// osl_currentResolutionBPP = osl_pixelWidth[pixelFormat]; - - if (!alreadyInited) { - oslSetupFTrigo(); - - //Allocate 1 Megabyte for the display list by default. Should be enough. - oslSetSysDisplayListSize(1 << 20); - //oslSetSysDisplayListSize((int)1024*1024*1.5); - - sceGuInit(); - } - - // setup - sceGuStart(GU_DIRECT, osl_list); - sceGuDisplay(0); - sceGuDrawBuffer(pixelFormat,(void*)0,512); - if (bDoubleBuffer) { - sceGuDispBuffer(480,272,(void*)((0x22000 * osl_pixelWidth[pixelFormat])>>3),512); - baseAdr = (u8*)(OSL_UVRAM_BASE + ((0x22000 * 2 * osl_pixelWidth[pixelFormat])>>3)); - - //Displaybuffer et drawbuffer initiaux - osl_curDrawBuf = (void*)OSL_UVRAM_BASE; - osl_curDispBuf = (void*)(OSL_UVRAM_BASE + ((0x22000 * osl_pixelWidth[pixelFormat])>>3)); - } - else { - sceGuDispBuffer(480,272,(void*)0,512); - baseAdr = (u8*)(OSL_UVRAM_BASE + ((0x22000 * osl_pixelWidth[pixelFormat])>>3)); - - //Displaybuffer et drawbuffer initiaux - osl_curDrawBuf = (void*)OSL_UVRAM_BASE; - osl_curDispBuf = osl_curDrawBuf; - } - - //SAKYA OLD - /*sceGuDepthBuffer((void*)0x110000, 512); - sceGuDepthRange(65535, 0); - sceGuDepthFunc(GU_GEQUAL); - //sceGuEnable(GU_DEPTH_TEST); - sceGuFrontFace(GU_CW); - //sceGuShadeModel(GU_SMOOTH); - sceGuEnable(GU_CULL_FACE); - sceGuEnable(GU_CLIP_PLANES); - sceGuEnable(GU_BLEND); - sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);*/ - //END SAKYA - - //SAKYA NEW - sceGuDepthBuffer((void*)0x110000, 512); - sceGuOffset(2048 - 480/2, 2048 - 272/2); - sceGuViewport(2048, 2048, 480, 272); - sceGuDepthRange(65535, 0); - sceGuScissor(0,0,480,272); - sceGuEnable(GU_SCISSOR_TEST); - sceGuDepthFunc(GU_GEQUAL); - sceGuDisable(GU_DEPTH_TEST); - sceGuFrontFace(GU_CW); - sceGuShadeModel(GU_SMOOTH); - sceGuEnable(GU_CULL_FACE); - sceGuEnable(GU_CLIP_PLANES); - sceGuEnable(GU_BLEND); - sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); - - sceGuEnable(GU_TEXTURE_2D), osl_textureEnabled = 1; - sceGuDisable(GU_ALPHA_TEST), osl_alphaTestEnabled = 0; - sceGuDisable(GU_DITHER), osl_ditheringEnabled = 0; - osl_bilinearFilterEnabled = 0; - oslSetTextureWrap(OSL_TW_REPEAT, OSL_TW_REPEAT); - //END SAKYA - - - //Initialise le gestionnaire de VRAM - oslVramMgrInit(); - //Définit le début de la VRAM - oslVramMgrSetParameters((void*)baseAdr, (u32)OSL_UVRAM_END - (u32)baseAdr); - - /*sceGuDisable(GU_DEPTH_TEST); - sceGuScissor(0,0,480,272); - sceGuEnable(GU_SCISSOR_TEST); - sceGuEnable(GU_TEXTURE_2D), osl_textureEnabled = 1; - sceGuDisable(GU_ALPHA_TEST), osl_alphaTestEnabled = 0; - sceGuTexFilter(GU_NEAREST,GU_NEAREST); - sceGuShadeModel(GU_SMOOTH); - sceGuDisable(GU_DITHER), osl_ditheringEnabled = 0; - osl_bilinearFilterEnabled = 0; - oslSetTextureWrap(OSL_TW_REPEAT, OSL_TW_REPEAT);*/ - - osl_isDrawingStarted = 0; - - sceGuFinish(); - sceGuSync(0,0); - - sceDisplayWaitVblankStart(); - sceGuDisplay(1); - - //Remplit l'image par défaut (informations en lecture seule) - memset(&osl_defaultBufferImage, 0, sizeof(osl_defaultBufferImage)); - osl_defaultBufferImage.sizeX = 480; - osl_defaultBufferImage.sizeY = 272; - osl_defaultBufferImage.realSizeX = 512; - osl_defaultBufferImage.realSizeY = 272; - osl_defaultBufferImage.pixelFormat = pixelFormat; - osl_defaultBufferImage.location = OSL_IN_VRAM; - osl_defaultBufferImage.data = osl_curDrawBuf; - osl_defaultBufferImage.sysSizeX = 512; - osl_defaultBufferImage.sysSizeY = 512; - osl_defaultBufferImage.totalSize = (0x22000 * osl_pixelWidth[pixelFormat])>>3; - oslSetImageTile(&osl_defaultBufferImage, 0,0, 480,272); - osl_curBuf = &osl_defaultBufferImage; - //Le buffer secondaire est identique, à un détail près (le buffer) - memcpy(&osl_secondaryBufferImage, &osl_defaultBufferImage, sizeof(osl_secondaryBufferImage)); - osl_secondaryBufferImage.data = osl_curDispBuf; - //A partir d'ici, on peut afficher des messages (fatal error et cie) - oslStartDrawing(); - oslSetAlpha(OSL_FX_RGBA, 0); - - if (!alreadyInited) - oslInitConsole(); - -} - - -void oslSwapBuffers() -{ - //Seulement si le double buffer est activé - if (osl_doubleBuffer) { - oslSetDrawBuffer(OSL_DEFAULT_BUFFER); -#ifdef PSP - osl_curDispBuf = osl_defaultBufferImage.data; - osl_secondaryBufferImage.data = osl_curDispBuf; - osl_curDrawBuf = oslAddVramPrefixPtr(sceGuSwapBuffers()); -#else - //Sur PC, rien de tout ça - oslGetUncachedPtr(sceGuSwapBuffers()); -#endif - } - //Met à jour l'image, assumant qu'il n'y a que l'adresse qui change entre les deux buffers - osl_defaultBufferImage.data = osl_curDrawBuf; -} - - -void oslSetBilinearFilter(int enabled) -{ - osl_bilinearFilterEnabled = enabled; - sceGuTexFilter(enabled?GU_LINEAR:GU_NEAREST, enabled?GU_LINEAR:GU_NEAREST); -} - -void oslSetDithering(int enabled) -{ - osl_ditheringEnabled = enabled; - if (enabled) - sceGuEnable(GU_DITHER); - else - sceGuDisable(GU_DITHER); -} - -void oslSetAlphaTest(int condition, int value) { - if (!osl_alphaTestEnabled) { - sceGuAlphaFunc(condition, value, 0xff); - sceGuEnable(GU_ALPHA_TEST); - } - osl_alphaTestEnabled = 1; -} - -void oslDisableAlphaTest() { - if (osl_alphaTestEnabled) - sceGuDisable(GU_ALPHA_TEST); - osl_alphaTestEnabled = 0; -} - -void oslClearScreen(int backColor) { - sceGuClearColor(backColor); - sceGuClear(GU_COLOR_BUFFER_BIT); -} - - -void oslSetScreenClipping(int x0, int y0, int x1, int y1) { - sceGuScissor(x0, y0, x1, y1); - sceGuEnable(GU_SCISSOR_TEST); -} - -void oslEndGfx() -{ - sceGuTerm(); - - if (osl_list) - free(osl_list); -} - - -void oslSetDepthTest(int enabled){ - if (enabled) - sceGuEnable(GU_DEPTH_TEST); - else - sceGuDisable(GU_DEPTH_TEST); - osl_alphaTestEnabled = enabled; -} +#include "oslib.h" + +#ifdef PSP +// unsigned int __attribute__((aligned(64))) osl_list[262144]; +#else +// unsigned int osl_list[262144]; +#endif +unsigned int *osl_list = NULL; +//unsigned char *osl_vMemPtr = (u8*)(0x04088000); +//unsigned short *g_vMemPtr = (void*)(0x00100000); +//unsigned long osl_temp_texture[8*8]; +//int osl_gradientTextureSampling=16; +void *osl_curTexture=NULL, *osl_curPalette=NULL; +//Remplacer par des defines? +//int osl_currentResolutionBPP=32, osl_currentPixelFormat=GU_PSM_8888; +void *osl_curDrawBuf = (void*)0, *osl_curDispBuf = (void*)0; +int osl_bilinearFilterEnabled, osl_ditheringEnabled, osl_isDrawingStarted=0; +int osl_currentAlphaEffect; +OSL_COLOR osl_currentAlphaCoeff, osl_currentAlphaCoeff2; +int osl_colorKeyEnabled, osl_colorKeyValue; +OSL_IMAGE osl_defaultBufferImage, osl_secondaryBufferImage, *osl_curBuf; +//Peut être mis à 0 pour gagner de la place, mais ce n'est pas garanti que tout fonctionne (particulièrement si le mode de texture n'est pas repeat). +int osl_alignBuffer = 3; +int osl_doubleBuffer=1; +int osl_textureEnabled = 1; +int osl_alphaTestEnabled = 0; +//ScePspFMatrix4 osl_matOrthoProjection, osl_matOrthoView, osl_matOrthoModel; +int osl_currentTexWrapU, osl_currentTexWrapV; + +const int osl_pixelWidth[] = {16, 16, 16, 32, 4, 8}; +//Taille des palettes (2^n) +const u8 osl_paletteSizes[]= { + 0, //16 bits + 0, //16 bits + 0, //16 bits + 0, //32 bits + 4, //4 bits + 8, //8 bits +}; + + +void oslSetAlpha2(u32 effect, u32 coeff1, u32 coeff2) { + int effet; + osl_currentAlphaEffect = effect | OSL_FX_COLOR; + if (effect > OSL_FX_NONE) { + effet = effect & ~OSL_FX_COLOR; + + if (effet == OSL_FX_RGBA) { + sceGuBlendFunc(GU_ADD,GU_SRC_ALPHA,GU_ONE_MINUS_SRC_ALPHA,0,0); + sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); + sceGuAmbientColor(0xffffffff); + osl_currentAlphaCoeff = 0xffffffff; + sceGuEnable(GU_BLEND); + return; + } + + if (!(effect & OSL_FX_COLOR)) + coeff1 = (coeff1 << 24) | 0xffffff; + + if (effet == OSL_FX_ALPHA) { //fxCoeff=0 -> transparent, fxCoeff=255 -> opaque + sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); + sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); + sceGuAmbientColor(coeff1); + osl_currentAlphaCoeff = coeff1; + } + else if (effet == OSL_FX_ADD) { //fxCoeff: opacité de l'objet, fxCoeffSrc: modifie la source + sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA,GU_FIX, 0, coeff2); + sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); + sceGuAmbientColor(coeff1); + osl_currentAlphaCoeff = coeff1; + osl_currentAlphaCoeff2 = coeff2; + } + else if (effet == OSL_FX_SUB) { //fxCoeff: opacité de l'objet, fxCoeffSrc: modifie la source + sceGuBlendFunc(GU_REVERSE_SUBTRACT, GU_SRC_ALPHA,GU_FIX, 0, coeff2); + sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); + sceGuAmbientColor(coeff1); + osl_currentAlphaCoeff = coeff1; + osl_currentAlphaCoeff2 = coeff2; + } + +/* if (effet == OSL_FX_FLAT) { + sceGuAlphaFunc(GU_GREATER, 0, 0xff); + sceGuEnable(GU_ALPHA_TEST); + sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA); + sceGuAmbientColor(0xffffffff); + sceGuDisable(GU_BLEND); + } + else { + sceGuDisable(GU_ALPHA_TEST); + sceGuEnable(GU_BLEND); + }*/ + sceGuEnable(GU_BLEND); + } + else { + osl_currentAlphaCoeff = 0xffffffff; + sceGuDisable(GU_BLEND); + } +} + +void oslSetAlphaWrite(int action, int value1, int value2) { +#ifdef PSP + if (action == OSL_FXAW_SET) { + sceGuStencilFunc(GU_ALWAYS, value1, 0xff); + sceGuStencilOp(GU_KEEP, GU_REPLACE, GU_REPLACE); + sceGuEnable(GU_STENCIL_TEST); +// sceGuAlphaFunc(GU_NOTEQUAL, value2, 0xff); +// sceGuEnable(GU_ALPHA_TEST); + } + else if (action == OSL_FXAW_NONE) { + sceGuDisable(GU_STENCIL_TEST); +// sceGuDisable(GU_ALPHA_TEST); + } +#endif +} + + +void oslDisableTransparentColor() { + osl_colorKeyEnabled = 0; + sceGuDisable(GU_COLOR_TEST); +} + +void oslSetTransparentColor(OSL_COLOR color) { + osl_colorKeyEnabled = 1; + osl_colorKeyValue = color; +// sceGuColorFunc(GU_NOTEQUAL,0,0xffffffff); + sceGuColorFunc(GU_NOTEQUAL, color, 0xffffffff); + sceGuEnable(GU_COLOR_TEST); +} + + +int oslConvertColor(int pfDst, int pfSrc, int color) { + int r=0, g=0, b=0, a=0; + if (pfSrc == pfDst) + return color; + if (pfSrc == OSL_PF_8888) + oslRgbaGet8888(color, r, g, b, a); + else if (pfSrc == OSL_PF_5650) + oslRgbGet5650f(color, r, g, b), a = 0xff; + else if (pfSrc == OSL_PF_5551) + oslRgbaGet5551f(color, r, g, b, a); + else if (pfSrc == OSL_PF_4444) + oslRgbaGet4444f(color, r, g, b, a); + if (pfDst == OSL_PF_8888) + color = RGBA(r, g, b, a); + else if (pfDst == OSL_PF_5650) + color = RGB16(r, g, b); + else if (pfDst == OSL_PF_5551) + color = RGBA15(r, g, b, a); + else if (pfDst == OSL_PF_4444) + color = RGBA12(r, g, b, a); + return color; +} + +int oslConvertColorEx(OSL_PALETTE *p, int pfDst, int pfSrc, int color) { + int r=0, g=0, b=0, a=0; + + if (pfSrc == pfDst) + return color; + if (!p) + return oslConvertColor(pfDst, pfSrc, color); + + if (pfSrc == OSL_PF_8888) + oslRgbaGet8888(color, r, g, b, a); + else if (pfSrc == OSL_PF_5650) + oslRgbGet5650f(color, r, g, b), a = 0xff; + else if (pfSrc == OSL_PF_5551) + oslRgbaGet5551f(color, r, g, b, a); + else if (pfSrc == OSL_PF_4444) + oslRgbaGet4444f(color, r, g, b, a); + else if (pfSrc == OSL_PF_8BIT || pfSrc == OSL_PF_4BIT) + //Convert to a true color + color = oslConvertColor(OSL_PF_8888, p->pixelFormat, oslGetPaletteColor(p, color)); + + if (pfDst == OSL_PF_8888) + color = RGBA(r, g, b, a); + else if (pfDst == OSL_PF_5650) + color = RGB16(r, g, b); + else if (pfDst == OSL_PF_5551) + color = RGBA15(r, g, b, a); + else if (pfDst == OSL_PF_4444) + color = RGBA12(r, g, b, a); + else if (pfDst == OSL_PF_8BIT || pfDst == OSL_PF_4BIT) { + u32 i; + for (i=0;inElements;i++) { + //Is it the real palette color? + if (oslGetPaletteColor(p, i) == color) + return i; + } + } + + return color; +} + + +//Dessine une tile de la texture sélectionnée. Eviter d'utiliser à l'extérieur. - NOT USED ANYMORE +void oslDrawTile(int u, int v, int x, int y, int tX, int tY) +{ + OSL_FAST_VERTEX *vertices; + vertices = (OSL_FAST_VERTEX*)sceGuGetMemory(2 * sizeof(OSL_FAST_VERTEX)); + + vertices[0].u = u; + vertices[0].v = v; + vertices[0].x = x; + vertices[0].y = y; + vertices[0].z = 0; + + vertices[1].u = u+tX; + vertices[1].v = v+tY; + vertices[1].x = x+tX; + vertices[1].y = y+tY; + vertices[1].z = 0; + + sceGuDrawArray(GU_SPRITES,GU_TEXTURE_16BIT|GU_VERTEX_16BIT|GU_TRANSFORM_2D,2,0,vertices); +} + + + +void oslStartDrawing() { + //Dessin déjà commencé? + if (osl_isDrawingStarted) + return; + osl_isDrawingStarted = 1; + osl_curTexture = NULL; + osl_curPalette=NULL; + sceGuStart(GU_DIRECT, osl_list); +#if 0 //<-- STAS: In fact this is not needed for intraFont to work (see graphics.c in intrafont_0.31/samples/graphics). + // Furthermore, all this stuff is not good here because it could interfere with the user application ! + /*SAKYA */ + if (osl_intraInit){ + sceGumMatrixMode(GU_PROJECTION); + sceGumLoadIdentity(); + sceGumPerspective( 75.0f, 16.0f/9.0f, 0.5f, 1000.0f); + + sceGumMatrixMode(GU_VIEW); + sceGumLoadIdentity(); + + sceGumMatrixMode(GU_MODEL); + sceGumLoadIdentity(); + + sceGuClearColor(0xFF000000); + sceGuClearDepth(0); + sceGuClear(GU_COLOR_BUFFER_BIT|GU_DEPTH_BUFFER_BIT); + } + /*END SAKYA */ +#endif //<-- STAS END --> + oslSetAlpha(OSL_FX_RGBA, 0xff); +} + +void oslEndDrawing() { + if (!osl_isDrawingStarted) + return; + sceGuFinish(); + sceGuSync(0,0); + osl_isDrawingStarted = 0; +} + +void oslSyncDrawing() { + if (osl_isDrawingStarted) { + sceGuFinish(); + sceGuSync(0,0); + sceGuStart(GU_DIRECT,osl_list); + } +} + +void oslSetSysDisplayListSize(int newSize) { + //Ensure we're not dealing with the GPU! + oslEndDrawing(); + if (osl_list) + free(osl_list); + //This function can cause random crashes. + //osl_list = (unsigned int*)memalign(64, newSize); + osl_list = (unsigned int*)memalign(16, newSize); +} + +void oslInitGfx(int pixelFormat, int bDoubleBuffer) { + u8 *baseAdr; + bool alreadyInited = (osl_list != NULL); + + osl_doubleBuffer = bDoubleBuffer; +// osl_currentPixelFormat = pixelFormat; +// osl_currentResolutionBPP = osl_pixelWidth[pixelFormat]; + + if (!alreadyInited) { + oslSetupFTrigo(); + + //Allocate 1 Megabyte for the display list by default. Should be enough. + oslSetSysDisplayListSize(1 << 20); + //oslSetSysDisplayListSize((int)1024*1024*1.5); + + sceGuInit(); + } + + // setup + sceGuStart(GU_DIRECT, osl_list); + sceGuDisplay(0); + sceGuDrawBuffer(pixelFormat,(void*)0,512); + if (bDoubleBuffer) { + sceGuDispBuffer(480,272,(void*)((0x22000 * osl_pixelWidth[pixelFormat])>>3),512); + baseAdr = (u8*)(OSL_UVRAM_BASE + ((0x22000 * 2 * osl_pixelWidth[pixelFormat])>>3)); + + //Displaybuffer et drawbuffer initiaux + osl_curDrawBuf = (void*)OSL_UVRAM_BASE; + osl_curDispBuf = (void*)(OSL_UVRAM_BASE + ((0x22000 * osl_pixelWidth[pixelFormat])>>3)); + } + else { + sceGuDispBuffer(480,272,(void*)0,512); + baseAdr = (u8*)(OSL_UVRAM_BASE + ((0x22000 * osl_pixelWidth[pixelFormat])>>3)); + + //Displaybuffer et drawbuffer initiaux + osl_curDrawBuf = (void*)OSL_UVRAM_BASE; + osl_curDispBuf = osl_curDrawBuf; + } + + //SAKYA OLD + /*sceGuDepthBuffer((void*)0x110000, 512); + sceGuDepthRange(65535, 0); + sceGuDepthFunc(GU_GEQUAL); + //sceGuEnable(GU_DEPTH_TEST); + sceGuFrontFace(GU_CW); + //sceGuShadeModel(GU_SMOOTH); + sceGuEnable(GU_CULL_FACE); + sceGuEnable(GU_CLIP_PLANES); + sceGuEnable(GU_BLEND); + sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);*/ + //END SAKYA + + //SAKYA NEW + //<-- STAS --> +// sceGuDepthBuffer((void*)0x110000, 512); // Absolute address is not good here ! + sceGuDepthBuffer((void*)((u32)baseAdr - (u32)OSL_UVRAM_BASE), 512); + baseAdr = (u8*)((u32)baseAdr + 0x22000 * 2); // Add the Depth Buffer length + //<-- STAS END --> + sceGuOffset(2048 - 480/2, 2048 - 272/2); + sceGuViewport(2048, 2048, 480, 272); + sceGuDepthRange(65535, 0); + sceGuScissor(0,0,480,272); + sceGuEnable(GU_SCISSOR_TEST); + sceGuDepthFunc(GU_GEQUAL); + sceGuDisable(GU_DEPTH_TEST); + sceGuFrontFace(GU_CW); + sceGuShadeModel(GU_SMOOTH); + sceGuEnable(GU_CULL_FACE); + sceGuEnable(GU_CLIP_PLANES); + sceGuEnable(GU_BLEND); + sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); + + sceGuEnable(GU_TEXTURE_2D), osl_textureEnabled = 1; + sceGuDisable(GU_ALPHA_TEST), osl_alphaTestEnabled = 0; + sceGuDisable(GU_DITHER), osl_ditheringEnabled = 0; + osl_bilinearFilterEnabled = 0; + oslSetTextureWrap(OSL_TW_REPEAT, OSL_TW_REPEAT); + //END SAKYA + + + //Initialise le gestionnaire de VRAM + oslVramMgrInit(); + //Définit le début de la VRAM + oslVramMgrSetParameters((void*)baseAdr, (u32)OSL_UVRAM_END - (u32)baseAdr); + + /*sceGuDisable(GU_DEPTH_TEST); + sceGuScissor(0,0,480,272); + sceGuEnable(GU_SCISSOR_TEST); + sceGuEnable(GU_TEXTURE_2D), osl_textureEnabled = 1; + sceGuDisable(GU_ALPHA_TEST), osl_alphaTestEnabled = 0; + sceGuTexFilter(GU_NEAREST,GU_NEAREST); + sceGuShadeModel(GU_SMOOTH); + sceGuDisable(GU_DITHER), osl_ditheringEnabled = 0; + osl_bilinearFilterEnabled = 0; + oslSetTextureWrap(OSL_TW_REPEAT, OSL_TW_REPEAT);*/ + + osl_isDrawingStarted = 0; + + sceGuFinish(); + sceGuSync(0,0); + + sceDisplayWaitVblankStart(); + sceGuDisplay(1); + + //Remplit l'image par défaut (informations en lecture seule) + memset(&osl_defaultBufferImage, 0, sizeof(osl_defaultBufferImage)); + osl_defaultBufferImage.sizeX = 480; + osl_defaultBufferImage.sizeY = 272; + osl_defaultBufferImage.realSizeX = 512; + osl_defaultBufferImage.realSizeY = 272; + osl_defaultBufferImage.pixelFormat = pixelFormat; + osl_defaultBufferImage.location = OSL_IN_VRAM; + osl_defaultBufferImage.data = osl_curDrawBuf; + osl_defaultBufferImage.sysSizeX = 512; + osl_defaultBufferImage.sysSizeY = 512; + osl_defaultBufferImage.totalSize = (0x22000 * osl_pixelWidth[pixelFormat])>>3; + oslSetImageTile(&osl_defaultBufferImage, 0,0, 480,272); + osl_curBuf = &osl_defaultBufferImage; + //Le buffer secondaire est identique, à un détail près (le buffer) + memcpy(&osl_secondaryBufferImage, &osl_defaultBufferImage, sizeof(osl_secondaryBufferImage)); + osl_secondaryBufferImage.data = osl_curDispBuf; + //A partir d'ici, on peut afficher des messages (fatal error et cie) + oslStartDrawing(); + oslSetAlpha(OSL_FX_RGBA, 0); + + if (!alreadyInited) + oslInitConsole(); + +} + +#if 0 //<-- STAS: this algorithm has different side effects for single and double buffering modes +void oslSwapBuffers() +{ + //Seulement si le double buffer est activé + if (osl_doubleBuffer) { + oslSetDrawBuffer(OSL_DEFAULT_BUFFER); +#ifdef PSP + osl_curDispBuf = osl_defaultBufferImage.data; + osl_secondaryBufferImage.data = osl_curDispBuf; + osl_curDrawBuf = oslAddVramPrefixPtr(sceGuSwapBuffers()); +#else + //Sur PC, rien de tout ça + oslGetUncachedPtr(sceGuSwapBuffers()); +#endif + } + //Met à jour l'image, assumant qu'il n'y a que l'adresse qui change entre les deux buffers + osl_defaultBufferImage.data = osl_curDrawBuf; +} + +#else //<-- STAS: much more simple and clear one... --> +void oslSwapBuffers() +{ + if (osl_curBuf != OSL_DEFAULT_BUFFER) // Reset the user's draw buffer to OSL_DEFAULT_BUFFER + oslSetDrawBuffer(OSL_DEFAULT_BUFFER); + osl_curDispBuf = osl_curDrawBuf; // The current draw buffer will be the display one + + if (osl_doubleBuffer) { // Get the new draw buffer pointer +#ifdef PSP + osl_curDrawBuf = oslAddVramPrefixPtr(sceGuSwapBuffers()); +#else + osl_curDrawBuf = oslGetUncachedPtr(sceGuSwapBuffers()); +#endif + } + osl_defaultBufferImage.data = osl_curDrawBuf; // Setup DEFAULT data ptr + osl_secondaryBufferImage.data = osl_curDispBuf; // Setup SECONDARY data ptr +} +#endif + +void oslSetBilinearFilter(int enabled) +{ + osl_bilinearFilterEnabled = enabled; + sceGuTexFilter(enabled?GU_LINEAR:GU_NEAREST, enabled?GU_LINEAR:GU_NEAREST); +} + +void oslSetDithering(int enabled) +{ + osl_ditheringEnabled = enabled; + if (enabled) + sceGuEnable(GU_DITHER); + else + sceGuDisable(GU_DITHER); +} + +void oslSetAlphaTest(int condition, int value) { + if (!osl_alphaTestEnabled) { + sceGuAlphaFunc(condition, value, 0xff); + sceGuEnable(GU_ALPHA_TEST); + } + osl_alphaTestEnabled = 1; +} + +void oslDisableAlphaTest() { + if (osl_alphaTestEnabled) + sceGuDisable(GU_ALPHA_TEST); + osl_alphaTestEnabled = 0; +} + +void oslClearScreen(int backColor) { + sceGuClearColor(backColor); + sceGuClear(GU_COLOR_BUFFER_BIT); +} + + +void oslSetScreenClipping(int x0, int y0, int x1, int y1) { + sceGuScissor(x0, y0, x1, y1); + sceGuEnable(GU_SCISSOR_TEST); +} + +void oslEndGfx() +{ + sceGuTerm(); + + if (osl_list) + free(osl_list); +} + + +void oslSetDepthTest(int enabled){ + if (enabled) + sceGuEnable(GU_DEPTH_TEST); + else + sceGuDisable(GU_DEPTH_TEST); + osl_alphaTestEnabled = enabled; +} diff --git a/libosl.a b/libosl.a index 2cd5cdf..de783fc 100644 Binary files a/libosl.a and b/libosl.a differ diff --git a/mikmod/Makefile b/mikmod/Makefile new file mode 100644 index 0000000..898a1dd --- /dev/null +++ b/mikmod/Makefile @@ -0,0 +1,41 @@ +# MikMod Library Makefile for DJGPP Linux +# Divine Entertainment Game Programming Pack + + +#################### +### User Options ### +#################### + +# Use the C or C++ compiler +CC = gcc +CFLAGS = -O2 -I. -I../include -g -DOSS + +Lib_file = ../lib/libmikmod.a + +LoaderObjs = mloader.o mlreg.o npertab.o sloader.o load_uni.o \ + load_mod.o load_m15.o load_mtm.o load_s3m.o load_stm.o load_669.o \ + load_far.o load_dsm.o load_med.o load_xm.o load_ult.o load_it.o \ + s3m_it.o + +DriverObjs = mdriver.o mdreg.o drv_nos.o drv_raw.o drv_wav.o \ + unix_drv/drv_oss.o +# unix_drv/drv_AF.o unix_drv/drv_aix.o unix_drv/drv_hp.o +# unix_drv/drv_sun.o unix_drv/drv_sgi.o + +PlayerObjs = mplayer.o + +#################### +## Makefile rules ## +#################### + +all: $(Lib_file) + +$(Lib_file): stream.o virtch.o munitrk.o \ + $(LoaderObjs) $(DriverObjs) $(PlayerObjs) + ar r $(Lib_file) stream.o virtch.o munitrk.o \ + $(LoaderObjs) $(PlayerObjs) $(DriverObjs) + +clean: + rm -f *.o + rm -f unix_drv/*.o + rm -f $(Lib_file) diff --git a/mikmod/drv_nos.c b/mikmod/drv_nos.c new file mode 100644 index 0000000..1d84301 --- /dev/null +++ b/mikmod/drv_nos.c @@ -0,0 +1,160 @@ +/* + +Name: +DRV_NOS.C + +Description: +Mikmod driver for no output on any soundcard, monitor, keyboard, or whatever :) + +Portability: +All systems - All compilers + +*/ + +#include "mikmod.h" + + +static BOOL NS_IsThere(void) +{ + return 1; +} + + +static SWORD NS_SampleLoad(SAMPLOAD *s, int type, VIRTUAL_FILE *fp) +{ + return 0; +} + + +static void NS_SampleUnload(SWORD h) +{ +} + + +static ULONG NS_SampleSpace(int type) +{ + return 0; +} + + +static ULONG NS_SampleLength(int type, SAMPLE *s) +{ + return s->length; +} + + +static BOOL NS_Init(void) +{ + return 0; +} + + +static void NS_Exit(void) +{ +} + + +static BOOL NS_Reset(void) +{ + return 0; +} + + +static BOOL NS_PlayStart(void) +{ +} + + +static void NS_PlayStop(void) +{ +} + + +static void NS_Update(void) +{ +} + + +static BOOL NS_SetNumVoices(void) +{ + return 0; +} + + +static void NS_VoiceSetVolume(UBYTE voice,UWORD vol) +{ +} + + +static void NS_VoiceSetFrequency(UBYTE voice,ULONG frq) +{ +} + + +static void NS_VoiceSetPanning(UBYTE voice,ULONG pan) +{ +} + + +static void NS_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags) +{ +} + + +static void NS_VoiceStop(UBYTE voice) +{ +} + + +static BOOL NS_VoiceStopped(UBYTE voice) +{ + return 0; +} + + +static void NS_VoiceReleaseSustain(UBYTE voice) +{ +} + + +static SLONG NS_VoiceGetPosition(UBYTE voice) +{ + return 0; +} + + +static ULONG NS_VoiceRealVolume(UBYTE voice) +{ + return 0; +} + + + +MDRIVER drv_nos = +{ NULL, + "No Sound", + "Nosound Driver v2.0 - (c) Creative Silence", + 255,255, + NS_IsThere, + NS_SampleLoad, + NS_SampleUnload, + NS_SampleSpace, + NS_SampleLength, + NS_Init, + NS_Exit, + NS_Reset, + NS_SetNumVoices, + NS_PlayStart, + NS_PlayStop, + NS_Update, + NS_VoiceSetVolume, + NS_VoiceSetFrequency, + NS_VoiceSetPanning, + NS_VoicePlay, + NS_VoiceStop, + NS_VoiceStopped, + NS_VoiceReleaseSustain, + NS_VoiceGetPosition, + NS_VoiceRealVolume +}; + diff --git a/mikmod/drv_raw.c b/mikmod/drv_raw.c new file mode 100644 index 0000000..511f862 --- /dev/null +++ b/mikmod/drv_raw.c @@ -0,0 +1,112 @@ +/* + +Name: +DRV_RAW.C + +Description: +Mikmod driver for output to a file called MUSIC.RAW + +MS-DOS Programmers: + !! DO NOT CALL MD_UPDATE FROM A INTERRUPT IF YOU USE THIS DRIVER !! + +Portability: + +MSDOS: BC(y) Watcom(y) DJGPP(y) +Win95: BC(y) +Linux: y +SGI: CC(y) GCC(y) + +(y) - yes +(n) - no (not possible or not useful) +(?) - may be possible, but not tested + +*/ + +#include "mikmod.h" + +#if (defined(__GNUC__) || defined(SGI)) +#include +#else +#include +#endif +#include +#include + +#define RAWBUFFERSIZE 8192 + +static int rawout; + +static SBYTE RAW_DMABUF[RAWBUFFERSIZE]; + + +static BOOL RAW_IsThere(void) +{ + return 1; +} + + +static BOOL RAW_Init(void) +{ + if(-1 == (rawout = open("music.raw", +#if (!defined(__GNUC__) && (!defined(SGI))) + O_BINARY | +#endif + O_RDWR | O_TRUNC | O_CREAT, S_IREAD | S_IWRITE))) + return 1; + + md_mode |= DMODE_SOFT_MUSIC | DMODE_SOFT_SNDFX; + + if(VC_Init()) return 1; + + return 0; +} + + +static void RAW_Exit(void) +{ + VC_Exit(); + close(rawout); +} + + +static void RAW_Update(void) +{ + VC_WriteBytes(RAW_DMABUF, RAWBUFFERSIZE); + write(rawout, RAW_DMABUF, RAWBUFFERSIZE); +} + + +static BOOL RAW_Reset(void) +{ + return 0; +} + + +MDRIVER drv_raw = +{ NULL, + "music.raw file", + "RAW [music.raw] file output driver v1.0", + 0,255, + RAW_IsThere, + VC_SampleLoad, + VC_SampleUnload, + VC_SampleSpace, + VC_SampleLength, + RAW_Init, + RAW_Exit, + RAW_Reset, + VC_SetNumVoices, + VC_PlayStart, + VC_PlayStop, + RAW_Update, + VC_VoiceSetVolume, + VC_VoiceSetFrequency, + VC_VoiceSetPanning, + VC_VoicePlay, + VC_VoiceStop, + VC_VoiceStopped, + VC_VoiceReleaseSustain, + VC_VoiceGetPosition, + VC_VoiceRealVolume +}; + diff --git a/mikmod/drv_wav.c b/mikmod/drv_wav.c new file mode 100644 index 0000000..676aeec --- /dev/null +++ b/mikmod/drv_wav.c @@ -0,0 +1,116 @@ + +#include "mikmod.h" + +#if (defined(__GNUC__) || defined(SGI)) +#include +#else +#include +#endif +#include +#include + +#define WAVBUFFERSIZE 65536 + +static VIRTUAL_FILE *wavout; + +static SBYTE *WAV_DMABUF; +static ULONG dumpsize; + +static BOOL WAV_IsThere(void) +{ + return 1; +} + + +static BOOL WAV_Init(void) +{ + if(NULL == (wavout = _mm_fopen("music.wav", "wb"))) return 1; + if(NULL == (WAV_DMABUF = _mm_malloc(WAVBUFFERSIZE))) return 1; + + md_mode |= DMODE_SOFT_MUSIC | DMODE_SOFT_SNDFX; + + if(VC_Init()) return 1; + + _mm_write_string("RIFF WAVEfmt ",wavout); + _mm_write_I_ULONG(16,wavout); /* length of this RIFF block crap */ + + _mm_write_I_UWORD(1, wavout); /* microsoft format type */ + _mm_write_I_UWORD((md_mode & DMODE_STEREO) ? 2 : 1, wavout); + _mm_write_I_ULONG(md_mixfreq, wavout); + _mm_write_I_ULONG(md_mixfreq * ((md_mode & DMODE_STEREO) ? 2 : 1) * + ((md_mode & DMODE_16BITS) ? 2 : 1), wavout); + + _mm_write_I_UWORD(((md_mode & DMODE_16BITS) ? 2 : 1) * + ((md_mode & DMODE_STEREO) ? 2 : 1), wavout); /* block alignment (8/16 bit) */ + + _mm_write_I_UWORD((md_mode & DMODE_16BITS) ? 16 : 8,wavout); + + _mm_write_string("data",wavout); + + dumpsize = 0; + + return 0; +} + + +static void WAV_Exit(void) +{ + VC_Exit(); + + /* write in the actual sizes now */ + + if(wavout!=NULL) + { _mm_fseek(wavout,4,SEEK_SET); + _mm_write_I_ULONG(dumpsize + 32, wavout); + _mm_fseek(wavout,40,SEEK_SET); + _mm_write_I_ULONG(dumpsize, wavout); + + _mm_fclose(wavout); + + if(WAV_DMABUF != NULL) free(WAV_DMABUF); + } +} + + +static void WAV_Update(void) +{ + VC_WriteBytes(WAV_DMABUF, WAVBUFFERSIZE); + VirtualFileWrite(WAV_DMABUF, 1, WAVBUFFERSIZE, wavout); + dumpsize += WAVBUFFERSIZE; +} + + +static BOOL WAV_Reset(void) +{ + return 0; +} + + +MDRIVER drv_wav = +{ NULL, + "music.wav file", + "WAV [music.wav] file output driver v1.0", + 0,255, + WAV_IsThere, + VC_SampleLoad, + VC_SampleUnload, + VC_SampleSpace, + VC_SampleLength, + WAV_Init, + WAV_Exit, + WAV_Reset, + VC_SetNumVoices, + VC_PlayStart, + VC_PlayStop, + WAV_Update, + VC_VoiceSetVolume, + VC_VoiceSetFrequency, + VC_VoiceSetPanning, + VC_VoicePlay, + VC_VoiceStop, + VC_VoiceStopped, + VC_VoiceReleaseSustain, + VC_VoiceGetPosition, + NULL +}; + diff --git a/mikmod/drv_wav_v2.c b/mikmod/drv_wav_v2.c new file mode 100644 index 0000000..2a9af89 --- /dev/null +++ b/mikmod/drv_wav_v2.c @@ -0,0 +1,116 @@ + +#include "mikmod.h" + +#ifdef __GNUC__ +#include +#else +#include +#endif +#include +#include + +#define WAVBUFFERSIZE 65536 + +static VIRTUAL_FILE *wavout; + +static SBYTE *WAV_DMABUF; +static ULONG dumpsize; + +static BOOL WAV_IsThere(void) +{ + return 1; +} + + +static BOOL WAV_Init(void) +{ + if(NULL == (wavout = _mm_fopen("music.wav", "wb"))) return 1; + if(NULL == (WAV_DMABUF = _mm_malloc(WAVBUFFERSIZE))) return 1; + + md_mode |= DMODE_SOFT_MUSIC | DMODE_SOFT_SNDFX; + + if(VC2_Init()) return 1; + + _mm_write_string("RIFF WAVEfmt ",wavout); + _mm_write_I_ULONG(16,wavout); /* length of this RIFF block crap */ + + _mm_write_I_UWORD(1, wavout); /* microsoft format type */ + _mm_write_I_UWORD((md_mode & DMODE_STEREO) ? 2 : 1, wavout); + _mm_write_I_ULONG(md_mixfreq, wavout); + _mm_write_I_ULONG(md_mixfreq * ((md_mode & DMODE_STEREO) ? 2 : 1) * + ((md_mode & DMODE_16BITS) ? 2 : 1), wavout); + + _mm_write_I_UWORD(((md_mode & DMODE_16BITS) ? 2 : 1) * + ((md_mode & DMODE_STEREO) ? 2 : 1), wavout); /* block alignment (8/16 bit) */ + + _mm_write_I_UWORD((md_mode & DMODE_16BITS) ? 16 : 8,wavout); + + _mm_write_string("data",wavout); + + dumpsize = 0; + + return 0; +} + + +static void WAV_Exit(void) +{ + VC2_Exit(); + + /* write in the actual sizes now */ + + if(wavout!=NULL) + { _mm_fseek(wavout,4,SEEK_SET); + _mm_write_I_ULONG(dumpsize + 32, wavout); + _mm_fseek(wavout,40,SEEK_SET); + _mm_write_I_ULONG(dumpsize, wavout); + + _mm_fclose(wavout); + + if(WAV_DMABUF != NULL) free(WAV_DMABUF); + } +} + + +static void WAV_Update(void) +{ + VC2_WriteBytes(WAV_DMABUF, WAVBUFFERSIZE); + VirtualFileWrite(WAV_DMABUF, 1, WAVBUFFERSIZE, wavout); + dumpsize += WAVBUFFERSIZE; +} + + +static BOOL WAV_Reset(void) +{ + return 0; +} + + +MDRIVER drv_wav = +{ NULL, + "music.wav file", + "WAV [music.wav] file output driver v1.0", + 0,255, + WAV_IsThere, + VC2_SampleLoad, + VC2_SampleUnload, + VC2_SampleSpace, + VC2_SampleLength, + WAV_Init, + WAV_Exit, + WAV_Reset, + VC2_SetNumVoices, + VC2_PlayStart, + VC2_PlayStop, + WAV_Update, + VC2_VoiceSetVolume, + VC2_VoiceSetFrequency, + VC2_VoiceSetPanning, + VC2_VoicePlay, + VC2_VoiceStop, + VC2_VoiceStopped, + VC2_VoiceReleaseSustain, + VC2_VoiceGetPosition, + NULL +}; + diff --git a/mikmod/getopt.h b/mikmod/getopt.h new file mode 100644 index 0000000..045f5a5 --- /dev/null +++ b/mikmod/getopt.h @@ -0,0 +1,82 @@ + +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +/* ================ */ +/* GETOPT.C Defines */ +/* ================ */ + +/* + Types: + + P_BOOLEAN : Looks for a + or - immidiately after the option. + If none found (space or other option), -1 is passed. + + P_NUMVALUE : Grabs the value after the option (whitespace ignored). + If no value is given, -1 is passed. + + P_STRING : Grabs the string after the option (leading whitespace + is ignored). If no string was present, NULL is returned. + + Notes: + + A filename or string is normally terminated by a space (always a single + word long). If a filename or string is enclosed in quotations ("blah + blah"), then the string is not terminated until the closing quote is + encountered. + +*/ + +typedef struct FILESTACK +{ struct FILESTACK *prev,*next; + CHAR *path; /* full path, including filename */ + ULONG size; /* Size of the file */ +} FILESTACK; + + +typedef struct P_OPTION +{ CHAR *token; /* option token (string) */ + UBYTE type; /* type of option */ +} P_OPTION; + + +typedef struct P_PARSE +{ int num; /* number of options */ + struct P_OPTION *option; /* array of options */ +} P_PARSE; + + +typedef union P_VALUE +{ SLONG number; /* numeric return value */ + CHAR *text; /* string return value */ +} P_VALUE; + +#define P_STRING 32 +#define P_BOOLEAN 64 +#define P_NUMVALUE 128 + +#define EX_FULLSORT 0 +#define EX_FILESORT 1 + +int ngetopt(CHAR *token, P_PARSE *parse, int argc, CHAR *argv[], void (*post)(int, P_VALUE *)); +BOOL ex_init(CHAR *dir, CHAR *filemask, int sort); +void ex_exit(void); + +extern FILESTACK *filestack; +extern BOOL sortbydir; /* set this to have getopt to catagorize filenames */ + /* by the way they are given on the command line. */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/mikmod/load_669.c b/mikmod/load_669.c new file mode 100644 index 0000000..70aab5b --- /dev/null +++ b/mikmod/load_669.c @@ -0,0 +1,255 @@ +/* + + Name: LOAD_669.C + + Description: + Tran's 669 module loader + + Portability: + All systems - all compilers (hopefully) + + If this module is found to not be portable to any particular platform, + please contact Jake Stine at dracoirs@epix.net (see MIKMOD.TXT for + more information on contacting the author). + +*/ + +#include +#include "mikmod.h" + + +/* Raw 669 header struct: */ + +typedef struct S69HEADER +{ UBYTE marker[2]; + CHAR message[108]; + UBYTE nos; + UBYTE nop; + UBYTE looporder; + UBYTE orders[0x80]; + UBYTE tempos[0x80]; + UBYTE breaks[0x80]; +} S69HEADER; + + +/* Raw 669 sampleinfo struct: */ + +typedef struct S69SAMPLE +{ CHAR filename[13]; + SLONG length; + SLONG loopbeg; + SLONG loopend; +} S69SAMPLE; + + +/* Raw 669 Note struct */ + +typedef struct S69NOTE +{ UBYTE a,b,c; +} S69NOTE; + + +static S69NOTE *s69pat = NULL; +static S69HEADER *mh = NULL; + +static CHAR *S69_Version[] = +{ "669", + "Extended 669" +}; + + +BOOL S69_Test(void) +{ + UBYTE id[2]; + + if(!_mm_read_UBYTES(id,2,modfp)) return 0; + if(!memcmp(id,"if",2) || !memcmp(id,"JN",2)) + { _mm_fseek(modfp,108,SEEK_CUR); + if(_mm_read_UBYTE(modfp) > 64) return 0; + if(_mm_read_UBYTE(modfp) > 128) return 0; + if(_mm_read_UBYTE(modfp) > 120) return 0; + return 1; + } + return 0; +} + + +BOOL S69_Init(void) +{ + if(!(s69pat=(S69NOTE *)_mm_malloc(64*8*sizeof(S69NOTE)))) return 0; + if(!(mh=(S69HEADER *)_mm_calloc(1,sizeof(S69HEADER)))) return 0; + return 1; +} + + +void S69_Cleanup(void) +{ + if(s69pat!=NULL) free(s69pat); + if(mh!=NULL) free(mh); + + mh = NULL; + s69pat = NULL; +} + + +BOOL S69_LoadPatterns(void) +{ + int t,s,q,tracks=0,t2,t3; + UBYTE note,inst,vol,a,b,c, lo; + S69NOTE *cur; + + if(!AllocPatterns()) return 0; + if(!AllocTracks()) return 0; + + for(t=0; tbreaks[t]+1; + + /* Load the pattern into the temp buffer */ + /* and convert it into the 3-byte format */ + + cur = s69pat; + for(t2=64; t2; t2--) + { for(t3=8; t3; t3--, cur++) + { cur->a = _mm_read_UBYTE(modfp); + cur->b = _mm_read_UBYTE(modfp); + cur->c = _mm_read_UBYTE(modfp); + } + } + + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + + for(s=0; s<8; s++) + { UniReset(); + UniPTEffect(0xf,75); /* was 78 */ + UniPTEffect(0xf,3); + + for(q=0; q<64; q++) + { a = s69pat[(q*8)+s].a; + b = s69pat[(q*8)+s].b; + c = s69pat[(q*8)+s].c; + + note = a >> 2; + inst = ((a & 0x3) << 4) | ((b & 0xf0) >> 4); + vol = b & 0xf; + + if(note < 0x3e) + { UniInstrument(inst); + UniNote(note+24); + } + + if(note < 0x3f) UniPTEffect(0xc,vol<<2); + + lo = c & 0xf; + switch(c >> 4) + { case 0: + UniPTEffect(0x1,lo); + break; + + case 1: + UniPTEffect(0x2,lo); + break; + + case 2: + UniPTEffect(0x3,lo); + break; + + case 4: + UniPTEffect(0x4,lo); + break; + } + UniNewline(); + } + if(!(of.tracks[tracks++]=UniDup())) return 0; + } + } + return 1; +} + + +BOOL S69_Load(void) +{ + int t; + S69SAMPLE s; + SAMPLE *q; + + /* try to read module header */ + + _mm_read_UBYTES(mh->marker,2,modfp); + _mm_read_UBYTES((UBYTE *)mh->message,108,modfp); + mh->nos = _mm_read_UBYTE(modfp); + mh->nop = _mm_read_UBYTE(modfp); + mh->looporder = _mm_read_UBYTE(modfp); + _mm_read_UBYTES(mh->orders,0x80,modfp); + _mm_read_UBYTES(mh->tempos,0x80,modfp); + _mm_read_UBYTES(mh->breaks,0x80,modfp); + + /* set module variables */ + + of.initspeed = 6; + of.inittempo = 125; + of.songname = DupStr(mh->message,108); + of.modtype = strdup(S69_Version[memcmp(mh->marker,"JN",2)==0]); + of.numchn = 8; + of.numpat = mh->nop; + of.numins = of.numsmp = mh->nos; + of.numtrk = of.numchn*of.numpat; + of.flags = UF_XMPERIODS; /* | UF_LINEAR; */ + + if(!AllocPositions(0x80)) return 0; + for(t=0; t<0x80; t++) + { if(mh->orders[t]==0xff) break; + of.positions[t] = mh->orders[t]; + } + + of.numpos = t; + + if(!AllocSamples()) return 0; + q = of.samples; + + for(t=0; tsamplename = DupStr(s.filename,13); + + q->seekpos = 0; + q->speed = 0; + q->length = s.length; + q->loopstart = s.loopbeg; + q->loopend = (s.loopendflags = (s.loopbegvolume = 64; + + q++; + } + + if(!S69_LoadPatterns()) return 0; + + return 1; +} + + +MLOADER load_669 = +{ NULL, + "669", + "Portable 669 loader v0.1", + S69_Init, + S69_Test, + S69_Load, + S69_Cleanup, + NULL +}; + + diff --git a/mikmod/load_dsm.c b/mikmod/load_dsm.c new file mode 100644 index 0000000..d52f7d4 --- /dev/null +++ b/mikmod/load_dsm.c @@ -0,0 +1,314 @@ +/* + + Name: LOAD_DSM.C + + Description: + DSIK Internal Format (DSM) module loader + + Portability: + All systems - all compilers (hopefully) + + If this module is found to not be portable to any particular platform, + please contact Jake Stine at dracoirs@epix.net (see MIKMOD.TXT for + more information on contacting the author). +*/ + +#include +#include "mikmod.h" + + +typedef struct DSMNOTE +{ UBYTE note,ins,vol,cmd,inf; +} DSMNOTE; + + +typedef struct DSMINST +{ CHAR filename[13]; + UWORD flags; + UBYTE volume; + ULONG length; + ULONG loopstart; + ULONG loopend; + ULONG reserved1; + UWORD c2spd; + UWORD reserved2; + CHAR samplename[28]; +} DSMINST; + + +typedef struct DSMSONG +{ CHAR songname[28]; + UWORD reserved1; + UWORD flags; + ULONG reserved2; + UWORD numord; + UWORD numsmp; + UWORD numpat; + UWORD numtrk; + UBYTE globalvol; + UBYTE mastervol; + UBYTE speed; + UBYTE bpm; + UBYTE panpos[16]; + UBYTE orders[128]; +} DSMSONG; + + + +static CHAR *SONGID = "SONG"; +static CHAR *INSTID = "INST"; +static CHAR *PATTID = "PATT"; + + +static UBYTE blockid[4]; +static ULONG blockln; +static ULONG blocklp; +static DSMSONG *mh = NULL; +static DSMNOTE *dsmbuf = NULL; + +static CHAR DSM_Version[] = "DSIK DSM-format"; + + +BOOL DSM_Test(void) +{ + UBYTE id[12]; + + if(_mm_read_UBYTES((UBYTE *)id,12,modfp)) return 0; + if(!memcmp(id,"RIFF",4) && !memcmp(&id[8],"DSMF",4)) return 1; + + return 0; +} + + +BOOL DSM_Init(void) +{ + if(!(dsmbuf=(DSMNOTE *)_mm_malloc(16*64*sizeof(DSMNOTE)))) return 0; + if(!(mh=(DSMSONG *)_mm_calloc(1,sizeof(DSMSONG)))) return 0; + return 1; +} + + +void DSM_Cleanup(void) +{ + if(dsmbuf!=NULL) free(dsmbuf); + if(mh!=NULL) free(mh); + + dsmbuf = NULL; + mh = NULL; +} + + +BOOL GetBlockHeader(void) +{ + /* make sure we're at the right position for reading the */ + /* next riff block, no matter how many bytes read */ + + _mm_fseek(modfp, blocklp+blockln, SEEK_SET); + + while(1) + { _mm_read_UBYTES(blockid,4,modfp); + blockln = _mm_read_I_ULONG(modfp); + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + if(memcmp(blockid,SONGID,4) && memcmp(blockid,INSTID,4) && memcmp(blockid,PATTID,4)) + { /*printf("Skipping unknown block type %4.4s\n",&blockid); */ + _mm_fseek(modfp, blockln, SEEK_CUR); + } else break; + } + + blocklp = _mm_ftell(modfp); + return 1; +} + + +BOOL DSM_ReadPattern(void) +{ + int row=0,flag; + DSMNOTE *n; + + /* clear pattern data */ + memset(dsmbuf,255,16*64*sizeof(DSMNOTE)); + _mm_read_UBYTE(modfp); + _mm_read_UBYTE(modfp); + + while(row<64) + { flag = _mm_read_UBYTE(modfp); + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + + if(flag) + { n = &dsmbuf[((flag&0xf)*64)+row]; + if(flag&0x80) n->note = _mm_read_UBYTE(modfp); + if(flag&0x40) n->ins = _mm_read_UBYTE(modfp); + if(flag&0x20) n->vol = _mm_read_UBYTE(modfp); + if(flag&0x10) + { n->cmd = _mm_read_UBYTE(modfp); + n->inf = _mm_read_UBYTE(modfp); + } + } else row++; + } + return 1; +} + + +UBYTE *DSM_ConvertTrack(DSMNOTE *tr) +{ + int t; + UBYTE note,ins,vol,cmd,inf; + + UniReset(); + for(t=0; t<64; t++) + { note = tr[t].note; + ins = tr[t].ins; + vol = tr[t].vol; + cmd = tr[t].cmd; + inf = tr[t].inf; + + if(ins!=0 && ins!=255) UniInstrument(ins-1); + if(note!=255) UniNote(note-1); /* <- normal note */ + if(vol<65) UniPTEffect(0xc,vol); + + if(cmd!=255) + { if(cmd==0x8) + { if(inf<=0x80) + { inf = (inf<0x80) ? inf<<1 : 255; + UniPTEffect(cmd,inf); + } + } else if(cmd==0xb) + { if(inf<=0x7f) UniPTEffect(cmd,inf); + } else + { /* Convert pattern jump from Dec to Hex */ + if(cmd == 0xd) + inf = (((inf&0xf0)>>4)*10)+(inf&0xf); + UniPTEffect(cmd,inf); + } + } + UniNewline(); + } + return UniDup(); +} + + +BOOL DSM_Load(void) +{ + int t; + DSMINST s; + SAMPLE *q; + int cursmp = 0, curpat = 0, track = 0; + + blocklp = 0; + blockln = 12; + + if(!GetBlockHeader()) return 0; + if(memcmp(blockid,SONGID,4)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + _mm_read_UBYTES(mh->songname,28,modfp); + mh->reserved1 = _mm_read_I_UWORD(modfp); + mh->flags = _mm_read_I_UWORD(modfp); + mh->reserved2 = _mm_read_I_ULONG(modfp); + mh->numord = _mm_read_I_UWORD(modfp); + mh->numsmp = _mm_read_I_UWORD(modfp); + mh->numpat = _mm_read_I_UWORD(modfp); + mh->numtrk = _mm_read_I_UWORD(modfp); + mh->globalvol = _mm_read_UBYTE(modfp); + mh->mastervol = _mm_read_UBYTE(modfp); + mh->speed = _mm_read_UBYTE(modfp); + mh->bpm = _mm_read_UBYTE(modfp); + _mm_read_UBYTES(mh->panpos,16,modfp); + _mm_read_UBYTES(mh->orders,128,modfp); + + /* set module variables */ + of.initspeed = mh->speed; + of.inittempo = mh->bpm; + of.modtype = strdup(DSM_Version); + of.numchn = mh->numtrk; + of.numpat = mh->numpat; + of.numtrk = of.numchn*of.numpat; + of.songname = DupStr(mh->songname,28); /* make a cstr of songname */ + + for(t=0; t<16; t++) + of.panning[t] = mh->panpos[t]<0x80 ? (mh->panpos[t]<<1) : 255; + + if(!AllocPositions(mh->numord)) return 0; + of.numpos = 0; + for(t=0; tnumord; t++) + { of.positions[of.numpos] = mh->orders[t]; + if(mh->orders[t]<254) of.numpos++; + } + + of.numins = of.numsmp = mh->numsmp; + + if(!AllocSamples()) return 0; + if(!AllocTracks()) return 0; + if(!AllocPatterns()) return 0; + + while(cursmpsamplename= DupStr(s.samplename,28); + q->seekpos = _mm_ftell(modfp); + q->speed = s.c2spd; + q->length = s.length; + q->loopstart = s.loopstart; + q->loopend = s.loopend; + q->volume = s.volume; + + if(s.flags&1) q->flags|=SF_LOOP; + if(s.flags&2) q->flags|=SF_SIGNED; + cursmp++; + } else if(!memcmp(blockid,PATTID,4) && curpat +#include "mikmod.h" + + +typedef struct FARSAMPLE +{ CHAR samplename[32]; + ULONG length; + UBYTE finetune; + UBYTE volume; + ULONG reppos; + ULONG repend; + UBYTE type; + UBYTE loop; +} FARSAMPLE; + + + +typedef struct FARHEADER1 +{ UBYTE id[4]; /* file magic */ + CHAR songname[40]; /* songname */ + CHAR blah[3]; /* 13,10,26 */ + UWORD headerlen; /* remaining length of header in bytes */ + UBYTE version; + UBYTE onoff[16]; + UBYTE edit1[9]; + UBYTE speed; + UBYTE panning[16]; + UBYTE edit2[4]; + UWORD stlen; +} FARHEADER1; + + +typedef struct FARHEADER2 +{ UBYTE orders[256]; + UBYTE numpat; + UBYTE snglen; + UBYTE loopto; + UWORD patsiz[256]; +} FARHEADER2; + + +typedef struct FARNOTE +{ UBYTE note,ins,vol,eff; +} FARNOTE; + + + +static CHAR FAR_Version[] = "Farandole"; +static FARHEADER1 *mh1 = NULL; +static FARHEADER2 *mh2 = NULL; +static FARNOTE *pat = NULL; + + +BOOL FAR_Test(void) +{ + UBYTE id[4]; + + if(!_mm_read_UBYTES(id,4,modfp)) return 0; + return(!memcmp(id,"FAR=",4)); +} + + +BOOL FAR_Init(void) +{ + if(!(mh1 = (FARHEADER1 *)_mm_malloc(sizeof(FARHEADER1)))) return 0; + if(!(mh2 = (FARHEADER2 *)_mm_malloc(sizeof(FARHEADER2)))) return 0; + if(!(pat = (FARNOTE *)_mm_malloc(16*256*sizeof(FARNOTE)))) return 0; + + return 1; +} + + +void FAR_Cleanup(void) +{ + if(mh1!=NULL) free(mh1); + if(mh2!=NULL) free(mh2); + if(pat!=NULL) free(pat); + + mh1 = NULL; + mh2 = NULL; + pat = NULL; +} + + +UBYTE *FAR_ConvertTrack(FARNOTE *n,int rows) +{ + int t; + + UniReset(); + + for(t=0; tnote) + { UniInstrument(n->ins); + UniNote(n->note+23+12); + } + + if(n->vol&0xf) UniPTEffect(0xc,(n->vol&0xf)<<2); + switch(n->eff>>4) + { case 0xf: + UniPTEffect(0xf,n->eff&0xf); + break; + + /* others not yet implemented */ + } + + UniNewline(); + n+=16; + } + return UniDup(); +} + + +BOOL FAR_Load(void) +{ + int t,u,tracks=0; + SAMPLE *q; + FARSAMPLE s; + FARNOTE *crow; + UBYTE smap[8]; + + /* try to read module header (first part) */ + _mm_read_UBYTES(mh1->id,4,modfp); + _mm_read_SBYTES(mh1->songname,40,modfp); + _mm_read_SBYTES(mh1->blah,3,modfp); + mh1->headerlen = _mm_read_I_UWORD (modfp); + mh1->version = _mm_read_UBYTE (modfp); + _mm_read_UBYTES(mh1->onoff,16,modfp); + _mm_read_UBYTES(mh1->edit1,9,modfp); + mh1->speed = _mm_read_UBYTE(modfp); + _mm_read_UBYTES(mh1->panning,16,modfp); + _mm_read_UBYTES(mh1->edit2,4,modfp); + mh1->stlen = _mm_read_I_UWORD (modfp); + + + /* init modfile data */ + + of.modtype = strdup(FAR_Version); + of.songname = DupStr(mh1->songname,40); + of.numchn = 16; + of.initspeed = mh1->speed; + of.inittempo = 99; + + for(t=0; t<16; t++) of.panning[t] = mh1->panning[t]<<4; + + /* read songtext into comment field */ + if(!ReadComment(mh1->stlen)) return 0; + + /* try to read module header (second part) */ + _mm_read_UBYTES(mh2->orders,256,modfp); + mh2->numpat = _mm_read_UBYTE(modfp); + mh2->snglen = _mm_read_UBYTE(modfp); + mh2->loopto = _mm_read_UBYTE(modfp); + _mm_read_I_UWORDS(mh2->patsiz,256,modfp); + +/* of.numpat=mh2->numpat; */ + of.numpos = mh2->snglen; + if(!AllocPositions(of.numpos)) return 0; + for(t=0; torders[t]==0xff) break; + of.positions[t] = mh2->orders[t]; + } + + /* count number of patterns stored in file */ + of.numpat = 0; + for(t=0; t<256; t++) + if(mh2->patsiz[t]) if((t+1)>of.numpat) of.numpat=t+1; + + of.numtrk = of.numpat*of.numchn; + + /* seek across eventual new data */ + _mm_fseek(modfp,mh1->headerlen-(869+mh1->stlen),SEEK_CUR); + + /* alloc track and pattern structures */ + if(!AllocTracks()) return 0; + if(!AllocPatterns()) return 0; + + for(t=0; tpatsiz[t]) + { rows = _mm_read_UBYTE(modfp); + tempo = _mm_read_UBYTE(modfp); + + crow = pat; + for(u=mh2->patsiz[t]-2; u; u--, crow++) + { crow->note = _mm_read_UBYTE(modfp); + crow->ins = _mm_read_UBYTE(modfp); + crow->vol = _mm_read_UBYTE(modfp); + crow->eff = _mm_read_UBYTE(modfp); + } + + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + + of.pattrows[t] = rows+2; + crow = pat; + for(u=16; u; u--) + if(!(of.tracks[tracks++] = FAR_ConvertTrack(crow,rows+2))) return 0; + } + } + + /* read sample map */ + if(!_mm_read_UBYTES(smap,8,modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* count number of samples used */ + of.numins = 0; + for(t=0; t<64; t++) + if(smap[t>>3] & (1 << (t&7))) of.numins++; + of.numsmp = of.numins; + + /* alloc sample structs */ + if(!AllocSamples()) return 0; + q = of.samples; + + for(t=0; t<64; t++) + { if(smap[t>>3] & (1 << (t&7))) + { _mm_read_SBYTES(s.samplename,32,modfp); + s.length = _mm_read_I_ULONG(modfp); + s.finetune = _mm_read_UBYTE(modfp); + s.volume = _mm_read_UBYTE(modfp); + s.reppos = _mm_read_I_ULONG(modfp); + s.repend = _mm_read_I_ULONG(modfp); + s.type = _mm_read_UBYTE(modfp); + s.loop = _mm_read_UBYTE(modfp); + + q->samplename = DupStr(s.samplename,32); + q->length = s.length; + q->loopstart = s.reppos; + q->loopend = s.repend; + q->volume = 64; + q->speed = 8363; + + q->flags=SF_SIGNED; + if(s.type&1) q->flags|=SF_16BITS; + if(s.loop) q->flags|=SF_LOOP; + + q->seekpos = _mm_ftell(modfp); + _mm_fseek(modfp,q->length,SEEK_CUR); + } + q++; + } + return 1; +} + + +CHAR *FAR_LoadTitle(void) +{ + CHAR s[40]; + + _mm_fseek(modfp,4,SEEK_SET); + if(!_mm_fread(s,40,1,modfp)) return NULL; + + return(DupStr(s,40)); +} + + +MLOADER load_far = +{ NULL, + "FAR", + "Portable FAR loader v0.1", + FAR_Init, + FAR_Test, + FAR_Load, + FAR_Cleanup, + FAR_LoadTitle +}; + diff --git a/mikmod/load_it.c b/mikmod/load_it.c new file mode 100644 index 0000000..a137f7a --- /dev/null +++ b/mikmod/load_it.c @@ -0,0 +1,856 @@ +/* + + Name: LOAD_IT.C + + Description: + ImpulseTracker (IT) module loader + + Portability: + All systems - all compilers (hopefully) + + Copyright 1997 by Jake Stine and Divine Entertainment + + If this module is found to not be portable to any particular platform, + please contact Jake Stine at dracoirs@epix.net (see MIKMOD.TXT for + more information on contacting the author). +*/ + +#include +#include "mikmod.h" + +/************************************************************************** +**************************************************************************/ + +typedef struct ITNOTE +{ UBYTE note,ins,volpan,cmd,inf; +} ITNOTE; + +UBYTE *IT_ConvertTrack(ITNOTE *tr,UWORD numrows); + + +/* Raw IT header struct: */ + +typedef struct ITHEADER +{ CHAR songname[26]; + UBYTE blank01[2]; + UWORD ordnum; + UWORD insnum; + UWORD smpnum; + UWORD patnum; + UWORD cwt; /* Created with tracker (y.xx = 0x0yxx) */ + UWORD cmwt; /* Compatable with tracker ver > than val. */ + UWORD flags; + UWORD special; /* bit 0 set = song message attached */ + UBYTE globvol; + UBYTE mixvol; /* mixing volume [ignored] */ + UBYTE initspeed; + UBYTE inittempo; + UBYTE pansep; /* panning separation between channels */ + UBYTE zerobyte; + UWORD msglength; + ULONG msgoffset; + UBYTE blank02[4]; + + UBYTE pantable[64]; + UBYTE voltable[64]; +} ITHEADER; + + +/* Raw IT sampleinfo struct: */ + +typedef struct ITSAMPLE +{ CHAR filename[12]; + UBYTE zerobyte; + UBYTE globvol; + UBYTE flag; + UBYTE volume; + UBYTE panning; + CHAR sampname[28]; + UWORD convert; /* sample conversion flag */ + ULONG length; + ULONG loopbeg; + ULONG loopend; + ULONG c5spd; + ULONG susbegin; + ULONG susend; + ULONG sampoffset; + UBYTE vibspeed; + UBYTE vibdepth; + UBYTE vibrate; + UBYTE vibwave; /* 0 = sine; 1 = rampdown; 2 = square; 3 = random (speed ignored) */ + + UBYTE noteindex; /* for converting c5spd to finetune */ +} ITSAMPLE; + + +typedef struct ITINSTHEADER +{ ULONG size; /* (dword) Instrument size */ + CHAR filename[12]; /* (char) Instrument filename */ + UBYTE zerobyte; /* (byte) Instrument type (always 0) */ + UBYTE volflg; + UBYTE volpts; + UBYTE volbeg; /* (byte) Volume loop start (node) */ + UBYTE volend; /* (byte) Volume loop end (node) */ + UBYTE volsusbeg; /* (byte) Volume sustain begin (node) */ + UBYTE volsusend; /* (byte) Volume Sustain end (node) */ + UBYTE panflg; + UBYTE panpts; + UBYTE panbeg; /* (byte) channel loop start (node) */ + UBYTE panend; /* (byte) channel loop end (node) */ + UBYTE pansusbeg; /* (byte) cahnnel sustain begin (node) */ + UBYTE pansusend; /* (byte) channel Sustain end (node) */ + UBYTE pitflg; + UBYTE pitpts; + UBYTE pitbeg; /* (byte) pitch loop start (node) */ + UBYTE pitend; /* (byte) pitch loop end (node) */ + UBYTE pitsusbeg; /* (byte) pitch sustain begin (node) */ + UBYTE pitsusend; /* (byte) pitch Sustain end (node) */ + UWORD blank; + UBYTE globvol; + UBYTE chanpan; + UWORD fadeout; /* Envelope end / NNA volume fadeout */ + UBYTE dnc; /* Duplicate note check */ + UBYTE dca; /* Duplicate check action */ + UBYTE dct; /* Duplicate check type */ + UBYTE nna; /* New Note Action [0,1,2,3] */ + UWORD trkvers; /* tracker version used to save [in files only] */ + UBYTE ppsep; /* Pitch-pan Separation */ + UBYTE ppcenter; /* Pitch-pan Center */ + UBYTE rvolvar; /* random volume varations */ + UBYTE rpanvar; /* random panning varations */ + UWORD numsmp; /* Number of samples in instrument [in files only] */ + CHAR name[26]; /* Instrument name */ + UBYTE blank01[6]; + UWORD samptable[120]; /* sample for each note [note / samp pairs] */ + + UBYTE volenv[200]; /* volume envelope (IT 1.x stuff) */ + UBYTE oldvoltick[25]; /* volume tick position (IT 1.x stuff) */ + UBYTE volnode[25]; /* aplitude of volume nodes */ + UWORD voltick[25]; /* tick value of volume nodes */ + SBYTE pannode[25]; /* panenv - node points */ + UWORD pantick[25]; /* tick value of panning nodes */ + SBYTE pitnode[25]; /* pitchenv - node points */ + UWORD pittick[25]; /* tick value of pitch nodes */ +} ITINSTHEADER; + + +/************************************************************************** +**************************************************************************/ + +extern SBYTE remap[64]; /* for removing empty channels */ +extern UBYTE *poslookup; /* S3M/IT fix - removing blank patterns needs a */ + /* lookup table to fix position-jump commands */ +static ULONG *paraptr = NULL; /* parapointer array (see IT docs) */ +static ITHEADER *mh = NULL; +static ITNOTE *itpat = NULL; /* allocate to space for one full pattern */ +static UBYTE *mask = NULL; /* arrays allocated to 64 elements and used for */ +static ITNOTE *last = NULL; /* uncompressing IT's pattern information */ +static int numtrk = 0; +static int old_effect; /* if set, use S3M old-effects stuffs */ +static int *noteindex; + +CHAR IT_Version[] = "ImpulseTracker x.xx"; + +BOOL IT_Test(void) +{ + UBYTE id[4]; + + if(!_mm_read_UBYTES(id,4,modfp)) return 0; + if(!memcmp(id,"IMPM",4)) return 1; + return 0; +} + +BOOL IT_Init(void) +{ + if((mh=(ITHEADER *)_mm_calloc(1,sizeof(ITHEADER)))==NULL) return 0; + if((poslookup=(UBYTE *)_mm_malloc(256*sizeof(UBYTE)))==NULL) return 0; + if((itpat=(ITNOTE *)_mm_malloc(200*64*sizeof(ITNOTE)))==NULL) return 0; + if((mask=(UBYTE *)_mm_malloc(64*sizeof(UBYTE)))==NULL) return 0; + if((last=(ITNOTE *)_mm_malloc(64*sizeof(ITNOTE)))==NULL) return 0; + + return 1; +} + +void IT_Cleanup(void) +{ + if(mh!=NULL) free(mh); + if(poslookup!=NULL) free(poslookup); + if(itpat!=NULL) free(itpat); + if(mask!=NULL) free(mask); + if(last!=NULL) free(last); + if(paraptr!=NULL) free(paraptr); + if(noteindex!=NULL) free(noteindex); + + mh = NULL; + poslookup = NULL; + itpat = NULL; + mask = NULL; + last = NULL; + paraptr = NULL; + noteindex = NULL; +} + + +BOOL IT_GetNumChannels(UWORD patrows) + +/* Because so many IT files have 64 channels as the set number used, but really */ +/* only use far less (usually 8 to 12 still), I had to make this function, */ +/* which determines the number of channels that are actually USED by a pattern. */ +/* */ +/* For every channel that's used, it sets the appropriate array entry of the */ +/* global varialbe 'isused' */ +/* */ +/* NOTE: You must first seek to the file location of the pattern before calling */ +/* this procedure. */ +/* Returns 1 on error */ +{ + int row=0,flag,ch; + + do + { flag = _mm_read_UBYTE(modfp); + if(flag == EOF) + { _mm_errno = MMERR_LOADING_PATTERN; + return 1; + } + + if(flag == 0) + { row++; + } else + { ch = (flag-1) & 63; + remap[ch] = 0; + if(flag & 128) mask[ch] = _mm_read_UBYTE(modfp); + if(mask[ch] & 1) _mm_read_UBYTE(modfp); + if(mask[ch] & 2) _mm_read_UBYTE(modfp); + if(mask[ch] & 4) _mm_read_UBYTE(modfp); + if(mask[ch] & 8) { _mm_read_UBYTE(modfp); _mm_read_UBYTE(modfp); } + } + } while(row < patrows); + + return 0; +} + + +BOOL IT_ReadPattern(UWORD patrows) +{ + int blah; + int row=0,flag,ch; + ITNOTE *itt = itpat, dummy,*n,*l; + + memset(itt,255,patrows*of.numchn*sizeof(ITNOTE)); + + do + { flag = _mm_read_UBYTE(modfp); + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + if(flag == 0) + { itt = &itt[of.numchn]; + row++; + } else + { ch = remap[(flag-1) & 63]; + if(ch != -1) + { n = &itt[ch]; + l = &last[ch]; + } else + { n = l = &dummy; } + + if(flag & 128) mask[ch] = _mm_read_UBYTE(modfp); + if(mask[ch] & 1) if((l->note = n->note = _mm_read_UBYTE(modfp)) == 255) + { l->note = n->note = 253; } + if(mask[ch] & 2) l->ins = n->ins = _mm_read_UBYTE(modfp); + if(mask[ch] & 4) l->volpan = n->volpan = _mm_read_UBYTE(modfp); + if(mask[ch] & 8) { l->cmd = n->cmd = _mm_read_UBYTE(modfp); + l->inf = n->inf = _mm_read_UBYTE(modfp); } + if(mask[ch] & 16) n->note = l->note; + if(mask[ch] & 32) n->ins = l->ins; + if(mask[ch] & 64) n->volpan = l->volpan; + if(mask[ch] & 128) { n->cmd = l->cmd; + n->inf = l->inf; } + } + } while(row < patrows); + + for(blah=0; blah=65) && (volpan<=74)) /* fine volume slide up (65-74) */ + { UniVolEffect(VOL_VOLSLIDE,0x0f + ((volpan-65)<<4)); + } else if((volpan>=75) && (volpan<=84)) /* fine volume slide down (75-84) */ + { UniVolEffect(VOL_VOLSLIDE,0xf0 + (volpan-75)); + } else if((volpan>=85) && (volpan<=94)) /* volume slide up (85-94) */ + { UniVolEffect(VOL_VOLSLIDE,((volpan-85)<<4)); + } else if((volpan>=95) && (volpan<=104)) /* volume slide down (95-104) */ + { UniVolEffect(VOL_VOLSLIDE,(volpan-95)); + } else if((volpan>=105) && (volpan<=114)) /* pitch slide up (105-114) */ + { UniVolEffect(VOL_PITCHSLIDEDN,((volpan-105)<<4)); + } else if((volpan>=115) && (volpan<=124)) /* pitch slide down (115-124) */ + { UniVolEffect(VOL_PITCHSLIDEUP,(volpan-115)); + } else if((volpan>=128) && (volpan<=192)) + { UniVolEffect(VOL_PANNING,((volpan-128) == 64) ? 255 : ((volpan-128) << 2)); + } else if((volpan>=193) && (volpan<=202)) /* portamento to note */ + { UniVolEffect(VOL_PORTAMENTO,portatable[volpan-193]); + } else if((volpan>=203) && (volpan<=212)) /* vibrato */ + { UniVolEffect(VOL_VIBRATO,(volpan-203)); + } + + S3MIT_ProcessCmd(tr[t*of.numchn].cmd,tr[t*of.numchn].inf,old_effect); + + UniNewline(); + } + return UniDup(); +} + + +int cvt_c5spd_to_finetune(ULONG c5spd, int sampnum) +{ + int ctmp=0,tmp,note=1,finetune=0; + + c5spd/=2; + + do + { tmp = getfrequency(of.flags,getlinearperiod(note,0)); + if(tmp >= c5spd) break; + ctmp = tmp; + note++; + } while(1); + + if(tmp != c5spd) + { if((tmp-c5spd) < (c5spd-ctmp)) + while(tmp>c5spd) tmp = getfrequency(of.flags,getlinearperiod(note,--finetune)); + else + { note--; + while(ctmpsongname,26,modfp); + _mm_read_UBYTES(mh->blank01,2,modfp); + mh->ordnum =_mm_read_I_UWORD(modfp); + mh->insnum =_mm_read_I_UWORD(modfp); + mh->smpnum =_mm_read_I_UWORD(modfp); + mh->patnum =_mm_read_I_UWORD(modfp); + mh->cwt =_mm_read_I_UWORD(modfp); + mh->cmwt =_mm_read_I_UWORD(modfp); + mh->flags =_mm_read_I_UWORD(modfp); + mh->special =_mm_read_I_UWORD(modfp); + + mh->globvol =_mm_read_UBYTE(modfp); + mh->mixvol =_mm_read_UBYTE(modfp); + mh->initspeed =_mm_read_UBYTE(modfp); + mh->inittempo =_mm_read_UBYTE(modfp); + mh->pansep =_mm_read_UBYTE(modfp); + mh->zerobyte =_mm_read_UBYTE(modfp); + mh->msglength =_mm_read_I_UWORD(modfp); + mh->msgoffset =_mm_read_I_ULONG(modfp); + _mm_read_UBYTES(mh->blank02,4,modfp); + _mm_read_UBYTES(mh->pantable,64,modfp); + _mm_read_UBYTES(mh->voltable,64,modfp); + + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + + of.modtype = strdup(IT_Version); + of.modtype[15] = (mh->cwt >> 8) + 0x30; + of.modtype[17] = ((mh->cwt >> 4) & 0xf) + 0x30; + of.modtype[18] = ((mh->cwt) & 0xf) + 0x30; + of.songname = DupStr(mh->songname,26); /* make a cstr of songname */ + of.reppos = 0; + of.numpat = mh->patnum; + of.numins = mh->insnum; + of.numsmp = mh->smpnum; + of.initspeed = mh->initspeed; + of.inittempo = mh->inittempo; + of.initvolume = mh->globvol; + + old_effect = 0; + if(mh->flags & 8) { of.flags |= (UF_XMPERIODS | UF_LINEAR); old_effect |= 2; } + if((mh->cwt >= 0x106) && (mh->flags & 16)) old_effect |= 1; + + /* set panning positions */ + for(t=0; t<64; t++) + { if(mh->pantable[t] < 64) of.panning[t] = mh->pantable[t] << 2; + else if(mh->pantable[t]==64) of.panning[t] = 255; + else if(mh->pantable[t]==100) of.panning[t] = PAN_SURROUND; + } + + /* set channel volumes */ + memcpy(of.chanvol,mh->voltable,64); + + /* read the order data */ + if(!AllocPositions(mh->ordnum)) return 0; + + for(t=0; tordnum; t++) + of.positions[t] = _mm_read_UBYTE(modfp); + + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + of.numpos = 0; + for(t=0; tordnum; t++) + { of.positions[of.numpos] = of.positions[t]; + poslookup[t] = of.numpos; /* bug fix for FREAKY S3Ms / ITs */ + if(of.positions[t]<254) of.numpos++; + } + + if((paraptr=(ULONG *)_mm_malloc((mh->insnum+mh->smpnum+of.numpat)*sizeof(ULONG))) == NULL) return 0; + + /* read the instrument, sample, and pattern parapointers */ + _mm_read_I_ULONGS(paraptr,mh->insnum+mh->smpnum+of.numpat,modfp); + + /* now is a good time to check if the header was too short :) */ + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* Check for and load song comment */ + if(mh->special & 1) + { _mm_fseek(modfp,(long)(mh->msgoffset),SEEK_SET); + if(!ReadComment(mh->msglength)) return 0; + } + + if(!(mh->flags & 4)) of.numins = of.numsmp; + if(!AllocSamples()) return 0; + + if((noteindex=(int *)_mm_malloc(mh->smpnum*sizeof(int)))==NULL) return 0; + + q = of.samples; + + /* Load all samples (they're used either way) */ + for(t=0; tsmpnum; t++) + { ITSAMPLE s; + + /* seek to sample position */ + _mm_fseek(modfp,(long)(paraptr[mh->insnum+t] + 4),SEEK_SET); + + /* and load sample info */ + _mm_read_string(s.filename,12,modfp); + s.zerobyte = _mm_read_UBYTE(modfp); + s.globvol = _mm_read_UBYTE(modfp); + s.flag = _mm_read_UBYTE(modfp); + s.volume = _mm_read_UBYTE(modfp); + _mm_read_string(s.sampname,26,modfp); + s.convert = _mm_read_UBYTE(modfp); + s.panning = _mm_read_UBYTE(modfp); + s.length = _mm_read_I_ULONG(modfp); + s.loopbeg = _mm_read_I_ULONG(modfp); + s.loopend = _mm_read_I_ULONG(modfp); + s.c5spd = _mm_read_I_ULONG(modfp); + s.susbegin = _mm_read_I_ULONG(modfp); + s.susend = _mm_read_I_ULONG(modfp); + s.sampoffset = _mm_read_I_ULONG(modfp); + s.vibspeed = _mm_read_UBYTE(modfp); + s.vibdepth = _mm_read_UBYTE(modfp); + s.vibrate = _mm_read_UBYTE(modfp); + s.vibwave = _mm_read_UBYTE(modfp); + + + /* Generate an error if c5spd is > 512k, or samplelength > 256 megs */ + /* (nothing would EVER be that high) */ + + if(_mm_feof(modfp) || (s.c5spd > 0x7ffffL) || (s.length > 0xfffffffUL) || + (s.loopbeg > 0xfffffffUL) || (s.loopend > 0xfffffffUL)) + { _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + + q->samplename = DupStr(s.sampname,26); + + q->speed = s.c5spd / 2; + q->panning = ((s.panning & 127)==64) ? 255 : (s.panning & 127) << 2; + q->length = s.length; + q->loopstart = s.loopbeg; + q->loopend = s.loopend; + q->volume = s.volume; + q->globvol = s.globvol; + q->seekpos = s.sampoffset; + + /* =================================== */ + /* Convert speed to XM linear finetune */ + + if(of.flags & UF_LINEAR) + q->speed = cvt_c5spd_to_finetune(s.c5spd, t); + + if(s.panning & 128) q->flags |= SF_OWNPAN; + + if(s.vibrate) + { q->vibflags |= AV_IT; + q->vibtype = s.vibwave; + q->vibsweep = s.vibrate * 2; + q->vibdepth = s.vibdepth; + q->vibrate = s.vibspeed; + } + + if(s.flag & 2) q->flags |= SF_16BITS; + if(s.flag & 16) q->flags |= SF_LOOP; + if(s.flag & 64) q->flags |= SF_BIDI; + + if(mh->cwt >= 0x200) + { if(s.convert & 1) q->flags |= SF_SIGNED; + if(s.convert & 4) q->flags |= SF_DELTA; + } + + q++; + } + + /* Load instruments if instrument mode flag enabled */ + + if(mh->flags & 4) + { if(!AllocInstruments()) return 0; + d = of.instruments; + of.flags |= UF_NNA | UF_INST; + + for(t=0; tinsnum; t++) + { ITINSTHEADER ih; + + /* seek to instrument position */ + _mm_fseek(modfp,paraptr[t]+4,SEEK_SET); + + /* and load instrument info */ + _mm_read_string(ih.filename,12,modfp); + ih.zerobyte = _mm_read_UBYTE(modfp); + if(mh->cwt < 0x200) /* load IT 1.xx inst header */ + { ih.volflg = _mm_read_UBYTE(modfp); + ih.volbeg = _mm_read_UBYTE(modfp); + ih.volend = _mm_read_UBYTE(modfp); + ih.volsusbeg = _mm_read_UBYTE(modfp); + ih.volsusend = _mm_read_UBYTE(modfp); + _mm_read_I_UWORD(modfp); + ih.fadeout = _mm_read_I_UWORD(modfp); + ih.nna = _mm_read_UBYTE(modfp); + ih.dnc = _mm_read_UBYTE(modfp); + } else /* Read IT200+ header */ + { ih.nna = _mm_read_UBYTE(modfp); + ih.dct = _mm_read_UBYTE(modfp); + ih.dca = _mm_read_UBYTE(modfp); + ih.fadeout = _mm_read_I_UWORD(modfp); + ih.ppsep = _mm_read_UBYTE(modfp); + ih.ppcenter = _mm_read_UBYTE(modfp); + ih.globvol = _mm_read_UBYTE(modfp); + ih.chanpan = _mm_read_UBYTE(modfp); + ih.rvolvar = _mm_read_UBYTE(modfp); + ih.rpanvar = _mm_read_UBYTE(modfp); + } + + ih.trkvers = _mm_read_I_UWORD(modfp); + ih.numsmp = _mm_read_UBYTE(modfp); + _mm_read_UBYTE(modfp); + _mm_read_string(ih.name,26,modfp); + _mm_read_UBYTES(ih.blank01,6,modfp); + _mm_read_I_UWORDS(ih.samptable,120,modfp); + if(mh->cwt < 0x200) /* load IT 1xx volume envelope */ + { _mm_read_UBYTES(ih.volenv,200,modfp); + for(lp=0; lp<25; lp++) + { ih.oldvoltick[lp] = _mm_read_UBYTE(modfp); + ih.volnode[lp] = _mm_read_UBYTE(modfp); + } + } else /* load IT 2xx vol & chanpan & pitch envs */ + { ih.volflg = _mm_read_UBYTE(modfp); + ih.volpts = _mm_read_UBYTE(modfp); + ih.volbeg = _mm_read_UBYTE(modfp); + ih.volend = _mm_read_UBYTE(modfp); + ih.volsusbeg = _mm_read_UBYTE(modfp); + ih.volsusend = _mm_read_UBYTE(modfp); + for(lp=0; lp<25; lp++) + { ih.volnode[lp] = _mm_read_UBYTE(modfp); + ih.voltick[lp] = _mm_read_I_UWORD(modfp); + } + _mm_read_UBYTE(modfp); + + ih.panflg = _mm_read_UBYTE(modfp); + ih.panpts = _mm_read_UBYTE(modfp); + ih.panbeg = _mm_read_UBYTE(modfp); + ih.panend = _mm_read_UBYTE(modfp); + ih.pansusbeg = _mm_read_UBYTE(modfp); + ih.pansusend = _mm_read_UBYTE(modfp); + for(lp=0; lp<25; lp++) + { ih.pannode[lp] = _mm_read_SBYTE(modfp); + ih.pantick[lp] = _mm_read_I_UWORD(modfp); + } + _mm_read_UBYTE(modfp); + + ih.pitflg = _mm_read_UBYTE(modfp); + ih.pitpts = _mm_read_UBYTE(modfp); + ih.pitbeg = _mm_read_UBYTE(modfp); + ih.pitend = _mm_read_UBYTE(modfp); + ih.pitsusbeg = _mm_read_UBYTE(modfp); + ih.pitsusend = _mm_read_UBYTE(modfp); + for(lp=0; lp<25; lp++) + { ih.pitnode[lp] = _mm_read_SBYTE(modfp); + ih.pittick[lp] = _mm_read_I_UWORD(modfp); + } + _mm_read_UBYTE(modfp); + } + + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + + d->volflg |= EF_VOLENV; + d->insname = DupStr(ih.name,26); + d->nnatype = ih.nna; + + if(mh->cwt < 0x200) + { d->volfade = ih.fadeout << 6; + if(ih.dnc) + { d->dct = DCT_NOTE; + d->dca = DCA_CUT; + } + + if(ih.volflg & 1) d->volflg |= EF_ON; + if(ih.volflg & 2) d->volflg |= EF_LOOP; + if(ih.volflg & 4) d->volflg |= EF_SUSTAIN; + + /* XM conversion of IT envelope Array */ + + d->volbeg = ih.volbeg; + d->volend = ih.volend; + d->volsusbeg = ih.volsusbeg; + d->volsusend = ih.volsusend; + + if(ih.volflg & 1) + { for(u=0; u<25; u++) + if(ih.oldvoltick[d->volpts] != 0xff) + { d->volenv[d->volpts].val = (ih.volnode[d->volpts] << 2); + d->volenv[d->volpts].pos = ih.oldvoltick[d->volpts]; + d->volpts++; + } else break; + } + } else + { d->panning = ((ih.chanpan&127) == 64) ? 255 : (ih.chanpan&127)<<2; + if(!(ih.chanpan & 128)) d->flags |= IF_OWNPAN; + + if(!(ih.ppsep & 128)) + { d->pitpansep = ih.ppsep << 2; + d->pitpancenter= ih.ppcenter; + d->flags |= IF_PITCHPAN; + } + d->globvol = ih.globvol >> 1; + d->volfade = ih.fadeout << 5; + d->dct = ih.dct; + d->dca = ih.dca; + + if(mh->cwt >= 0x204) + { d->rvolvar = ih.rvolvar; + d->rpanvar = ih.rpanvar; + } + + if(ih.volflg & 1) d->volflg |= EF_ON; + if(ih.volflg & 2) d->volflg |= EF_LOOP; + if(ih.volflg & 4) d->volflg |= EF_SUSTAIN; + + if(ih.panflg & 1) d->panflg |= EF_ON; + if(ih.panflg & 2) d->panflg |= EF_LOOP; + if(ih.panflg & 4) d->panflg |= EF_SUSTAIN; + + if(ih.pitflg & 1) d->pitflg |= EF_ON; + if(ih.pitflg & 2) d->pitflg |= EF_LOOP; + if(ih.pitflg & 4) d->pitflg |= EF_SUSTAIN; + + d->volpts = ih.volpts; + d->volbeg = ih.volbeg; + d->volend = ih.volend; + d->volsusbeg = ih.volsusbeg; + d->volsusend = ih.volsusend; + + for(u=0; uvolenv[u].val = (ih.volnode[u] << 2); + d->volenv[u].pos = ih.voltick[u]; + } + + d->panpts = ih.panpts; + d->panbeg = ih.panbeg; + d->panend = ih.panend; + d->pansusbeg = ih.pansusbeg; + d->pansusend = ih.pansusend; + + for(u=0; upanenv[u].val = (ih.pannode[u]+32) << 2; + d->panenv[u].pos = ih.pantick[u]; + } + + d->pitpts = ih.pitpts; + d->pitbeg = ih.pitbeg; + d->pitend = ih.pitend; + d->pitsusbeg = ih.pitsusbeg; + d->pitsusend = ih.pitsusend; + + for(u=0; upitenv[u].val = (ih.pitnode[u]+32); + d->pitenv[u].pos = ih.pittick[u]; + } + } + + if(of.flags & UF_LINEAR) + { for(u=0; u<120; u++) + { d->samplenote[u] = (ih.samptable[u] & 255); + d->samplenumber[u] = (ih.samptable[u] >> 8) ? ((ih.samptable[u] >> 8) - 1) : 255; + if(d->samplenumber[u]!=255) + d->samplenote[u] += noteindex[d->samplenumber[u]]; + } + } else + { for(u=0; u<120; u++) + { d->samplenote[u] = (ih.samptable[u] & 255); + d->samplenumber[u] = (ih.samptable[u] >> 8) ? ((ih.samptable[u] >> 8) - 1) : 255; + } + } + + d++; + } + } else if(of.flags & UF_LINEAR) + { if(!AllocInstruments()) return 0; + d = of.instruments; + of.flags |= UF_INST; + + for(t=0; tsmpnum; t++, d++) + { for(u=0; u<120; u++) + d->samplenote[u] += noteindex[d->samplenumber[u]]; + } + } + + + /* Figure out how many channels this blasted song actually uses (what */ + /* ever happened to common courtesy of storing this simple value */ + /* somewhere in the damn module, eh!?) */ + + of.numchn = 0; + memset(remap,-1,64*sizeof(UBYTE)); + + for(t=0; tinsnum+mh->smpnum+t] != 0) /* No parapointer = pattern of 64 rows, EMPTY */ + { _mm_fseek(modfp,(((long)paraptr[mh->insnum+mh->smpnum+t])),SEEK_SET); + packlen = _mm_read_I_UWORD(modfp); + packlen = _mm_read_I_UWORD(modfp); /* read pattern length (# of rows) */ + _mm_read_I_ULONG(modfp); + if(IT_GetNumChannels(packlen)) return 0; + } + } + + /* give each of them a different number */ + for(t=0; t<64; t++) + { if(remap[t]==0) + { remap[t] = of.numchn; + of.numchn++; + } + } + + of.numtrk = of.numpat*of.numchn; + + + if(!AllocPatterns()) return 0; + if(!AllocTracks()) return 0; + + for(t=0; tinsnum+mh->smpnum+t] == 0) /* No parapointer = pattern of 64 rows, EMPTY */ + { of.pattrows[t] = 64; + for(u=0; uinsnum+mh->smpnum+t])),SEEK_SET); + packlen = _mm_read_I_UWORD(modfp); + of.pattrows[t] = _mm_read_I_UWORD(modfp); + _mm_read_I_ULONG(modfp); + + if(!IT_ReadPattern(of.pattrows[t])) return 0; + } + } + + return 1; +} + + +CHAR *IT_LoadTitle(void) +{ + CHAR s[26]; + + _mm_fseek(modfp,4,SEEK_SET); + if(!_mm_fread(s,26,1,modfp)) return NULL; + + return(DupStr(s,26)); +} + + +MLOADER load_it = +{ NULL, + "IT", + "Portable IT loader v0.2", + IT_Init, + IT_Test, + IT_Load, + IT_Cleanup, + + IT_LoadTitle +}; + diff --git a/mikmod/load_m15.c b/mikmod/load_m15.c new file mode 100644 index 0000000..ac1dcf4 --- /dev/null +++ b/mikmod/load_m15.c @@ -0,0 +1,410 @@ +/* + + Name: LOAD_M15.C + + Description: + 15 instrument MOD loader + Also supports Ultimate Sound Tracker (old M15 format) + + Portability: + All systems - all compilers (hopefully) + + If this module is found to not be portable to any particular platform, + please contact Jake Stine at dracoirs@epix.net (see MIKMOD.TXT for + more information on contacting the author). + +*/ + +#include +#include "mikmod.h" + +/************************************************************************* +*************************************************************************/ + + +typedef struct MSAMPINFO /* sample header as it appears in a module */ +{ CHAR samplename[22]; + UWORD length; + UBYTE finetune; + UBYTE volume; + UWORD reppos; + UWORD replen; +} MSAMPINFO; + + +typedef struct MODULEHEADER /* verbatim module header */ +{ CHAR songname[20]; /* the songname.. */ + MSAMPINFO samples[15]; /* all sampleinfo */ + UBYTE songlength; /* number of patterns used */ + UBYTE magic1; /* should be 127 */ + UBYTE positions[128]; /* which pattern to play at pos */ +} MODULEHEADER; + + +typedef struct MODNOTE +{ UBYTE a,b,c,d; +} MODNOTE; + + +/************************************************************************* +*************************************************************************/ + +static MODULEHEADER *mh = NULL; /* raw as-is module header */ +static MODNOTE *patbuf = NULL; +static BOOL ust_loader = 0; /* if TRUE, load as a ust module. */ +static CHAR nulls[3] = {0,0,0}; + +static BOOL LoadModuleHeader(MODULEHEADER *mh) +{ + int t; + + _mm_read_string(mh->songname,20,modfp); + + for(t=0; t<15; t++) + { MSAMPINFO *s = &mh->samples[t]; + _mm_read_string(s->samplename,22,modfp); + s->length =_mm_read_M_UWORD(modfp); + s->finetune =_mm_read_UBYTE(modfp); + s->volume =_mm_read_UBYTE(modfp); + s->reppos =_mm_read_M_UWORD(modfp); + s->replen =_mm_read_M_UWORD(modfp); + } + + mh->songlength =_mm_read_UBYTE(modfp); + mh->magic1 =_mm_read_UBYTE(modfp); /* should be 127 */ + _mm_read_UBYTES(mh->positions,128,modfp); + + return(!_mm_feof(modfp)); +} + + +static int CheckPatternType(int numpat) + +/* Checks the patterns in the modfile for UST / 15-inst indications. */ +/* For example, if an effect 3xx is found, it is assumed that the song */ +/* is 15-inst. If a 1xx effect has dat greater than 0x20, it is UST. */ +/* Returns: 0 indecisive; 1 = UST; 2 = 15-inst */ + +{ + int t; + UBYTE eff, dat; + + ust_loader = 1; + + for(t=0; t= 2)) return 2; + if(eff==1) + { if(dat > 0x1f) return 1; + if(dat < 0x3) return 2; + } + if((eff==2) && (dat > 0x1f)) return 1; + } + + return 0; +} + + +BOOL M15_Test(void) +{ + int t, numpat; + MODULEHEADER mh; + + ust_loader = 0; + + if(!LoadModuleHeader(&mh)) return 0; + if(mh.magic1>127) return 0; + + for(t=0; t<15; t++) + { /* all finetunes should be zero */ + if(mh.samples[t].finetune != 0) return 0; + + /* all volumes should be <= 64 */ + if(mh.samples[t].volume > 64) return 0; + + /* all instrument names should begin with s, st-, or a number */ + if(mh.samples[t].samplename[0] == 's') + { if((memcmp(mh.samples[t].samplename,"st-",3) != 0) && + (memcmp(mh.samples[t].samplename,"ST-",3) != 0) && + (memcmp(mh.samples[t].samplename,nulls,3) != 0)) + ust_loader = 1; + } else if((mh.samples[t].samplename[0] < '0') || (mh.samples[t].samplename[0] > '9')) + ust_loader = 1; + + if(mh.samples[t].length > 4999) + { ust_loader = 0; + if(mh.samples[t].length > 32768) return 0; + } + + if(!ust_loader) return 1; + + if(((mh.samples[t].reppos) + mh.samples[t].replen) > (mh.samples[t].length + 10)) + { ust_loader = 1; + return 1; + } + + } + + for(numpat=0, t=0; t numpat) + numpat = mh.positions[t]; + } + + numpat++; + switch(CheckPatternType(numpat)) + { case 0: /* indecisive, so check more clues... */ + + break; + + case 1: ust_loader = 1; break; + case 2: ust_loader = 0; break; + } + + return 1; +} + + +BOOL M15_Init(void) +{ + if(!(mh=(MODULEHEADER *)_mm_calloc(1,sizeof(MODULEHEADER)))) return 0; + return 1; +} + + +void M15_Cleanup(void) +{ + if(mh!=NULL) free(mh); + if(patbuf!=NULL) free(patbuf); + + mh = NULL; + patbuf = NULL; +} + + +/* +Old (amiga) noteinfo: + + _____byte 1_____ byte2_ _____byte 3_____ byte4_ +/ \ / \ / \ / \ +0000 0000-00000000 0000 0000-00000000 + +Upper four 12 bits for Lower four Effect command. +bits of sam- note period. bits of sam- +ple number. ple number. + +*/ + + +static void M15_ConvertNote(MODNOTE *n) +{ + UBYTE instrument,effect,effdat,note; + UWORD period; + + /* extract the various information from the 4 bytes that */ + /* make up a single note */ + + instrument = (n->a&0x10)|(n->c>>4); + period = (((UWORD)n->a&0xf)<<8)+n->b; + effect = n->c&0xf; + effdat = n->d; + + /* Convert the period to a note number */ + + note=0; + if(period != 0) + { for(note=0; note<60; note++) + if(period >= npertab[note]) break; + note++; + if(note==61) note = 0; + } + + if(instrument!=0) UniInstrument(instrument-1); + if(note!=0) UniNote(note+23); + + /* Convert pattern jump from Dec to Hex */ + if(effect == 0xd) + effdat = (((effdat&0xf0)>>4)*10)+(effdat&0xf); + + if(ust_loader) + { switch(effect) + { case 0: break; + case 1: + UniPTEffect(0,effdat); + break; + + case 2: + if(effdat&0xf) UniPTEffect(1,effdat&0xf); + if(effdat>>2) UniPTEffect(2,effdat>>2); + break; + + case 3: break; + + default: + UniPTEffect(effect,effdat); + break; + } + } else UniPTEffect(effect,effdat); +} + + +static UBYTE *M15_ConvertTrack(MODNOTE *n) +{ + int t; + + UniReset(); + for(t=0; t<64; t++) + { M15_ConvertNote(n); + UniNewline(); + n += 4; + } + return UniDup(); +} + + + +static BOOL M15_LoadPatterns(void) +/* Loads all patterns of a modfile and converts them into the */ +/* 3 byte format. */ +{ + int t,s,tracks=0; + + if(!AllocPatterns()) return 0; + if(!AllocTracks()) return 0; + + /* Allocate temporary buffer for loading */ + /* and converting the patterns */ + + if(!(patbuf=(MODNOTE *)_mm_calloc(64U*4,sizeof(MODNOTE)))) return 0; + + for(t=0; tsongname,20); /* make a cstr of songname */ + of.numpos = mh->songlength; /* copy the songlength */ + + if(!AllocPositions(of.numpos)) return 0; + for(t=0; tpositions[t]; + + + /* Count the number of patterns */ + + of.numpat = 0; + + for(t=0; t of.numpat) + of.numpat = of.positions[t]; + } + of.numpat++; + of.numtrk = of.numpat*4; + + /* Finally, init the sampleinfo structures */ + + of.numins = of.numsmp = 15; + if(!AllocSamples()) return 0; + + s = mh->samples; /* init source pointer */ + q = of.samples; + + for(t=0; tsamplename = DupStr(s->samplename,22); + + /* init the sampleinfo variables and */ + /* convert the size pointers to longword format */ + + q->speed = finetune[s->finetune&0xf]; + q->volume = s->volume; + if(ust_loader) + q->loopstart = s->reppos; + else + q->loopstart = s->reppos<<1; + q->loopend = q->loopstart+(s->replen<<1); + q->length = s->length<<1; + + q->flags = SF_SIGNED | SF_UST_LOOP; + if(s->replen>1) q->flags |= SF_LOOP; + + /* fix replen if repend>length */ + + if(q->loopend>q->length) q->loopend = q->length; + + s++; /* point to next source sampleinfo */ + q++; + } + + if(!M15_LoadPatterns()) return 0; + + ust_loader = 0; + return 1; +} + + +CHAR *M15_LoadTitle(void) +{ + CHAR s[20]; + + _mm_fseek(modfp,0,SEEK_SET); + if(!_mm_fread(s,22,1,modfp)) return NULL; + + return(DupStr(s,20)); +} + + +MLOADER load_m15 = +{ NULL, + "15-instrument module", + "Portable MOD-15 loader v0.1", + M15_Init, + M15_Test, + M15_Load, + M15_Cleanup, + M15_LoadTitle +}; diff --git a/mikmod/load_med.c b/mikmod/load_med.c new file mode 100644 index 0000000..90fe2b3 --- /dev/null +++ b/mikmod/load_med.c @@ -0,0 +1,490 @@ +/* + + Name: LOAD_MED.C + + Description: + Amiga MED module loader + + Portability: + All systems - all compilers (hopefully) + + If this module is found to not be portable to any particular platform, + please contact Jake Stine at dracoirs@epix.net (see MIKMOD.TXT for + more information on contacting the author). + +*/ + +#include +#include "mikmod.h" + +#define MMD0_string 0x4D4D4430 +#define MMD1_string 0x4D4D4431 + +typedef struct MMD0 +{ ULONG id; + ULONG modlen; + ULONG MMD0songP; /* struct MMD0song *song; */ + UWORD psecnum; /* for the player routine, MMD2 only */ + UWORD pseq; /* " " " " */ + ULONG MMD0BlockPP; /* struct MMD0Block **blockarr; */ + ULONG reserved1; + ULONG InstrHdrPP; /* struct InstrHdr **smplarr; */ + ULONG reserved2; + ULONG MMD0expP; /* struct MMD0exp *expdata; */ + ULONG reserved3; + UWORD pstate; /* some data for the player routine */ + UWORD pblock; + UWORD pline; + UWORD pseqnum; + SWORD actplayline; + UBYTE counter; + UBYTE extra_songs; /* number of songs - 1 */ +} MMD0; + + +typedef struct MMD0sample +{ UWORD rep,replen; /* offs: 0(s), 2(s) */ + UBYTE midich; /* offs: 4(s) */ + UBYTE midipreset; /* offs: 5(s) */ + UBYTE svol; /* offs: 6(s) */ + SBYTE strans; /* offs: 7(s) */ +} MMD0sample; + + +typedef struct MMD0song +{ MMD0sample sample[63]; /* 63 * 8 bytes = 504 bytes */ + UWORD numblocks; /* offs: 504 */ + UWORD songlen; /* offs: 506 */ + UBYTE playseq[256]; /* offs: 508 */ + UWORD deftempo; /* offs: 764 */ + SBYTE playtransp; /* offs: 766 */ + UBYTE flags; /* offs: 767 */ + UBYTE flags2; /* offs: 768 */ + UBYTE tempo2; /* offs: 769 */ + UBYTE trkvol[16]; /* offs: 770 */ + UBYTE mastervol; /* offs: 786 */ + UBYTE numsamples; /* offs: 787 */ +} MMD0song; + + +typedef struct MMD0NOTE +{ UBYTE a,b,c; +} MMD0NOTE; + + +typedef struct MMD1NOTE +{ UBYTE a,b,c,d; +} MMD1NOTE; + + +typedef struct InstrHdr +{ ULONG length; + SWORD type; + /* Followed by actual data */ +} InstrHdr; + + +static MMD0 *mh = NULL; +static MMD0song *ms = NULL; +static ULONG *ba = NULL; +static MMD0NOTE *mmd0pat = NULL; +static MMD1NOTE *mmd1pat = NULL; + +#define d0note(row,col) mmd0pat[(row*(UWORD)of.numchn)+col] +#define d1note(row,col) mmd1pat[(row*(UWORD)of.numchn)+col] + + +static CHAR MED_Version[] = "MED"; + + +BOOL MED_Test(void) +{ + UBYTE id[4]; + + if(!_mm_read_UBYTES(id,4,modfp)) return 0; + if(!memcmp(id,"MMD0",4)) return 1; + if(!memcmp(id,"MMD1",4)) return 1; + return 0; +} + + +BOOL MED_Init(void) +{ + if(!(mh=(MMD0 *)_mm_calloc(1,sizeof(MMD0)))) return 0; + if(!(ms=(MMD0song *)_mm_calloc(1,sizeof(MMD0song)))) return 0; + return 1; +} + + +void MED_Cleanup(void) +{ + if(mh!=NULL) free(mh); + if(ms!=NULL) free(ms); + if(ba!=NULL) free(ba); + if(mmd0pat!=NULL) free(mmd0pat); + if(mmd1pat!=NULL) free(mmd1pat); + + mh = NULL; + ms = NULL; + ba = NULL; /* blockarr */ + mmd0pat = NULL; + mmd1pat = NULL; +} + + +void EffectCvt(UBYTE eff,UBYTE dat) +{ + switch(eff) + { /* 0x0 0x1 0x2 0x3 0x4 // PT effects */ + case 0x5: /* PT vibrato with speed/depth nibbles swapped */ + UniPTEffect(0x4,(dat>>4) | ((dat&0xf)<<4) ); + break; + + case 0x6: /* not used */ + case 0x7: /* not used */ + case 0x8: /* midi hold/decay */ + break; + + case 0x9: + if(dat<=0x20) UniPTEffect(0xf,dat); + break; + + /* 0xa 0xb 0xc all PT effects */ + + case 0xd: /* same as PT volslide */ + UniPTEffect(0xa,dat); + break; + + case 0xe: /* synth jmp - midi */ + break; + + case 0xf: + /* F00 does patternbreak with med */ + if(dat==0) UniPTEffect(0xd,0); + else if(dat<=0xa) UniPTEffect(0xf,dat); + else if(dat<0xf1) UniPTEffect(0xf,((UWORD)dat*125)/33); + else if(dat==0xff) UniPTEffect(0xc,0); /* stop note */ + break; + + default: /* all normal PT effects are handled here :) */ + /* Convert pattern jump from Dec to Hex */ + if(eff == 0xd) + dat = (((dat&0xf0)>>4)*10)+(dat&0xf); + UniPTEffect(eff,dat); + break; + } +} + + + +UBYTE *MED_Convert1(int col) +{ + int t; + UBYTE a,b,c,d,inst,note,eff,dat; + MMD1NOTE *n; + + UniReset(); + for(t=0; t<64; t++) + { n = &d1note(t,col); + a = n->a; + b = n->b; + c = n->c; + d = n->d; + + note = a&0x7f; + inst = b&0x3f; + eff = c&0xf; + dat = d; + + if(inst!=0) UniInstrument(inst-1); + if(note!=0) UniNote(note+23); + + EffectCvt(eff,dat); + UniNewline(); + } + + return UniDup(); +} + + +UBYTE *MED_Convert0(int col) +{ + int t; + UBYTE a,b,c,inst,note,eff,dat; + MMD0NOTE *n; + + UniReset(); + for(t=0;t<64;t++) + { n = &d0note(t,col); + a = n->a; + b = n->b; + c = n->c; + + note = a & 0x3f; + a >>= 6; + a = ((a & 1) << 1) | (a >> 1); + + inst = (b >> 4) | (a << 4); + eff = b & 0xf; + dat = c; + + if(inst!=0) UniInstrument(inst-1); + if(note!=0) UniNote(note+35); + + EffectCvt(eff,dat); + UniNewline(); + } + return UniDup(); +} + + +BOOL LoadMMD0Patterns(void) +{ + int t,row,col; + UWORD numtracks,numlines,maxlines=0,track=0; + MMD0NOTE *mmdp; + + /* first, scan patterns to see how many channels are used */ + for(t=0; tof.numchn) of.numchn = numtracks; + if(numlines>maxlines) maxlines = numlines; + } + + of.numtrk = of.numpat*of.numchn; + if(!AllocTracks()) return 0; + if(!AllocPatterns()) return 0; + + if(!(mmd0pat=(MMD0NOTE*)_mm_calloc(of.numchn*(maxlines+1),sizeof(MMD0NOTE)))) return 0; + + /* second read: no more mr. nice guy, */ + /* really read and convert patterns */ + + for(t=0; ta = _mm_read_UBYTE(modfp); + mmdp->b = _mm_read_UBYTE(modfp); + mmdp->c = _mm_read_UBYTE(modfp); + } + } + + for(col=0; colof.numchn) of.numchn = numtracks; + if(numlines>maxlines) maxlines = numlines; + } + + of.numtrk = of.numpat*of.numchn; + if(!AllocTracks()) return 0; + if(!AllocPatterns()) return 0; + + if(!(mmd1pat=(MMD1NOTE*)_mm_calloc(of.numchn*(maxlines+1),sizeof(MMD1NOTE)))) return 0; + + /* second read: no more mr. nice guy, really read and convert patterns */ + for(t=0; ta = _mm_read_UBYTE(modfp); + mmdp->b = _mm_read_UBYTE(modfp); + mmdp->c = _mm_read_UBYTE(modfp); + mmdp->d = _mm_read_UBYTE(modfp); + } + } + + for(col=0;colid = _mm_read_M_ULONG(modfp); + mh->modlen = _mm_read_M_ULONG(modfp); + mh->MMD0songP = _mm_read_M_ULONG(modfp); + mh->psecnum = _mm_read_M_UWORD(modfp); + mh->pseq = _mm_read_M_UWORD(modfp); + mh->MMD0BlockPP = _mm_read_M_ULONG(modfp); + mh->reserved1 = _mm_read_M_ULONG(modfp); + mh->InstrHdrPP = _mm_read_M_ULONG(modfp); + mh->reserved2 = _mm_read_M_ULONG(modfp); + mh->MMD0expP = _mm_read_M_ULONG(modfp); + mh->reserved3 = _mm_read_M_ULONG(modfp); + mh->pstate = _mm_read_M_UWORD(modfp); + mh->pblock = _mm_read_M_UWORD(modfp); + mh->pline = _mm_read_M_UWORD(modfp); + mh->pseqnum = _mm_read_M_UWORD(modfp); + mh->actplayline = _mm_read_M_SWORD(modfp); + mh->counter = _mm_read_UBYTE(modfp); + mh->extra_songs = _mm_read_UBYTE(modfp); + + /* Seek to MMD0song struct */ + _mm_fseek(modfp,mh->MMD0songP,SEEK_SET); + + + /* Load the MMD0 Song Header */ + + mss = ms->sample; /* load the sample data first */ + for(t=63; t; t--, mss++) + { mss->rep = _mm_read_M_UWORD(modfp); + mss->replen = _mm_read_M_UWORD(modfp); + mss->midich = _mm_read_UBYTE(modfp); + mss->midipreset = _mm_read_UBYTE(modfp); + mss->svol = _mm_read_UBYTE(modfp); + mss->strans = _mm_read_SBYTE(modfp); + } + + ms->numblocks = _mm_read_M_UWORD(modfp); + ms->songlen = _mm_read_M_UWORD(modfp); + _mm_read_UBYTES(ms->playseq,256,modfp); + ms->deftempo = _mm_read_M_UWORD(modfp); + ms->playtransp = _mm_read_SBYTE(modfp); + ms->flags = _mm_read_UBYTE(modfp); + ms->flags2 = _mm_read_UBYTE(modfp); + ms->tempo2 = _mm_read_UBYTE(modfp); + _mm_read_UBYTES(ms->trkvol,16,modfp); + ms->mastervol = _mm_read_UBYTE(modfp); + ms->numsamples = _mm_read_UBYTE(modfp); + + /* check for a bad header */ + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* seek to and read the samplepointer array */ + _mm_fseek(modfp,mh->InstrHdrPP,SEEK_SET); + if(!_mm_read_M_ULONGS(sa,ms->numsamples,modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* alloc and read the blockpointer array */ + if(!(ba=(ULONG *)_mm_calloc(ms->numblocks, sizeof(ULONG)))) return 0; + _mm_fseek(modfp,mh->MMD0BlockPP,SEEK_SET); + if(!_mm_read_M_ULONGS(ba,ms->numblocks,modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + + /* copy song positions */ + if(!AllocPositions(ms->songlen)) return 0; + for(t=0; tsonglen; t++) + of.positions[t] = ms->playseq[t]; + + of.initspeed = 6; + of.inittempo = ((UWORD)ms->deftempo*125)/33; + of.modtype = strdup(MED_Version); + of.numchn = 0; /* will be counted later */ + of.numpat = ms->numblocks; + of.numpos = ms->songlen; + of.numins = ms->numsamples; + + of.numsmp = of.numins; + if(!AllocSamples()) return 0; + q = of.samples; + + for(t=0; tsamplename = NULL; + q->length = s.length; + q->seekpos = _mm_ftell(modfp); + q->loopstart = ms->sample[t].rep<<1; + q->loopend = q->loopstart+(ms->sample[t].replen<<1); + q->flags = SF_SIGNED; + q->speed = 8363; + q->volume = 64; + + if(ms->sample[t].replen>1) q->flags|=SF_LOOP; + + /* don't load sample if length>='MMD0' hah.. hah.. very funny.. NOT! */ + if(q->length >= MMD0_string) q->length = 0; + + q++; + } + + + if(mh->id==MMD0_string) + { if(!LoadMMD0Patterns()) return 0; + } else if(mh->id==MMD1_string) + { if(!LoadMMD1Patterns()) return 0; + } else + { _mm_errno = MMERR_NOT_A_MODULE; + return 0; + } + + return 1; +} + + +MLOADER load_med = +{ NULL, + "MED", + "MED loader v0.1", + MED_Init, + MED_Test, + MED_Load, + MED_Cleanup, + NULL +}; + + diff --git a/mikmod/load_mod.c b/mikmod/load_mod.c new file mode 100644 index 0000000..3152feb --- /dev/null +++ b/mikmod/load_mod.c @@ -0,0 +1,341 @@ +/* + + Name: LOAD_MOD.C + + Description: + Generic MOD loader (Protracker, StarTracker, FastTracker, etc) + + Portability: + All systems - all compilers (hopefully) + + If this module is found to not be portable to any particular platform, + please contact Jake Stine at dracoirs@epix.net (see MIKMOD.TXT for + more information on contacting the author). + +*/ + +#include +#include "mikmod.h" + +/************************************************************************* +*************************************************************************/ + + +typedef struct MSAMPINFO /* sample header as it appears in a module */ +{ CHAR samplename[22]; + UWORD length; + UBYTE finetune; + UBYTE volume; + UWORD reppos; + UWORD replen; +} MSAMPINFO; + + +typedef struct MODULEHEADER /* verbatim module header */ +{ CHAR songname[20]; /* the songname.. */ + MSAMPINFO samples[31]; /* all sampleinfo */ + UBYTE songlength; /* number of patterns used */ + UBYTE magic1; /* should be 127 */ + UBYTE positions[128]; /* which pattern to play at pos */ + UBYTE magic2[4]; /* string "M.K." or "FLT4" or "FLT8" */ +} MODULEHEADER; + +#define MODULEHEADERSIZE 1084 + + +typedef struct MODTYPE /* struct to identify type of module */ +{ CHAR id[5]; + UBYTE channels; + CHAR *name; +} MODTYPE; + + +typedef struct MODNOTE +{ UBYTE a,b,c,d; +} MODNOTE; + + +/************************************************************************* +*************************************************************************/ + + +CHAR protracker[] = "Protracker"; +CHAR startracker[] = "Startracker"; +CHAR fasttracker[] = "Fasttracker"; +CHAR ins15tracker[] = "15-instrument"; +CHAR oktalyzer[] = "Oktalyzer"; +CHAR taketracker[] = "TakeTracker"; + + +MODTYPE modtypes[] = +{ "M.K.",4,protracker, /* protracker 4 channel */ + "M!K!",4,protracker, /* protracker 4 channel */ + "FLT4",4,startracker, /* startracker 4 channel */ + "2CHN",2,fasttracker, /* fasttracker 2 channel */ + "4CHN",4,fasttracker, /* fasttracker 4 channel */ + "6CHN",6,fasttracker, /* fasttracker 6 channel */ + "8CHN",8,fasttracker, /* fasttracker 8 channel */ + "10CH",10,fasttracker, /* fasttracker 10 channel */ + "12CH",12,fasttracker, /* fasttracker 12 channel */ + "14CH",14,fasttracker, /* fasttracker 14 channel */ + "16CH",16,fasttracker, /* fasttracker 16 channel */ + "18CH",18,fasttracker, /* fasttracker 18 channel */ + "20CH",20,fasttracker, /* fasttracker 20 channel */ + "22CH",22,fasttracker, /* fasttracker 22 channel */ + "24CH",24,fasttracker, /* fasttracker 24 channel */ + "26CH",26,fasttracker, /* fasttracker 26 channel */ + "28CH",28,fasttracker, /* fasttracker 28 channel */ + "30CH",30,fasttracker, /* fasttracker 30 channel */ + "32CH",32,fasttracker, /* fasttracker 32 channel */ + "CD81",8,oktalyzer, /* atari oktalyzer 8 channel */ + "OKTA",8,oktalyzer, /* atari oktalyzer 8 channel */ + "16CN",16,taketracker, /* taketracker 16 channel */ + "32CN",32,taketracker, /* taketracker 32 channel */ + " ",4,ins15tracker /* 15-instrument 4 channel */ +}; + +static MODULEHEADER *mh = NULL; /* raw as-is module header */ +static MODNOTE *patbuf = NULL; +static int modtype = 0; + +BOOL MOD_Test(void) +{ + UBYTE id[4]; + + _mm_fseek(modfp,MODULEHEADERSIZE-4,SEEK_SET); + if(!_mm_fread(id,4,1,modfp)) return 0; + + /* find out which ID string */ + + for(modtype=0; modtype<23; modtype++) + if(!memcmp(id,modtypes[modtype].id,4)) return 1; + + return 0; +} + + +BOOL MOD_Init(void) +{ + if(!(mh=(MODULEHEADER *)_mm_calloc(1,sizeof(MODULEHEADER)))) return 0; + return 1; +} + + +void MOD_Cleanup(void) +{ + if(mh!=NULL) free(mh); + if(patbuf!=NULL) free(patbuf); + + mh = NULL; + patbuf = NULL; +} + + +/* +Old (amiga) noteinfo: + + _____byte 1_____ byte2_ _____byte 3_____ byte4_ +/ \ / \ / \ / \ +0000 0000-00000000 0000 0000-00000000 + +Upper four 12 bits for Lower four Effect command. +bits of sam- note period. bits of sam- +ple number. ple number. + +*/ + + +void ConvertNote(MODNOTE *n) +{ + UBYTE instrument,effect,effdat,note; + UWORD period; + + /* extract the various information from the 4 bytes that */ + /* make up a single note */ + + instrument = (n->a&0x10)|(n->c>>4); + period = (((UWORD)n->a&0xf)<<8)+n->b; + effect = n->c&0xf; + effdat = n->d; + + /* Convert the period to a note number */ + + note=0; + if(period!=0) + { for(note=0; note<60; note++) + if(period >= npertab[note]) break; + note++; + if(note==61) note = 0; + } + + if(instrument!=0) UniInstrument(instrument-1); + if(note!=0) UniNote(note+23); + + /* Convert pattern jump from Dec to Hex */ + if(effect == 0xd) + effdat = (((effdat&0xf0)>>4)*10)+(effdat&0xf); + + UniPTEffect(effect,effdat); +} + + +UBYTE *ConvertTrack(MODNOTE *n) +{ + int t; + + UniReset(); + for(t=0;t<64;t++) + { ConvertNote(n); + UniNewline(); + n+=of.numchn; + } + return UniDup(); +} + + +BOOL ML_LoadPatterns(void) +/* Loads all patterns of a modfile and converts them into the */ +/* 3 byte format. */ +{ + int t,s,tracks = 0; + + if(!AllocPatterns()) return 0; + if(!AllocTracks()) return 0; + + /* Allocate temporary buffer for loading */ + /* and converting the patterns */ + + if(!(patbuf=(MODNOTE *)_mm_calloc(64U*of.numchn,sizeof(MODNOTE)))) return 0; + + for(t=0; tsongname,20,modfp); + + for(t=0; t<31; t++) + { s = &mh->samples[t]; + _mm_read_string(s->samplename,22,modfp); + s->length =_mm_read_M_UWORD(modfp); + s->finetune =_mm_read_UBYTE(modfp); + s->volume =_mm_read_UBYTE(modfp); + s->reppos =_mm_read_M_UWORD(modfp); + s->replen =_mm_read_M_UWORD(modfp); + } + + mh->songlength =_mm_read_UBYTE(modfp); + mh->magic1 =_mm_read_UBYTE(modfp); + + _mm_read_UBYTES(mh->positions,128,modfp); + _mm_read_UBYTES(mh->magic2,4,modfp); + + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + + of.initspeed = 6; + of.inittempo = 125; + of.numchn = modtypes[modtype].channels; /* get number of channels */ + of.modtype = strdup(modtypes[modtype].name); /* get ascii type of mod */ + of.songname = DupStr(mh->songname,20); /* make a cstr of songname */ + of.numpos = mh->songlength; /* copy the songlength */ + + if(!AllocPositions(of.numpos)) return 0; + for(t=0; tpositions[t]; + + /* Count the number of patterns */ + + of.numpat = 0; + + for(t=0; t of.numpat) + of.numpat = of.positions[t]; + } + of.numpat++; + of.numtrk = of.numpat*of.numchn; + + /* Finally, init the sampleinfo structures */ + of.numins = of.numsmp = 31; + + if(!AllocSamples()) return 0; + + s = mh->samples; /* init source pointer */ + q = of.samples; + + for(t=0; tsamplename = DupStr(s->samplename, 22); + + /* init the sampleinfo variables and */ + /* convert the size pointers to longword format */ + + q->speed = finetune[s->finetune & 0xf]; + q->volume = s->volume; + q->loopstart = (ULONG)s->reppos << 1; + q->loopend = q->loopstart + ((ULONG)s->replen << 1); + q->length = (ULONG)s->length << 1; + + q->flags = SF_SIGNED; + if(s->replen > 1) q->flags |= SF_LOOP; + + /* fix replen if repend > length */ + if(q->loopend > q->length) q->loopend = q->length; + + s++; /* point to next source sampleinfo */ + q++; + } + + if(!ML_LoadPatterns()) return 0; + return 1; +} + + +CHAR *MOD_LoadTitle(void) +{ + CHAR s[20]; + + _mm_fseek(modfp,0,SEEK_SET); + if(!_mm_fread(s,20,1,modfp)) return NULL; + + return(DupStr(s,20)); +} + + +MLOADER load_mod = +{ NULL, + "Standard module", + "Portable MOD loader v0.11", + MOD_Init, + MOD_Test, + MOD_Load, + MOD_Cleanup, + MOD_LoadTitle +}; + diff --git a/mikmod/load_mtm.c b/mikmod/load_mtm.c new file mode 100644 index 0000000..44aec88 --- /dev/null +++ b/mikmod/load_mtm.c @@ -0,0 +1,282 @@ +/* + + Name: LOAD_MTM.C + + Description: + MTM module loader + + Portability: + All systems - all compilers (hopefully) + + If this module is found to not be portable to any particular platform, + please contact Jake Stine at dracoirs@epix.net (see MIKMOD.TXT for + more information on contacting the author). + +*/ + +#include +#include "mikmod.h" + +/************************************************************************** +**************************************************************************/ + + +typedef struct MTMSAMPLE +{ CHAR samplename[22]; + ULONG length; + ULONG reppos; + ULONG repend; + UBYTE finetune; + UBYTE volume; + UBYTE attribute; +} MTMSAMPLE; + + + +typedef struct MTMHEADER +{ UBYTE id[3]; /* MTM file marker */ + UBYTE version; /* upper major, lower nibble minor version number */ + char songname[20]; /* ASCIIZ songname */ + UWORD numtracks; /* number of tracks saved */ + UBYTE lastpattern; /* last pattern number saved */ + UBYTE lastorder; /* last order number to play (songlength-1) */ + UWORD commentsize; /* length of comment field */ + UBYTE numsamples; /* number of samples saved */ + UBYTE attribute; /* attribute byte (unused) */ + UBYTE beatspertrack; /* */ + UBYTE numchannels; /* number of channels used */ + UBYTE panpos[32]; /* voice pan positions */ +} MTMHEADER; + + +typedef struct MTMNOTE +{ UBYTE a,b,c; +} MTMNOTE; + + +/************************************************************************** +**************************************************************************/ + + +static MTMHEADER *mh = NULL; +static MTMNOTE *mtmtrk = NULL; +static UWORD pat[32]; + +char MTM_Version[] = "MTM"; + + + +BOOL MTM_Test(void) +{ + UBYTE id[3]; + if(!_mm_read_UBYTES(id,3,modfp)) return 0; + if(!memcmp(id,"MTM",3)) return 1; + return 0; +} + + +BOOL MTM_Init(void) +{ + if(!(mtmtrk=(MTMNOTE *)_mm_calloc(64,sizeof(MTMNOTE)))) return 0; + if(!(mh=(MTMHEADER *)_mm_calloc(1,sizeof(MTMHEADER)))) return 0; + + return 1; +} + + +void MTM_Cleanup(void) +{ + if(mtmtrk!=NULL) free(mtmtrk); + if(mh!=NULL) free(mh); + + mtmtrk = NULL; + mh = NULL; +} + + +UBYTE *MTM_Convert(void) +{ + int t; + UBYTE a,b,c,inst,note,eff,dat; + + UniReset(); + for(t=0; t<64; t++) + { a = mtmtrk[t].a; + b = mtmtrk[t].b; + c = mtmtrk[t].c; + + inst = ((a&0x3)<<4)|(b>>4); + note = a>>2; + + eff = b&0xf; + dat = c; + + if(inst!=0) UniInstrument(inst-1); + if(note!=0) UniNote(note+24); + + /* mtm bug bugfix: when the effect is volslide, */ + /* slide-up _always_ overrides slide-dn. */ + + if(eff==0xa && dat&0xf0) dat&=0xf0; + + /* Convert pattern jump from Dec to Hex */ + if(eff == 0xd) + dat = (((dat&0xf0)>>4)*10)+(dat&0xf); + UniPTEffect(eff,dat); + UniNewline(); + } + return UniDup(); +} + + +BOOL MTM_Load(void) +{ + MTMSAMPLE s; + SAMPLE *q; + + int t,u; + + /* try to read module header */ + + _mm_read_UBYTES(mh->id,3,modfp); + mh->version =_mm_read_UBYTE(modfp); + _mm_read_string(mh->songname,20,modfp); + mh->numtracks =_mm_read_I_UWORD(modfp); + mh->lastpattern =_mm_read_UBYTE(modfp); + mh->lastorder =_mm_read_UBYTE(modfp); + mh->commentsize =_mm_read_I_UWORD(modfp); + mh->numsamples =_mm_read_UBYTE(modfp); + mh->attribute =_mm_read_UBYTE(modfp); + mh->beatspertrack=_mm_read_UBYTE(modfp); + mh->numchannels =_mm_read_UBYTE(modfp); + _mm_read_UBYTES(mh->panpos,32,modfp); + + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + + of.initspeed = 6; + of.inittempo = 125; + of.modtype = strdup(MTM_Version); + of.numchn = mh->numchannels; + of.numtrk = mh->numtracks+1; /* get number of channels */ + of.songname = DupStr(mh->songname,20); /* make a cstr of songname */ + of.numpos = mh->lastorder+1; /* copy the songlength */ + of.numpat = mh->lastpattern+1; + for(t=0; t<32; t++) of.panning[t] = mh->panpos[t] << 4; + + of.numins = of.numsmp = mh->numsamples; + if(!AllocSamples()) return 0; + + q = of.samples; + + for(t=0; tsamplename = DupStr(s.samplename,22); + q->seekpos = 0; + q->speed = finetune[s.finetune]; + q->length = s.length; + q->loopstart = s.reppos; + q->loopend = s.repend; + q->volume = s.volume; + + if((s.repend-s.reppos) > 2) q->flags |= SF_LOOP; + + if(s.attribute & 1) + { /* If the sample is 16-bits, convert the length */ + /* and replen byte-values into sample-values */ + + q->flags|=SF_16BITS; + q->length>>=1; + q->loopstart>>=1; + q->loopend>>=1; + } + + q++; + } + + if(!AllocPositions(of.numpos)) return 0; + for(t=0; tcommentsize)) return 0; + + return 1; +} + + +CHAR *MTM_LoadTitle(void) +{ + CHAR s[20]; + + _mm_fseek(modfp,4,SEEK_SET); + if(!_mm_fread(s,20,1,modfp)) return NULL; + + return(DupStr(s,20)); +} + + +MLOADER load_mtm = +{ NULL, + "MTM", + "Portable MTM loader v0.1", + MTM_Init, + MTM_Test, + MTM_Load, + MTM_Cleanup, + MTM_LoadTitle +}; + diff --git a/mikmod/load_s3m.c b/mikmod/load_s3m.c new file mode 100644 index 0000000..7a309c0 --- /dev/null +++ b/mikmod/load_s3m.c @@ -0,0 +1,466 @@ +/* + + Name: LOAD_S3M.C + + Description: + Screamtracker (S3M) module loader + + Portability: + All systems - all compilers (hopefully) + + If this module is found to not be portable to any particular platform, + please contact Jake Stine at dracoirs@epix.net (see MIKMOD.TXT for + more information on contacting the author). + +*/ + +#include +#include "mikmod.h" + +/************************************************************************** +**************************************************************************/ + +typedef struct S3MNOTE +{ UBYTE note,ins,vol,cmd,inf; +} S3MNOTE; + +typedef S3MNOTE S3MTRACK[64]; + + +/* Raw S3M header struct: */ + +typedef struct S3MHEADER +{ CHAR songname[28]; + UBYTE t1a; + UBYTE type; + UBYTE unused1[2]; + UWORD ordnum; + UWORD insnum; + UWORD patnum; + UWORD flags; + UWORD tracker; + UWORD fileformat; + CHAR scrm[4]; + UBYTE mastervol; + UBYTE initspeed; + UBYTE inittempo; + UBYTE mastermult; + UBYTE ultraclick; + UBYTE pantable; + UBYTE unused2[8]; + UWORD special; + UBYTE channels[32]; +} S3MHEADER; + + +/* Raw S3M sampleinfo struct: */ + +typedef struct S3MSAMPLE +{ UBYTE type; + CHAR filename[12]; + UBYTE memsegh; + UWORD memsegl; + ULONG length; + ULONG loopbeg; + ULONG loopend; + UBYTE volume; + UBYTE dsk; + UBYTE pack; + UBYTE flags; + ULONG c2spd; + UBYTE unused[12]; + CHAR sampname[28]; + CHAR scrs[4]; +} S3MSAMPLE; + +/************************************************************************** +**************************************************************************/ + + +extern UBYTE *poslookup; /* S3M/IT fix - removing blank patterns needs a */ + /* lookup table to fix position-jump commands */ +extern SBYTE remap[64]; /* for removing empty channels */ + +static S3MNOTE *s3mbuf = NULL; /* pointer to a complete S3M pattern */ +static S3MHEADER *mh = NULL; +static UWORD *paraptr = NULL; /* parapointer array (see S3M docs) */ + +CHAR S3M_Version[] = "Screamtracker 3.xx"; + +BOOL S3M_Test(void) +{ + UBYTE id[4]; + + _mm_fseek(modfp,0x2c,SEEK_SET); + if(!_mm_read_UBYTES(id,4,modfp)) return 0; + if(!memcmp(id,"SCRM",4)) return 1; + return 0; +} + +BOOL S3M_Init(void) +{ + if(!(s3mbuf = (S3MNOTE *)_mm_malloc(16*64*sizeof(S3MNOTE)))) return 0; + if(!(mh = (S3MHEADER *)_mm_calloc(1,sizeof(S3MHEADER)))) return 0; + if(!(poslookup = (UBYTE *)_mm_malloc(sizeof(UBYTE)*128))) return 0; + + return 1; +} + +void S3M_Cleanup(void) +{ + if(s3mbuf!=NULL) free(s3mbuf); + if(paraptr!=NULL) free(paraptr); + if(poslookup!=NULL) free(poslookup); + if(mh!=NULL) free(mh); + + paraptr = NULL; + s3mbuf = NULL; + poslookup = NULL; + mh = NULL; +} + + +BOOL S3M_GetNumChannels(void) + +/* Because so many s3m files have 16 channels as the set number used, but really */ +/* only use far less (usually 8 to 12 still), I had to make this function, */ +/* which determines the number of channels that are actually USED by a pattern. */ +/* */ +/* For every channel that's used, it sets the appropriate array entry of the */ +/* global varialbe 'isused' */ +/* */ +/* NOTE: You must first seek to the file location of the pattern before calling */ +/* this procedure. */ +/* Returns 1 on fail. */ + +{ + int row=0,flag,ch; + + while(row<64) + { flag = _mm_read_UBYTE(modfp); + + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_PATTERN; + return 1; + } + + if(flag) + { ch = flag&31; + if(mh->channels[ch] < 16) remap[ch] = 0; + + if(flag&32) + { _mm_read_UBYTE(modfp); + _mm_read_UBYTE(modfp); + } + + if(flag&64) + _mm_read_UBYTE(modfp); + + if(flag&128) + { _mm_read_UBYTE(modfp); + _mm_read_UBYTE(modfp); + } + } else row++; + } + + return 0; +} + + +BOOL S3M_ReadPattern(void) +{ + int row=0,flag,ch; + S3MNOTE *n; + S3MNOTE dummy; + + /* clear pattern data */ + memset(s3mbuf,255,16*64*sizeof(S3MNOTE)); + + while(row<64) + { flag = _mm_read_UBYTE(modfp); + + if(flag==EOF) + { _mm_errno = MMERR_LOADING_PATTERN; + return 0; + } + + if(flag) + { ch = remap[flag&31]; + + if(ch != -1) + n = &s3mbuf[(64U*ch)+row]; + else + n = &dummy; + + if(flag&32) + { n->note = _mm_read_UBYTE(modfp); + n->ins = _mm_read_UBYTE(modfp); + } + + if(flag&64) + n->vol = _mm_read_UBYTE(modfp); + + if(flag&128) + { n->cmd = _mm_read_UBYTE(modfp); + n->inf = _mm_read_UBYTE(modfp); + } + } else row++; + } + return 1; +} + + +void S3MIT_ProcessCmd(UBYTE cmd, UBYTE inf, BOOL oldeffect); + +UBYTE *S3M_ConvertTrack(S3MNOTE *tr) +{ + int t; + + UBYTE note,ins,vol; + + UniReset(); + for(t=0; t<64; t++) + { + note = tr[t].note; + ins = tr[t].ins; + vol = tr[t].vol; + + + if(ins!=0 && ins!=255) UniInstrument(ins-1); + if(note!=255) + { if(note==254) UniPTEffect(0xc,0); /* <- note off command */ + else UniNote(((note>>4)*12)+(note&0xf)); /* <- normal note */ + } + + if(vol<255) + UniPTEffect(0xc,vol); + + S3MIT_ProcessCmd(tr[t].cmd,tr[t].inf,1); + UniNewline(); + } + + return UniDup(); +} + + +BOOL S3M_Load(void) +{ + int t,u,track = 0; + SAMPLE *q; + UBYTE pan[32]; + + /* try to read module header */ + + _mm_read_string(mh->songname,28,modfp); + mh->t1a =_mm_read_UBYTE(modfp); + mh->type =_mm_read_UBYTE(modfp); + _mm_read_UBYTES(mh->unused1,2,modfp); + mh->ordnum =_mm_read_I_UWORD(modfp); + mh->insnum =_mm_read_I_UWORD(modfp); + mh->patnum =_mm_read_I_UWORD(modfp); + mh->flags =_mm_read_I_UWORD(modfp); + mh->tracker =_mm_read_I_UWORD(modfp); + mh->fileformat =_mm_read_I_UWORD(modfp); + _mm_read_string(mh->scrm,4,modfp); + + mh->mastervol =_mm_read_UBYTE(modfp); + mh->initspeed =_mm_read_UBYTE(modfp); + mh->inittempo =_mm_read_UBYTE(modfp); + mh->mastermult =_mm_read_UBYTE(modfp); + mh->ultraclick =_mm_read_UBYTE(modfp); + mh->pantable =_mm_read_UBYTE(modfp); + _mm_read_UBYTES(mh->unused2,8,modfp); + mh->special =_mm_read_I_UWORD(modfp); + _mm_read_UBYTES(mh->channels,32,modfp); + + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + + of.modtype = strdup(S3M_Version); + of.modtype[14] = ((mh->tracker >> 8) &0xf) + 0x30; + of.modtype[16] = ((mh->tracker >> 4)&0xf) + 0x30; + of.modtype[17] = ((mh->tracker)&0xf) + 0x30; + of.songname = DupStr(mh->songname,28); + of.numpat = mh->patnum; + of.reppos = 0; + of.numins = of.numsmp = mh->insnum; + of.initspeed = mh->initspeed; + of.inittempo = mh->inittempo; + of.initvolume = mh->mastervol<<1; + + /* read the order data */ + if(!AllocPositions(mh->ordnum)) return 0; + for(t=0; tordnum; t++) + of.positions[t] = _mm_read_UBYTE(modfp); + + of.numpos = 0; + for(t=0; tordnum; t++) + { of.positions[of.numpos] = of.positions[t]; + poslookup[t] = of.numpos; /* bug fix for FREAKY S3Ms */ + if(of.positions[t]<254) of.numpos++; + } + + if((paraptr=(UWORD *)_mm_malloc((of.numins+of.numpat)*sizeof(UWORD)))==NULL) return 0; + + /* read the instrument+pattern parapointers */ + _mm_read_I_UWORDS(paraptr,of.numins+of.numpat,modfp); + + + if(mh->pantable==252) + { /* read the panning table (ST 3.2 addition. See below for further */ + /* portions of channel panning [past reampper]). */ + _mm_read_UBYTES(pan,32,modfp); + } + + + /* now is a good time to check if the header was too short :) */ + + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + + /* ============================================== */ + /* Load those darned Samples! (no insts in ST3) */ + + if(!AllocSamples()) return 0; + + q = of.samples; + + for(t=0; tsamplename = DupStr(s.sampname,28); + q->speed = s.c2spd; + q->length = s.length; + q->loopstart = s.loopbeg; + q->loopend = s.loopend; + q->volume = s.volume; + q->seekpos = (((long)s.memsegh)<<16|s.memsegl)<<4; + + if(s.flags&1) q->flags |= SF_LOOP; + if(s.flags&4) q->flags |= SF_16BITS; + if(mh->fileformat==1) q->flags |= SF_SIGNED; + + /* DON'T load sample if it doesn't have the SCRS tag */ + if(memcmp(s.scrs,"SCRS",4)!=0) q->length = 0; + + q++; + } + + /* ==================================== */ + /* Determine the number of channels actually used. (what ever happened */ + /* to the concept of a single "numchn" variable, eh?! */ + + of.numchn = 0; + memset(remap,-1,32*sizeof(UBYTE)); + + for(t=0; tchannels[t]<16) && (remap[t]!=-1)) + { if(mh->channels[t]<8) + of.panning[remap[t]] = 0x20; /* 0x30 = std s3m val */ + else + of.panning[remap[t]] = 0xd0; /* 0xc0 = std s3m val */ + } + } + + if(mh->pantable==252) + { /* set panning positions according to panning table (new for st3.2) */ + for(t=0; t<32; t++) + { if((pan[t]&0x20) && (mh->channels[t]<16) && (remap[t]!=-1)) + of.panning[remap[t]] = (pan[t]&0xf)<<4; + } + } + + + /* ============================== */ + /* Load the pattern info now! */ + + of.numtrk = of.numpat*of.numchn; + if(!AllocTracks()) return 0; + if(!AllocPatterns()) return 0; + + for(t=0; t +#include +#include "mikmod.h" + + +typedef struct STMNOTE +{ UBYTE note,insvol,volcmd,cmdinf; +} STMNOTE; + + +/* Raw STM sampleinfo struct: */ + +typedef struct STMSAMPLE +{ CHAR filename[12]; /* Can't have long comments - just filename comments :) */ + UBYTE unused; /* 0x00 */ + UBYTE instdisk; /* Instrument disk */ + UWORD reserved; /* ISA in memory when in ST 2 */ + UWORD length; /* Sample length */ + UWORD loopbeg; /* Loop start point */ + UWORD loopend; /* Loop end point */ + UBYTE volume; /* Volume */ + UBYTE reserved2; /* More reserved crap */ + UWORD c2spd; /* Good old c2spd */ + UBYTE reserved3[4]; /* Yet more of PSi's reserved crap */ + UWORD isa; /* Internal Segment Address -> */ + /* contrary to the tech specs, this is NOT actually */ + /* written to the stm file. */ +} STMSAMPLE; + +/* Raw STM header struct: */ + +typedef struct STMHEADER +{ CHAR songname[20]; + CHAR trackername[8]; /* !SCREAM! for ST 2.xx */ + UBYTE unused; /* 0x1A */ + UBYTE filetype; /* 1=song, 2=module (only 2 is supported, of course) :) */ + UBYTE ver_major; /* Like 2 */ + UBYTE ver_minor; /* "ditto" */ + UBYTE inittempo; /* initspeed= stm inittempo>>4 */ + UBYTE numpat; /* number of patterns */ + UBYTE globalvol; /* <- WoW! a RiGHT TRiANGLE =8*) */ + UBYTE reserved[13]; /* More of PSi's internal crap */ + STMSAMPLE sample[31]; /* STM sample data */ + UBYTE patorder[128]; /* Docs say 64 - actually 128 */ +} STMHEADER; + + +static STMNOTE *stmbuf = NULL; +static STMHEADER *mh = NULL; + +static CHAR STM_Version[] = "Screamtracker 2"; + + +BOOL STM_Test(void) +{ + UBYTE str[9],filetype; + + _mm_fseek(modfp,21,SEEK_SET); + _mm_read_UBYTES(str,9,modfp); + filetype = _mm_read_UBYTE(modfp); + if(!memcmp(str,"!SCREAM!",8) || (filetype!=2)) /* STM Module = filetype 2 */ + return 0; + return 1; +} + + + +BOOL STM_Init(void) +{ + if(!(mh=(STMHEADER *)_mm_calloc(1,sizeof(STMHEADER)))) return 0; + if(!(stmbuf=(STMNOTE *)_mm_calloc(64U*of.numchn,sizeof(STMNOTE)))) return 0; + + return 1; +} + +void STM_Cleanup(void) +{ + if(mh!=NULL) free(mh); + if(stmbuf!=NULL) free(stmbuf); + + stmbuf = NULL; + mh = NULL; +} + + + +void STM_ConvertNote(STMNOTE *n) +{ + UBYTE note,ins,vol,cmd,inf; + + /* extract the various information from the 4 bytes that */ + /* make up a single note */ + + note = n->note; + ins = n->insvol>>3; + vol = (n->insvol&7)+(n->volcmd>>1); + cmd = n->volcmd&15; + inf = n->cmdinf; + + if(ins!=0 && ins<32) UniInstrument(ins-1); + + /* special values of [SBYTE0] are handled here -> */ + /* we have no idea if these strange values will ever be encountered. */ + /* but it appears as though stms sound correct. */ + if(note==254 || note==252) UniPTEffect(0xc,0); /* <- note off command (???) */ + else + /* if note < 251, then all three bytes are stored in the file */ + if(note<251) UniNote((((note>>4)+2)*12)+(note&0xf)); /* <- normal note and up the octave by two */ + + if(vol<65) + UniPTEffect(0xc,vol); + + if(cmd!=255){ + switch(cmd){ + + case 1: /* Axx set speed to xx and add 0x1c to fix StoOoPiD STM 2.x */ + UniPTEffect(0xf,inf>>4); + break; + + case 2: /* Bxx position jump */ + UniPTEffect(0xb,inf); + break; + + case 3: /* Cxx patternbreak to row xx */ + UniPTEffect(0xd,(((inf&0xf0)>>4)*10)+(inf&0xf)); + break; + + case 4: /* Dxy volumeslide */ + UniWrite(UNI_S3MEFFECTD); + UniWrite(inf); + break; + + case 5: /* Exy toneslide down */ + UniWrite(UNI_S3MEFFECTE); + UniWrite(inf); + break; + + case 6: /* Fxy toneslide up */ + UniWrite(UNI_S3MEFFECTF); + UniWrite(inf); + break; + + case 7: /* Gxx Tone portamento,speed xx */ + UniPTEffect(0x3,inf); + break; + + case 8: /* Hxy vibrato */ + UniPTEffect(0x4,inf); + break; + + case 9: /* Ixy tremor, ontime x, offtime y */ + UniWrite(UNI_S3MEFFECTI); + UniWrite(inf); + break; + + case 0xa: /* Jxy arpeggio */ + UniPTEffect(0x0,inf); + break; + + case 0xb: /* Kxy Dual command H00 & Dxy */ + UniPTEffect(0x4,0); + UniWrite(UNI_S3MEFFECTD); + UniWrite(inf); + break; + + case 0xc: /* Lxy Dual command G00 & Dxy */ + UniPTEffect(0x3,0); + UniWrite(UNI_S3MEFFECTD); + UniWrite(inf); + break; + + /* Support all these above, since ST2 can LOAD these values */ + /* but can actually only play up to J - and J is only */ + /* half-way implemented in ST2 */ + + case 0x18: /* Xxx amiga command 8xx - What the hell, support panning. :) */ + UniPTEffect(0x8,inf); + break; + } + } +} + + +UBYTE *STM_ConvertTrack(STMNOTE *n) +{ + int t; + + UniReset(); + for(t=0; t<64; t++) + { STM_ConvertNote(n); + UniNewline(); + n+=of.numchn; + } + return UniDup(); +} + + +BOOL STM_LoadPatterns(void) +{ + int t,s,tracks=0; + + if(!AllocPatterns()) return 0; + if(!AllocTracks()) return 0; + + /* Allocate temporary buffer for loading */ + /* and converting the patterns */ + + for(t=0; tsongname,20,modfp); + _mm_read_string(mh->trackername,8,modfp); + mh->unused =_mm_read_UBYTE(modfp); + mh->filetype =_mm_read_UBYTE(modfp); + mh->ver_major =_mm_read_UBYTE(modfp); + mh->ver_minor =_mm_read_UBYTE(modfp); + mh->inittempo =_mm_read_UBYTE(modfp); + mh->numpat =_mm_read_UBYTE(modfp); + mh->globalvol =_mm_read_UBYTE(modfp); + _mm_read_UBYTES(mh->reserved,13,modfp); + + for(t=0;t<31;t++) + { STMSAMPLE *s = &mh->sample[t]; /* STM sample data */ + + _mm_read_string(s->filename,12,modfp); + s->unused =_mm_read_UBYTE(modfp); + s->instdisk =_mm_read_UBYTE(modfp); + s->reserved =_mm_read_I_UWORD(modfp); + s->length =_mm_read_I_UWORD(modfp); + s->loopbeg =_mm_read_I_UWORD(modfp); + s->loopend =_mm_read_I_UWORD(modfp); + s->volume =_mm_read_UBYTE(modfp); + s->reserved2=_mm_read_UBYTE(modfp); + s->c2spd =_mm_read_I_UWORD(modfp); + _mm_read_UBYTES(s->reserved3,4,modfp); + s->isa =_mm_read_I_UWORD(modfp); + } + _mm_read_UBYTES(mh->patorder,128,modfp); + + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + + of.modtype = strdup(STM_Version); + of.songname = DupStr(mh->songname,20); /* make a cstr of songname */ + of.numpat = mh->numpat; + of.inittempo = 125; /* mh->inittempo+0x1c; */ + of.initspeed = mh->inittempo>>4; + of.numchn = 4; /* get number of channels */ + + t=0; + if(!AllocPositions(0x80)) return 0; + while(mh->patorder[t]!=99) /* 99 terminates the patorder list */ + { of.positions[t] = mh->patorder[t]; + t++; + } + of.numpos = --t; + of.numtrk = of.numpat*of.numchn; + + /* Finally, init the sampleinfo structures */ + of.numins = of.numsmp = 31; /* always this */ + + if(!AllocSamples()) return 0; + if(!STM_LoadPatterns()) return 0; + + q = of.samples; + + MikMod_ISA = _mm_ftell(modfp); + MikMod_ISA = (MikMod_ISA+15)&0xfffffff0; + + for(t=0; tsamplename = DupStr(mh->sample[t].filename,12); + q->speed = mh->sample[t].c2spd; + q->volume = mh->sample[t].volume; + q->length = mh->sample[t].length; + if (!mh->sample[t].volume || q->length==1 ) q->length = 0; /* if vol = 0 or length = 1, then no sample */ + q->loopstart = mh->sample[t].loopbeg; + q->loopend = mh->sample[t].loopend; + q->seekpos = MikMod_ISA; + + MikMod_ISA+=q->length; + MikMod_ISA = (MikMod_ISA+15)&0xfffffff0; + + /* Once again, contrary to the STM specs, all the sample data is */ + /* actually SIGNED! Sheesh */ + + q->flags = SF_SIGNED; + + if(mh->sample[t].loopend>0 && mh->sample[t].loopend!=0xffff) q->flags|=SF_LOOP; + + /* fix replen if repend>length */ + + if(q->loopend > q->length) q->loopend = q->length; + + q++; + } + + return 1; +} + + +CHAR *STM_LoadTitle(void) +{ + CHAR s[20]; + + _mm_fseek(modfp,0,SEEK_SET); + if(!_mm_fread(s,20,1,modfp)) return NULL; + + return(DupStr(s,20)); +} + + +MLOADER load_stm = +{ NULL, + "STM", + "Portable STM Loader - V 1.2", + STM_Init, + STM_Test, + STM_Load, + STM_Cleanup, + STM_LoadTitle +}; + diff --git a/mikmod/load_ult.c b/mikmod/load_ult.c new file mode 100644 index 0000000..12d4cf4 --- /dev/null +++ b/mikmod/load_ult.c @@ -0,0 +1,292 @@ +/* + + Name: LOAD_ULT.C + + Description: + Ultratracker (ULT) module loader + + Portability: + All systems - all compilers (hopefully) + + If this module is found to not be portable to any particular platform, + please contact Jake Stine at dracoirs@epix.net (see MIKMOD.TXT for + more information on contacting the author). + +*/ + +#include +#include "mikmod.h" + + +#define ULTS_16BITS 4 +#define ULTS_LOOP 8 +#define ULTS_REVERSE 16 + + +/* Raw ULT header struct: */ + +typedef struct ULTHEADER +{ CHAR id[16]; + CHAR songtitle[32]; + UBYTE reserved; +} ULTHEADER; + + +/* Raw ULT sampleinfo struct: */ + +typedef struct ULTSAMPLE +{ CHAR samplename[32]; + CHAR dosname[12]; + SLONG loopstart; + SLONG loopend; + SLONG sizestart; + SLONG sizeend; + UBYTE volume; + UBYTE flags; + SWORD finetune; +} ULTSAMPLE; + + +typedef struct ULTEVENT +{ UBYTE note,sample,eff,dat1,dat2; +} ULTEVENT; + + +CHAR *ULT_Version[]= +{ "Ultra Tracker V1.3", + "Ultra Tracker V1.4", + "Ultra Tracker V1.5", + "Ultra Tracker V1.6" +}; + + +BOOL ULT_Test(void) +{ + CHAR id[16]; + + if(!_mm_read_string(id,15,modfp)) return 0; + return(!strncmp(id,"MAS_UTrack_V00",14)); +} + + +BOOL ULT_Init(void) +{ + return 1; +} + + +void ULT_Cleanup(void) +{ +} + +ULTEVENT ev; + + + +int ReadUltEvent(ULTEVENT *event) +{ + UBYTE flag,rep=1; + + flag = _mm_read_UBYTE(modfp); + + if(flag==0xfc) + { rep = _mm_read_UBYTE(modfp); + event->note =_mm_read_UBYTE(modfp); + } else + event->note = flag; + + event->sample =_mm_read_UBYTE(modfp); + event->eff =_mm_read_UBYTE(modfp); + event->dat1 =_mm_read_UBYTE(modfp); + event->dat2 =_mm_read_UBYTE(modfp); + + return rep; +} + + +BOOL ULT_Load(void) +{ + int t,u,tracks=0; + SAMPLE *q; + ULTSAMPLE s; + ULTHEADER mh; + UBYTE nos,noc,nop; + + /* try to read module header */ + + _mm_read_string(mh.id,15,modfp); + _mm_read_string(mh.songtitle,32,modfp); + mh.reserved = _mm_read_UBYTE(modfp); + + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + if(mh.id[14]<'1' || mh.id[14]>'4') + { _mm_errno = MMERR_NOT_A_MODULE; + return 0; + } + + of.modtype = strdup(ULT_Version[mh.id[14]-'1']); + of.initspeed = 6; + of.inittempo = 125; + + /* read songtext */ + + if(!ReadComment((UWORD)mh.reserved*32)) return 0; + + nos = _mm_read_UBYTE(modfp); + + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + of.songname = DupStr(mh.songtitle,32); + of.numins = nos; + + if(!AllocSamples()) return 0; + + q = of.samples; + + for(t=0; tsamplename = DupStr(s.samplename,32); + q->speed = 8363; + + if(mh.id[14]>='4') + { _mm_read_I_UWORD(modfp); /* read 1.6 extra info(??) word */ + q->speed=s.finetune; + } + + q->length = s.sizeend-s.sizestart; + q->volume = s.volume>>2; + q->loopstart = s.loopstart; + q->loopend = s.loopend; + + q->flags = SF_SIGNED; + + if(s.flags&ULTS_LOOP) + q->flags|=SF_LOOP; + + if(s.flags&ULTS_16BITS) + { q->flags|=SF_16BITS; + q->loopstart>>=1; + q->loopend>>=1; + } + + q++; + } + + if(!AllocPositions(256)) return 0; + for(t=0; t<256; t++) + of.positions[t] = _mm_read_UBYTE(modfp); + for(t=0; t<256; t++) + if(of.positions[t]==255) break; + + of.numpos = t; + + noc = _mm_read_UBYTE(modfp); + nop = _mm_read_UBYTE(modfp); + + of.numchn = noc+1; + of.numpat = nop+1; + of.numtrk = of.numchn*of.numpat; + + if(!AllocTracks()) return 0; + if(!AllocPatterns()) return 0; + + for(u=0; u='3') + for(t=0; t>4; + + /* ULT panning effect fixed by Alexander Kerkhove : */ + + if(eff==0xc) UniPTEffect(eff,ev.dat2>>2); + else if(eff==0xb) UniPTEffect(8,ev.dat2*0xf); + else UniPTEffect(eff,ev.dat2); + + eff=ev.eff&0xf; + + if(eff==0xc) UniPTEffect(eff,ev.dat1>>2); + else if(eff==0xb) UniPTEffect(8,ev.dat1*0xf); + else UniPTEffect(eff,ev.dat1); + + UniNewline(); + done++; + } + } + if(!(of.tracks[t]=UniDup())) return 0; + } + + return 1; +} + + +CHAR *ULT_LoadTitle(void) +{ + CHAR s[32]; + + _mm_fseek(modfp,15,SEEK_SET); + if(!_mm_fread(s,32,1,modfp)) return NULL; + + return(DupStr(s,32)); +} + + +MLOADER load_ult = +{ NULL, + "ULT", + "Portable ULT loader v0.1", + ULT_Init, + ULT_Test, + ULT_Load, + ULT_Cleanup, + ULT_LoadTitle +}; + diff --git a/mikmod/load_uni.c b/mikmod/load_uni.c new file mode 100644 index 0000000..9712599 --- /dev/null +++ b/mikmod/load_uni.c @@ -0,0 +1,237 @@ +/* + +Name: LOAD_UNI.C + +Description: +UNIMOD (mikmod's internal format) module loader. +Currently only supports UniMOD 06 - the internal format for MikMod 3.0. + +Portability: +All systems - all compilers (hopefully) + +*/ + +#include +#include +#include "mikmod.h" + +enum {OSL_MB_OK=1, OSL_MB_CANCEL, OSL_MB_YES, OSL_MB_NO, OSL_MB_QUIT}; +enum {OSL_KEY_SELECT=1, OSL_KEY_START=4, OSL_KEY_UP=5, OSL_KEY_RIGHT=6, OSL_KEY_DOWN=7, OSL_KEY_LEFT=8, OSL_KEY_L=9, OSL_KEY_R=10, + OSL_KEY_TRIANGLE=13, OSL_KEY_CIRCLE=14, OSL_KEY_CROSS=15, OSL_KEY_SQUARE=16, OSL_KEY_HOME=17, OSL_KEY_HOLD=18, OSL_KEY_NOTE=24}; +extern unsigned int oslMessageBox(const char *text, const char *title, unsigned int flags); +#define oslMake3Buttons(b1,a1,b2,a2,b3,a3) ((b1)|((a1)<<5)|((b2)<<9)|((a2)<<14)|((b3)<<18)|((a3)<<23)) +#define oslDebug(format...) ({ char __str2[1000], __str[1000]; sprintf(__str2, "Debug (%s:%i,%s)",__FUNCTION__,__LINE__,__FILE__); sprintf(__str , ##format); oslMessageBox(__str, __str2, oslMake3Buttons(OSL_KEY_CROSS,OSL_MB_OK,OSL_KEY_TRIANGLE,OSL_MB_QUIT,0,0)); }) + + +BOOL UNI_Test(void) +{ + UBYTE id[4]; + + _mm_read_UBYTES(id,4,modfp); + if(!memcmp(id, "UN06", 4)) return 1; + + return 0; +} + + +BOOL UNI_Init(void) +{ + return 1; +} + + +void UNI_Cleanup(void) +{ +} + + +UBYTE *TrkRead(void) +{ + UBYTE *t; + UWORD len; + + len = _mm_read_M_UWORD(modfp); + t = (UBYTE *)malloc(len); + _mm_read_UBYTES(t,len,modfp); + + return t; +} + + +BOOL UNI_Load(void) +{ + int t,v,w; + INSTRUMENT *i; + SAMPLE *s; + + /* UNI format version 3.0 (#6) */ + + of.modtype = strdup("MikMod UniFormat 3.0"); + + _mm_fseek(modfp,5,SEEK_SET); /* skip the header */ + + of.flags = _mm_read_M_UWORD(modfp); + of.numchn = _mm_read_UBYTE(modfp); + of.numvoices = _mm_read_UBYTE(modfp); + of.numpos = _mm_read_M_UWORD(modfp); + of.numpat = _mm_read_M_UWORD(modfp); + of.numtrk = _mm_read_M_UWORD(modfp); + of.numins = _mm_read_M_UWORD(modfp); + of.numsmp = _mm_read_M_UWORD(modfp); + of.reppos = _mm_read_M_UWORD(modfp); + of.initspeed = _mm_read_UBYTE(modfp); + of.inittempo = _mm_read_UBYTE(modfp); + of.initvolume = _mm_read_UBYTE(modfp); + + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + of.songname = StringRead(modfp); + of.composer = StringRead(modfp); + of.comment = StringRead(modfp); + + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + if(!AllocSamples()) return 0; + if(!AllocTracks()) return 0; + if(!AllocPatterns()) return 0; + if(!AllocPositions(of.numpos)) return 0; + + _mm_read_UBYTES(of.positions,of.numpos,modfp); + _mm_read_M_UWORDS(of.panning,of.numchn,modfp); + _mm_read_UBYTES(of.chanvol,of.numchn,modfp); + + + /* Load sample headers */ + + s = of.samples; + for(v=0; vflags = _mm_read_M_UWORD(modfp); + s->speed = _mm_read_M_ULONG(modfp); + s->volume = _mm_read_UBYTE(modfp); + s->panning = _mm_read_M_UWORD(modfp); + s->length = _mm_read_M_ULONG(modfp); + s->loopstart = _mm_read_M_ULONG(modfp); + s->loopend = _mm_read_M_ULONG(modfp); + s->susbegin = _mm_read_M_ULONG(modfp); + s->susend = _mm_read_M_ULONG(modfp); + + s->globvol = _mm_read_UBYTE(modfp); + s->vibflags = _mm_read_UBYTE(modfp); + s->vibtype = _mm_read_UBYTE(modfp); + s->vibsweep = _mm_read_UBYTE(modfp); + s->vibdepth = _mm_read_UBYTE(modfp); + s->vibrate = _mm_read_UBYTE(modfp); + s->samplename = StringRead(modfp); + + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + } + + /* Load instruments */ + + if(of.flags & UF_INST) + { if(!AllocInstruments()) return 0; + i = of.instruments; + + for(v=0; vflags = _mm_read_UBYTE(modfp); + i->nnatype = _mm_read_UBYTE(modfp); + i->dca = _mm_read_UBYTE(modfp); + i->dct = _mm_read_UBYTE(modfp); + i->globvol = _mm_read_UBYTE(modfp); + i->panning = _mm_read_M_UWORD(modfp); + i->pitpansep = _mm_read_UBYTE(modfp); + i->pitpancenter = _mm_read_UBYTE(modfp); + i->rvolvar = _mm_read_UBYTE(modfp); + i->rpanvar = _mm_read_UBYTE(modfp); + + i->volfade = _mm_read_M_UWORD(modfp); + + i->volflg = _mm_read_UBYTE(modfp); + i->volpts = _mm_read_UBYTE(modfp); + i->volsusbeg = _mm_read_UBYTE(modfp); + i->volsusend = _mm_read_UBYTE(modfp); + i->volbeg = _mm_read_UBYTE(modfp); + i->volend = _mm_read_UBYTE(modfp); + + for(w=0; wvolpts; w++) + { i->volenv[w].pos = _mm_read_M_SWORD(modfp); + i->volenv[w].val = _mm_read_M_SWORD(modfp); + } + + i->panflg = _mm_read_UBYTE(modfp); + i->panpts = _mm_read_UBYTE(modfp); + i->pansusbeg = _mm_read_UBYTE(modfp); + i->pansusend = _mm_read_UBYTE(modfp); + i->panbeg = _mm_read_UBYTE(modfp); + i->panend = _mm_read_UBYTE(modfp); + + for(w=0; wpanpts; w++) + { i->panenv[w].pos = _mm_read_M_SWORD(modfp); + i->panenv[w].val = _mm_read_M_SWORD(modfp); + } + + i->pitflg = _mm_read_UBYTE(modfp); + i->pitpts = _mm_read_UBYTE(modfp); + i->pitsusbeg = _mm_read_UBYTE(modfp); + i->pitsusend = _mm_read_UBYTE(modfp); + i->pitbeg = _mm_read_UBYTE(modfp); + i->pitend = _mm_read_UBYTE(modfp); + + for(w=0; wpitpts; w++) + { i->pitenv[w].pos = _mm_read_M_SWORD(modfp); + i->pitenv[w].val = _mm_read_M_SWORD(modfp); + } + + _mm_read_UBYTES(i->samplenumber, 120, modfp); + _mm_read_UBYTES(i->samplenote, 120, modfp); + + i->insname = StringRead(modfp); + + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + } + } + + /* Read patterns */ + + _mm_read_M_UWORDS(of.pattrows,of.numpat,modfp); + _mm_read_M_UWORDS(of.patterns,of.numpat*of.numchn,modfp); + + /* Read tracks */ + + for(t=0; t + + +typedef struct +{ CHAR rID[4]; + ULONG rLen; + CHAR wID[4]; + CHAR fID[4]; + ULONG fLen; + UWORD wFormatTag; + UWORD nChannels; + ULONG nSamplesPerSec; + ULONG nAvgBytesPerSec; + UWORD nBlockAlign; + UWORD nFormatSpecific; +} WAV; + + +BOOL WAV_Load(void) +{ + SAMPLE *si; + static WAV wh; + static CHAR dID[4]; + + /* read wav header */ + + _mm_read_string(wh.rID,4,stream_fp); + wh.rLen = _mm_read_I_ULONG(stream_fp); + _mm_read_string(wh.wID,4,stream_fp); + _mm_read_string(wh.fID,4,stream_fp); + wh.fLen = _mm_read_I_ULONG(stream_fp); + wh.wFormatTag = _mm_read_I_UWORD(stream_fp); + wh.nChannels = _mm_read_I_UWORD(stream_fp); + wh.nSamplesPerSec = _mm_read_I_ULONG(stream_fp); + wh.nAvgBytesPerSec = _mm_read_I_ULONG(stream_fp); + wh.nBlockAlign = _mm_read_I_UWORD(stream_fp); + wh.nFormatSpecific = _mm_read_I_UWORD(stream_fp); + + /* check it */ + + if( _mm_feof(stream_fp) || + memcmp(wh.rID,"RIFF",4) || + memcmp(wh.wID,"WAVE",4) || + memcmp(wh.fID,"fmt ",4) ) + { + _mm_errno = MMERR_UNKNOWN_WAVE_TYPE; + return 0; + } + + /* skip other crap */ + + _mm_fseek(stream_fp,wh.fLen-16,SEEK_CUR); + _mm_read_string(dID,4,stream_fp); + + if( memcmp(dID,"data",4) ) + { _mm_errno = MMERR_UNKNOWN_WAVE_TYPE; + return 0; + } + + if(wh.nChannels > 1) + { _mm_errno = MMERR_UNKNOWN_WAVE_TYPE; + return 0; + } + +/* printf("wFormatTag: %x\n",wh.wFormatTag); */ +/* printf("blockalign: %x\n",wh.nBlockAlign); */ +/* prinff("nFormatSpc: %x\n",wh.nFormatSpecific); */ + + if((si=(SAMPLE *)_mm_calloc(1,sizeof(SAMPLE)))==NULL) return 0; + + si->speed = wh.nSamplesPerSec/wh.nChannels; + si->volume = 64; + + si->length = _mm_read_I_ULONG(stream_fp); + + if(wh.nBlockAlign==2) + { si->flags = SF_16BITS | SF_SIGNED; + si->length>>=1; + } + + return 0; +} + + diff --git a/mikmod/load_xm.c b/mikmod/load_xm.c new file mode 100644 index 0000000..79aeeeb --- /dev/null +++ b/mikmod/load_xm.c @@ -0,0 +1,679 @@ +/* + + Name: LOAD_XM.C + + Description: + Fasttracker (XM) module loader + + Portability: + All systems - all compilers (hopefully) + + If this module is found to not be portable to any particular platform, + please contact Jake Stine at dracoirs@epix.net (see MIKMOD.TXT for + more information on contacting the author). + +*/ + +#include +#include "mikmod.h" + +/************************************************************************** +**************************************************************************/ + + +typedef struct XMHEADER +{ CHAR id[17]; /* ID text: 'Extended module: ' */ + CHAR songname[21]; /* Module name, padded with zeroes and 0x1a at the end */ + CHAR trackername[20]; /* Tracker name */ + UWORD version; /* (word) Version number, hi-byte major and low-byte minor */ + ULONG headersize; /* Header size */ + UWORD songlength; /* (word) Song length (in patten order table) */ + UWORD restart; /* (word) Restart position */ + UWORD numchn; /* (word) Number of channels (2,4,6,8,10,...,32) */ + UWORD numpat; /* (word) Number of patterns (max 256) */ + UWORD numins; /* (word) Number of instruments (max 128) */ + UWORD flags; /* (word) Flags: bit 0: 0 = Amiga frequency table (see below) 1 = Linear frequency table */ + UWORD tempo; /* (word) Default tempo */ + UWORD bpm; /* (word) Default BPM */ + UBYTE orders[256]; /* (byte) Pattern order table */ +} XMHEADER; + + +typedef struct XMINSTHEADER +{ ULONG size; /* (dword) Instrument size */ + CHAR name[22]; /* (char) Instrument name */ + UBYTE type; /* (byte) Instrument type (always 0) */ + UWORD numsmp; /* (word) Number of samples in instrument */ + ULONG ssize; /* */ +} XMINSTHEADER; + + +typedef struct XMPATCHHEADER +{ UBYTE what[96]; /* (byte) Sample number for all notes */ + UWORD volenv[24]; /* (byte) Points for volume envelope */ + UWORD panenv[24]; /* (byte) Points for panning envelope */ + UBYTE volpts; /* (byte) Number of volume points */ + UBYTE panpts; /* (byte) Number of panning points */ + UBYTE volsus; /* (byte) Volume sustain point */ + UBYTE volbeg; /* (byte) Volume loop start point */ + UBYTE volend; /* (byte) Volume loop end point */ + UBYTE pansus; /* (byte) Panning sustain point */ + UBYTE panbeg; /* (byte) Panning loop start point */ + UBYTE panend; /* (byte) Panning loop end point */ + UBYTE volflg; /* (byte) Volume type: bit 0: On; 1: Sustain; 2: Loop */ + UBYTE panflg; /* (byte) Panning type: bit 0: On; 1: Sustain; 2: Loop */ + UBYTE vibflg; /* (byte) Vibrato type */ + UBYTE vibsweep; /* (byte) Vibrato sweep */ + UBYTE vibdepth; /* (byte) Vibrato depth */ + UBYTE vibrate; /* (byte) Vibrato rate */ + UWORD volfade; /* (word) Volume fadeout */ + UWORD reserved[11]; /* (word) Reserved */ +} XMPATCHHEADER; + + +typedef struct XMWAVHEADER +{ ULONG length; /* (dword) Sample length */ + ULONG loopstart; /* (dword) Sample loop start */ + ULONG looplength; /* (dword) Sample loop length */ + UBYTE volume; /* (byte) Volume */ + SBYTE finetune; /* (byte) Finetune (signed byte -128..+127) */ + UBYTE type; /* (byte) Type: Bit 0-1: 0 = No loop, 1 = Forward loop, */ + /* 2 = Ping-pong loop; */ + /* 4: 16-bit sampledata */ + UBYTE panning; /* (byte) Panning (0-255) */ + SBYTE relnote; /* (byte) Relative note number (signed byte) */ + UBYTE reserved; /* (byte) Reserved */ + CHAR samplename[22]; /* (char) Sample name */ + + UBYTE vibtype; /* (byte) Vibrato type */ + UBYTE vibsweep; /* (byte) Vibrato sweep */ + UBYTE vibdepth; /* (byte) Vibrato depth */ + UBYTE vibrate; /* (byte) Vibrato rate */ +} XMWAVHEADER; + + +typedef struct XMPATHEADE +{ ULONG size; /* (dword) Pattern header length */ + UBYTE packing; /* (byte) Packing type (always 0) */ + UWORD numrows; /* (word) Number of rows in pattern (1..256) */ + UWORD packsize; /* (word) Packed patterndata size */ +} XMPATHEADER; + +typedef struct MTMNOTE +{ UBYTE a,b,c; +} MTMNOTE; + + +typedef struct XMNOTE +{ UBYTE note,ins,vol,eff,dat; +}XMNOTE; + +/************************************************************************** +**************************************************************************/ + +static XMNOTE *xmpat = NULL; +static XMHEADER *mh = NULL; + +BOOL XM_Test(void) +{ + UBYTE id[17]; + + if(!_mm_read_UBYTES(id,17,modfp)) return 0; + if(!memcmp(id,"Extended Module: ",17)) return 1; + return 0; +} + + +BOOL XM_Init(void) +{ + if(!(mh=(XMHEADER *)_mm_calloc(1,sizeof(XMHEADER)))) return 0; + return 1; +} + + +void XM_Cleanup(void) +{ + if(mh!=NULL) free(mh); + mh = NULL; +} + + +void XM_ReadNote(XMNOTE *n) +{ + UBYTE cmp; + + memset(n,0,sizeof(XMNOTE)); + + cmp = _mm_read_UBYTE(modfp); + + if(cmp&0x80) + { if(cmp&1) n->note = _mm_read_UBYTE(modfp); + if(cmp&2) n->ins = _mm_read_UBYTE(modfp); + if(cmp&4) n->vol = _mm_read_UBYTE(modfp); + if(cmp&8) n->eff = _mm_read_UBYTE(modfp); + if(cmp&16) n->dat = _mm_read_UBYTE(modfp); + } + else + { n->note = cmp; + n->ins = _mm_read_UBYTE(modfp); + n->vol = _mm_read_UBYTE(modfp); + n->eff = _mm_read_UBYTE(modfp); + n->dat = _mm_read_UBYTE(modfp); + } +} + + +UBYTE *XM_Convert(XMNOTE *xmtrack,UWORD rows) +{ + int t; + UBYTE note,ins,vol,eff,dat; + + UniReset(); + + for(t=0; tnote; + ins = xmtrack->ins; + vol = xmtrack->vol; + eff = xmtrack->eff; + dat = xmtrack->dat; + + if(note!=0) + { if(note==97) + { UniWrite(UNI_KEYFADE); + UniWrite(0); + } else + UniNote(note-1); + } + + if(ins!=0) UniInstrument(ins-1); + + switch(vol>>4) + { + case 0x6: /* volslide down */ + if(vol&0xf) + { UniWrite(UNI_XMEFFECTA); + UniWrite(vol&0xf); + } + break; + + case 0x7: /* volslide up */ + if(vol&0xf) + { UniWrite(UNI_XMEFFECTA); + UniWrite(vol<<4); + } + break; + + /* volume-row fine volume slide is compatible with protracker */ + /* EBx and EAx effects i.e. a zero nibble means DO NOT SLIDE, as */ + /* opposed to 'take the last sliding value'. */ + + case 0x8: /* finevol down */ + UniPTEffect(0xe,0xb0 | (vol&0xf)); + break; + + case 0x9: /* finevol up */ + UniPTEffect(0xe,0xa0 | (vol&0xf)); + break; + + case 0xa: /* set vibrato speed */ + UniPTEffect(0x4,vol<<4); + break; + + case 0xb: /* vibrato */ + UniPTEffect(0x4,vol&0xf); + break; + + case 0xc: /* set panning */ + UniPTEffect(0x8,vol<<4); + break; + + case 0xd: /* panning slide left */ + /* only slide when data nibble not zero: */ + + if(vol&0xf) + { UniWrite(UNI_XMEFFECTP); + UniWrite(vol&0xf); + } + break; + + case 0xe: /* panning slide right */ + /* only slide when data nibble not zero: */ + + if(vol&0xf) + { UniWrite(UNI_XMEFFECTP); + UniWrite(vol<<4); + } + break; + + case 0xf: /* tone porta */ + UniPTEffect(0x3,vol<<4); + break; + + default: + if(vol>=0x10 && vol<=0x50) + UniPTEffect(0xc,vol-0x10); + } + + switch(eff) + { + case 0x4: /* Effect 4: Vibrato */ + UniWrite(UNI_XMEFFECT4); + UniWrite(dat); + break; + + case 0xa: + UniWrite(UNI_XMEFFECTA); + UniWrite(dat); + break; + + case 0xe: + switch(dat>>4) + { case 0x1: /* XM fine porta up */ + UniWrite(UNI_XMEFFECTE1); + UniWrite(dat&0xf); + break; + + case 0x2: /* XM fine porta down */ + UniWrite(UNI_XMEFFECTE2); + UniWrite(dat&0xf); + break; + + case 0xa: /* XM fine volume up */ + UniWrite(UNI_XMEFFECTEA); + UniWrite(dat&0xf); + break; + + case 0xb: /* XM fine volume down */ + UniWrite(UNI_XMEFFECTEB); + UniWrite(dat&0xf); + break; + + default: + UniPTEffect(0x0e,dat); + } + break; + + case 'G'-55: /* G - set global volume */ + if(dat>64) dat = 64; + UniWrite(UNI_XMEFFECTG); + UniWrite(dat); + break; + + case 'H'-55: /* H - global volume slide */ + UniWrite(UNI_XMEFFECTH); + UniWrite(dat); + break; + + case 'K'-55: /* K - keyOff and KeyFade */ + UniWrite(UNI_KEYFADE); + UniWrite(dat); + break; + + case 'L'-55: /* L - set envelope position */ + UniWrite(UNI_XMEFFECTL); + UniWrite(dat); + break; + + case 'P'-55: /* P - panning slide */ + UniWrite(UNI_XMEFFECTP); + UniWrite(dat); + break; + + case 'R'-55: /* R - multi retrig note */ + UniWrite(UNI_S3MEFFECTQ); + UniWrite(dat); + break; + + case 'T'-55: /* T - Tremor !! (== S3M effect I) */ + UniWrite(UNI_S3MEFFECTI); + UniWrite(dat); + break; + + case 'X'-55: + if((dat>>4) == 1) /* X1 - Extra Fine Porta up */ + { UniWrite(UNI_XMEFFECTX1); + UniWrite(dat & 0xf); + } else if((dat>>4) == 2) /* X2 - Extra Fine Porta down */ + { UniWrite(UNI_XMEFFECTX2); + UniWrite(dat & 0xf); + } + break; + + default: + if(eff <= 0xf) + { /* Convert pattern jump from Dec to Hex */ + if(eff == 0xd) + dat = (((dat&0xf0)>>4)*10)+(dat&0xf); + UniPTEffect(eff,dat); + } + break; + } + + UniNewline(); + xmtrack++; + } + return UniDup(); +} + + + +BOOL XM_Load(void) +{ + INSTRUMENT *d; + SAMPLE *q; + XMWAVHEADER *wh,*s; + int t,u,v,p,numtrk; + long next; + ULONG nextwav[256]; + BOOL dummypat=0; + + /* try to read module header */ + + _mm_read_string(mh->id,17,modfp); + _mm_read_string(mh->songname,21,modfp); + _mm_read_string(mh->trackername,20,modfp); + mh->version =_mm_read_I_UWORD(modfp); + mh->headersize =_mm_read_I_ULONG(modfp); + mh->songlength =_mm_read_I_UWORD(modfp); + mh->restart =_mm_read_I_UWORD(modfp); + mh->numchn =_mm_read_I_UWORD(modfp); + mh->numpat =_mm_read_I_UWORD(modfp); + mh->numins =_mm_read_I_UWORD(modfp); + mh->flags =_mm_read_I_UWORD(modfp); + mh->tempo =_mm_read_I_UWORD(modfp); + mh->bpm =_mm_read_I_UWORD(modfp); + _mm_read_UBYTES(mh->orders,256,modfp); + + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_HEADER; + return 0; + } + + /* set module variables */ + of.initspeed = mh->tempo; + of.inittempo = mh->bpm; + of.modtype = DupStr(mh->trackername,20); + of.numchn = mh->numchn; + of.numpat = mh->numpat; + of.numtrk = (UWORD)of.numpat*of.numchn; /* get number of channels */ + of.songname = DupStr(mh->songname,20); /* make a cstr of songname */ + of.numpos = mh->songlength; /* copy the songlength */ + of.reppos = mh->restart; + of.numins = mh->numins; + of.flags |= UF_XMPERIODS | UF_INST; + if(mh->flags&1) of.flags |= UF_LINEAR; + + memset(of.chanvol,64,of.numchn); /* store channel volumes */ + + if(!AllocPositions(of.numpos+3)) return 0; + for(t=0; torders[t]; + +/* + WHY THIS CODE HERE?? I CAN'T REMEMBER! + + Well, I do know why, mikmak! Seems that FT2 doesn't always count blank + patterns AT ALL if they are at the END of the song. So, we have to check + for any patter numbers in the order list greater than the number of pat- + terns total. If one or more is found, we set it equal to the pattern total + and make a dummy pattern to accomidate for the discrepency! +*/ + + for(t=0; t of.numpat) + { of.positions[t] = of.numpat; + dummypat = 1; + } + } + + if(dummypat) { of.numpat++; of.numtrk+=of.numchn; } + + if(!AllocTracks()) return 0; + if(!AllocPatterns()) return 0; + + numtrk = 0; + for(t=0; tnumpat; t++) + { XMPATHEADER ph; + + ph.size =_mm_read_I_ULONG(modfp); + ph.packing =_mm_read_UBYTE(modfp); + ph.numrows =_mm_read_I_UWORD(modfp); + ph.packsize =_mm_read_I_UWORD(modfp); + + of.pattrows[t] = ph.numrows; + + /* Gr8.. when packsize is 0, don't try to load a pattern.. it's empty. */ + /* This bug was discovered thanks to Khyron's module.. */ + + if(!(xmpat=(XMNOTE *)_mm_calloc(ph.numrows*of.numchn,sizeof(XMNOTE)))) return 0; + + if(ph.packsize>0) + { for(u=0; usamplenumber,255,120); + + /* read instrument header */ + + headend = _mm_ftell(modfp); + ih.size = _mm_read_I_ULONG(modfp); + headend += ih.size; + _mm_read_string(ih.name, 22, modfp); + ih.type = _mm_read_UBYTE(modfp); + ih.numsmp = _mm_read_I_UWORD(modfp); + d->insname = DupStr(ih.name,22); + + if(ih.size > 29) + { ih.ssize = _mm_read_I_ULONG(modfp); + if(ih.numsmp > 0) + { XMPATCHHEADER pth; + + _mm_read_UBYTES (pth.what, 96, modfp); + _mm_read_I_UWORDS (pth.volenv, 24, modfp); + _mm_read_I_UWORDS (pth.panenv, 24, modfp); + pth.volpts = _mm_read_UBYTE(modfp); + pth.panpts = _mm_read_UBYTE(modfp); + pth.volsus = _mm_read_UBYTE(modfp); + pth.volbeg = _mm_read_UBYTE(modfp); + pth.volend = _mm_read_UBYTE(modfp); + pth.pansus = _mm_read_UBYTE(modfp); + pth.panbeg = _mm_read_UBYTE(modfp); + pth.panend = _mm_read_UBYTE(modfp); + pth.volflg = _mm_read_UBYTE(modfp); + pth.panflg = _mm_read_UBYTE(modfp); + pth.vibflg = _mm_read_UBYTE(modfp); + pth.vibsweep = _mm_read_UBYTE(modfp); + pth.vibdepth = _mm_read_UBYTE(modfp); + pth.vibrate = _mm_read_UBYTE(modfp); + pth.volfade = _mm_read_I_UWORD(modfp); + + /* read the remainder of the header */ + for(u=headend-_mm_ftell(modfp); u; u--) _mm_read_UBYTE(modfp); + + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + + for(u=0; u<96; u++) + d->samplenumber[u] = pth.what[u] + of.numsmp; + + d->volfade = pth.volfade; + + memcpy(d->volenv,pth.volenv,24); + if(pth.volflg & 1) d->volflg |= EF_ON; + if(pth.volflg & 2) d->volflg |= EF_SUSTAIN; + if(pth.volflg & 4) d->volflg |= EF_LOOP; + d->volsusbeg = d->volsusend = pth.volsus; + d->volbeg = pth.volbeg; + d->volend = pth.volend; + d->volpts = pth.volpts; + + /* scale volume envelope: */ + + for(p=0; p<12; p++) + d->volenv[p].val <<= 2; + + if((d->volflg & EF_ON) && (d->volpts < 2)) + d->volflg &= ~EF_ON; + + memcpy(d->panenv,pth.panenv,24); + d->panflg = pth.panflg; + d->pansusbeg = d->pansusend = pth.pansus; + d->panbeg = pth.panbeg; + d->panend = pth.panend; + d->panpts = pth.panpts; + + /* scale panning envelope: */ + + for(p=0; p<12; p++) + d->panenv[p].val <<= 2; + if((d->panflg & EF_ON) && (d->panpts < 2)) + d->panflg &= ~EF_ON; + + next = 0; + + /* Samples are stored outside the instrument struct now, so we have */ + /* to load them all into a temp area, count the of.numsmp along the */ + /* way and then do an AllocSamples() and move everything over */ + + for(u=0; ulength =_mm_read_I_ULONG (modfp); + s->loopstart =_mm_read_I_ULONG (modfp); + s->looplength =_mm_read_I_ULONG (modfp); + s->volume =_mm_read_UBYTE (modfp); + s->finetune =_mm_read_SBYTE (modfp); + s->type =_mm_read_UBYTE (modfp); + s->panning =_mm_read_UBYTE (modfp); + s->relnote =_mm_read_SBYTE (modfp); + s->vibtype = pth.vibflg; + s->vibsweep = pth.vibsweep; + s->vibdepth = pth.vibdepth*4; + s->vibrate = pth.vibrate; + + s->reserved =_mm_read_UBYTE (modfp); + _mm_read_string(s->samplename, 22, modfp); + + nextwav[of.numsmp+u] = next; + next += s->length; + + if(_mm_feof(modfp)) + { _mm_errno = MMERR_LOADING_SAMPLEINFO; + return 0; + } + } + + for(u=0; usamplename = DupStr(s->samplename,22); + q->length = s->length; + q->loopstart = s->loopstart; + q->loopend = s->loopstart+s->looplength; + q->volume = s->volume; + q->speed = s->finetune+128; + q->panning = s->panning; + q->seekpos = nextwav[u]; + q->vibtype = s->vibtype; + q->vibsweep = s->vibsweep; + q->vibdepth = s->vibdepth; + q->vibrate = s->vibrate; + + if(s->type & 0x10) + { q->length >>= 1; + q->loopstart >>= 1; + q->loopend >>= 1; + } + + q->flags|=SF_OWNPAN; + if(s->type&0x3) q->flags|=SF_LOOP; + if(s->type&0x2) q->flags|=SF_BIDI; + + if(s->type&0x10) q->flags|=SF_16BITS; + q->flags|=SF_DELTA; + q->flags|=SF_SIGNED; + } + + d = of.instruments; + s = wh; + for(u=0; usamplenumber[t]].relnote / 12) > ) + { s[d->samplenumber[t]].relnote -= 12; + of.samples[d->samplenumber[t]].speed <<= 1; + } + */ + for(t=0; t<96; t++) + d->samplenote[t] = (d->samplenumber[t]==of.numsmp) ? 255 : (t+s[d->samplenumber[t]].relnote); + } + + free(wh); + return 1; +} + + + +CHAR *XM_LoadTitle(void) +{ + CHAR s[21]; + + _mm_fseek(modfp,17,SEEK_SET); + if(!_mm_fread(s,21,1,modfp)) return NULL; + + return(DupStr(s,21)); +} + + + +MLOADER load_xm = +{ NULL, + "XM", + "Portable XM loader v0.5", + XM_Init, + XM_Test, + XM_Load, + XM_Cleanup, + XM_LoadTitle +}; diff --git a/mikmod/makefile.freebsd b/mikmod/makefile.freebsd new file mode 100644 index 0000000..478e14a --- /dev/null +++ b/mikmod/makefile.freebsd @@ -0,0 +1,41 @@ +# MikMod Library Makefile for FreeBSD +# Divine Entertainment Game Programming Pack + + +#################### +### User Options ### +#################### + +# Use the C or C++ compiler +CC = gcc +CFLAGS = -Wall -O6 -funroll-loops -ffast-math -finline-functions -fomit-frame-pointer -pipe -I. -I../include -DOSS + +Lib_file = ../lib/libmikmod.a + +LoaderObjs = mloader.o mlreg.o npertab.o sloader.o load_uni.o \ + load_mod.o load_m15.o load_mtm.o load_s3m.o load_stm.o load_669.o \ + load_far.o load_dsm.o load_med.o load_xm.o load_ult.o load_it.o \ + s3m_it.o + +DriverObjs = mdriver.o mdreg.o drv_nos.o drv_raw.o drv_wav.o \ + unix_drv/drv_oss.o +# unix_drv/drv_AF.o unix_drv/drv_aix.o unix_drv/drv_hp.o +# unix_drv/drv_sun.o unix_drv/drv_sgi.o + +PlayerObjs = mplayer.o + +#################### +## Makefile rules ## +#################### + +all: $(Lib_file) + +$(Lib_file): stream.o virtch.o munitrk.o \ + $(LoaderObjs) $(DriverObjs) $(PlayerObjs) + ar r $(Lib_file) stream.o virtch.o munitrk.o \ + $(LoaderObjs) $(PlayerObjs) $(DriverObjs) + +clean: + rm -f *.o + rm -f unix_drv/*.o + rm -f $(Lib_file) diff --git a/mikmod/makefile.gcc b/mikmod/makefile.gcc new file mode 100644 index 0000000..0be2e6c --- /dev/null +++ b/mikmod/makefile.gcc @@ -0,0 +1,55 @@ +# MikMod Library Makefile for DJGPP (*NOT* Linux) +# Divine Entertainment Game Programming Pack + + +#################### +### User Options ### +#################### + +# Use the C or C++ compiler +CC = gcc +Librarian = ar +Compiler_Options = -O2 -I. -I../include -g + +Lib_file = ../lib/mikmod.a +Lib_file2 = ..\lib\mikmod.a + +LoaderObjs = mloader.o mlreg.o npertab.o sloader.o load_uni.o \ + load_mod.o load_m15.o load_mtm.o load_s3m.o load_stm.o load_669.o \ + load_far.o load_dsm.o load_med.o load_xm.o load_ult.o load_it.o \ + s3m_it.o + +DriverObjs = mdriver.o mdreg.o drv_nos.o drv_raw.o dos_drv/mdma.o \ + dos_drv/mirq.o dos_drv/gus.o dos_drv/gusdrv1.o dos_drv/gusdrv2.o \ + dos_drv/sb.o dos_drv/sb16.o dos_drv/sbpro.o dos_drv/sndscape.o \ + dos_drv/pas16.o dos_drv/awe32.o dos_drv/wss.o + +DriverObjs2 = mdriver.o mdreg.o drv_nos.o drv_raw.o mdma.o \ + mirq.o gus.o gus_drv1.o gus_mix.o sb.o sb16.o sbpro.o sndscape.o \ + pas16.o awe32.o wss.o + +PlayerObjs = mplayer.o + +#################### +## Makefile rules ## +#################### + +all: $(Lib_file) + +$(Lib_file): stream.o virtch.o resample.o munitrk.o \ + $(LoaderObjs) $(DriverObjs) $(PlayerObjs) + del $(Lib_file2) + $(Librarian) r $(Lib_file) stream.o virtch.o resample.o munitrk.o \ + $(LoaderObjs) $(DriverObjs2) $(PlayerObjs) + +%.o: %.c + $(CC) -c $(Compiler_Options) $< + +# capital S is very important!!! +%.o: %.S + $(CC) -c $(Compiler_Options) $< + +clean: + del *.o + del dos_drv\*.o + del $(Lib_file2) diff --git a/mikmod/makefile.linux b/mikmod/makefile.linux new file mode 100644 index 0000000..981ba97 --- /dev/null +++ b/mikmod/makefile.linux @@ -0,0 +1,41 @@ +# MikMod Library Makefile for DJGPP Linux +# Divine Entertainment Game Programming Pack + + +#################### +### User Options ### +#################### + +# Use the C or C++ compiler +CC = gcc +CFLAGS = -O2 -I. -I../include -g -DOSS + +Lib_file = ../lib/libmikmod.a + +LoaderObjs = mloader.o mlreg.o npertab.o sloader.o load_uni.o \ + load_mod.o load_m15.o load_mtm.o load_s3m.o load_stm.o load_669.o \ + load_far.o load_dsm.o load_med.o load_xm.o load_ult.o load_it.o \ + s3m_it.o + +DriverObjs = mdriver.o mdreg.o drv_nos.o drv_raw.o drv_wav.o \ + unix_drv/drv_oss.o unix_drv/drv_stdout.o +# unix_drv/drv_AF.o unix_drv/drv_aix.o unix_drv/drv_hp.o +# unix_drv/drv_sun.o unix_drv/drv_sgi.o + +PlayerObjs = mplayer.o + +#################### +## Makefile rules ## +#################### + +all: $(Lib_file) + +$(Lib_file): stream.o virtch.o munitrk.o \ + $(LoaderObjs) $(DriverObjs) $(PlayerObjs) + ar r $(Lib_file) stream.o virtch.o munitrk.o \ + $(LoaderObjs) $(PlayerObjs) $(DriverObjs) + +clean: + rm -f *.o + rm -f unix_drv/*.o + rm -f $(Lib_file) diff --git a/mikmod/makefile.psp b/mikmod/makefile.psp new file mode 100644 index 0000000..de4c0fa --- /dev/null +++ b/mikmod/makefile.psp @@ -0,0 +1,40 @@ +# MikMod Library Makefile for PSP +# Divine Entertainment Game Programming Pack + + +#################### +### User Options ### +#################### + +# Use the C or C++ compiler +CC = psp-gcc +CFLAGS = -O2 -I. -I/usr/local/pspdev/psp/sdk/include -g -DPSP + +Lib_file = ../lib/libmikmod.a + +LoaderObjs = mloader.o mlreg.o npertab.o sloader.o load_uni.o mwav.o \ + load_mod.o load_m15.o load_mtm.o load_s3m.o load_stm.o load_669.o \ + load_far.o load_dsm.o load_med.o load_xm.o load_ult.o load_it.o \ + s3m_it.o load_wav.o + +DriverObjs = mdriver.o mdreg.o drv_nos.o + +PlayerObjs = mplayer.o + +mmioObjs = mmio/mmio.o mmio/mmalloc.o mmio/mmerror.o + +#################### +## Makefile rules ## +#################### + +all: $(Lib_file) + +$(Lib_file): stream.o virtch.o munitrk.o \ + $(LoaderObjs) $(DriverObjs) $(PlayerObjs) + psp-ar r $(Lib_file) stream.o virtch.o munitrk.o \ + $(LoaderObjs) $(PlayerObjs) $(DriverObjs) $(mmioObjs) + +clean: + rm -f *.o + rm -f unix_drv/*.o + rm -f $(Lib_file) diff --git a/mikmod/makefile.sgi b/mikmod/makefile.sgi new file mode 100644 index 0000000..690e791 --- /dev/null +++ b/mikmod/makefile.sgi @@ -0,0 +1,41 @@ +# MikMod Library Makefile for SGI + + +#################### +### User Options ### +#################### + +AUDIO_INCLUDES = -I/u/kanthak/include +AUDIO_LIBS = -L/u/kanthak/lib + + +# Use the C or C++ compiler +CC = cc +CFLAGS = -O2 -I. -I../include $(AUDIO_INCLUDES) -DSGI + +Lib_file = ../lib/libmikmod.a + +LoaderObjs = mloader.o mlreg.o npertab.o sloader.o load_uni.o \ + load_mod.o load_m15.o load_mtm.o load_s3m.o load_stm.o \ + load_669.o load_far.o load_dsm.o load_med.o load_xm.o \ + load_ult.o load_it.o s3m_it.o + +DriverObjs = mdriver.o mdreg.o drv_nos.o drv_raw.o drv_wav.o + +PlayerObjs = mplayer.o + +#################### +## Makefile rules ## +#################### + +all: $(Lib_file) + +$(Lib_file): stream.o virtch.o munitrk.o \ + $(LoaderObjs) $(DriverObjs) $(PlayerObjs) unix_drv/drv_sgi.o + ar r $(Lib_file) stream.o virtch.o munitrk.o \ + $(LoaderObjs) $(PlayerObjs) $(DriverObjs) drv_sgi.o + +clean: + rm -f *.o + rm -f unix_drv/*.o + rm -f $(Lib_file) diff --git a/mikmod/makefile.sun b/mikmod/makefile.sun new file mode 100644 index 0000000..381df80 --- /dev/null +++ b/mikmod/makefile.sun @@ -0,0 +1,39 @@ +# MikMod Library Makefile for Solaris + + +#################### +### User Options ### +#################### + +# Use the C or C++ compiler +CC = gcc +CFLAGS = -O2 -I. -I../include -DSOLARIS -DUSE_HEADPHONE +# USE_HEADPHONE above forces the sound ouput to go to the headphones instead of +# the speaker. This flag is optional. + +Lib_file = ../lib/libmikmod.a + +LoaderObjs = mloader.o mlreg.o npertab.o sloader.o load_uni.o \ + load_mod.o load_m15.o load_mtm.o load_s3m.o load_stm.o \ + load_669.o load_far.o load_dsm.o load_med.o load_xm.o \ + load_ult.o load_it.o s3m_it.o + +DriverObjs = mdriver.o mdreg.o drv_nos.o drv_raw.o drv_wav.o + +PlayerObjs = mplayer.o + +#################### +## Makefile rules ## +#################### + +all: $(Lib_file) + +$(Lib_file): stream.o virtch.o munitrk.o \ + $(LoaderObjs) $(DriverObjs) $(PlayerObjs) unix_drv/drv_sun.o + ar r $(Lib_file) stream.o virtch.o munitrk.o \ + $(LoaderObjs) $(PlayerObjs) $(DriverObjs) drv_sun.o + +clean: + rm -f *.o + rm -f unix_drv/*.o + rm -f $(Lib_file) diff --git a/mikmod/mdreg.c b/mikmod/mdreg.c new file mode 100644 index 0000000..a8bd2a1 --- /dev/null +++ b/mikmod/mdreg.c @@ -0,0 +1,64 @@ +/* + + Name: MDREG.C + + Description: + A single routine for registering all drivers in MikMod for the current + platform. + + Portability: + DOS, WIN95, OS2, SunOS, Solaris, + Linux, HPUX, AIX, SGI, Alpha + + Anything not listed above is assumed to not be supported by this procedure! + + All Others: n + + - all compilers! + +*/ + +#include "mikmod.h" + +void MikMod_RegisterAllDrivers(void) +{ + +#ifdef SUN + MikMod_RegisterDriver(drv_sun); +#elif defined(PSP) + MikMod_RegisterDriver(drv_psp); +#elif defined(SOLARIS) + MikMod_RegisterDriver(drv_sun); +#elif defined(__alpha) + MikMod_RegisterDriver(drv_AF); +#elif defined(OSS) + MikMod_RegisterDriver(drv_oss); + MikMod_RegisterDriver(drv_stdout); + #ifdef ULTRA + MikMod_RegisterDriver(drv_ultra); + #endif /* ULTRA */ +#elif defined(__hpux) + MikMod_RegisterDriver(drv_hp); +#elif defined(AIX) + MikMod_RegisterDriver(drv_aix); +#elif defined(SGI) + MikMod_RegisterDriver(drv_sgi); +#elif defined(__OS2__) + MikMod_RegisterDriver(drv_os2); +#elif defined(__WIN32__) + MikMod_RegisterDriver(drv_w95); +#else + MikMod_RegisterDriver(drv_awe); + MikMod_RegisterDriver(drv_gus); +/* MikMod_RegisterDriver(drv_gus2); // use for hardware mixing only (smaller / faster) */ + MikMod_RegisterDriver(drv_pas); + MikMod_RegisterDriver(drv_wss); + MikMod_RegisterDriver(drv_ss); + MikMod_RegisterDriver(drv_sb16); + MikMod_RegisterDriver(drv_sbpro); + MikMod_RegisterDriver(drv_sb); +#endif + +} + + diff --git a/mikmod/mdriver.c b/mikmod/mdriver.c new file mode 100644 index 0000000..b97971a --- /dev/null +++ b/mikmod/mdriver.c @@ -0,0 +1,559 @@ +/* + +Name: MDRIVER.C + +Description: +These routines are used to access the available soundcard drivers. + +Portability: +All systems - all compilers + +*/ + +#include "mikmod.h" + +MDRIVER *firstdriver = NULL, *md_driver = &drv_nos; +extern UNIMOD *pf; /* <- this modfile is being played */ + +UWORD md_device = 0; +//Brunni/ Pour resampler, répète 1 << md_mixshift fois le même sample. +UWORD md_mixshift = 0; +UWORD md_mixfreq = 44100; +UWORD md_mode = DMODE_STEREO | DMODE_16BITS | DMODE_SURROUND; +UWORD md_dmabufsize = 50; +UBYTE md_pansep = 128; /* 128 == 100% (full left/right) */ + +UBYTE md_reverb = 6; /* Reverb */ + +UBYTE md_volume = 96; /* Global sound volume (0-128) */ +UBYTE md_musicvolume = 128; /* volume of song */ +UBYTE md_sndfxvolume = 128; /* volume of sound effects */ + +UBYTE md_bpm = 125; + + +/* Do not modify the numchn variables yourself! use MD_SetVoices() */ + +UBYTE md_numchn = 0, md_sngchn = 0, md_sfxchn = 0; +UBYTE md_hardchn = 0, md_softchn = 0; + + +void (*md_player)(void) = Player_HandleTick; +static BOOL isplaying = 0, initialized = 0; +static UBYTE *sfxinfo; +static int sfxpool; + +static SAMPLE **md_sample = NULL; + +/* Backup variables. This way, the end programmer can fiddle with the */ +/* main globals without mikmod blowing up. */ + +static UWORD idevice, imixfreq, imode, idmabufsize; + + +static void LimitHardVoices(int limit) + +/* Limits the number of hardware voices to the specified amount. */ +/* This function should only be used by the low-level drivers. */ + +{ + int t = 0; + + if(!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn > limit)) md_sfxchn = limit; + if(!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn > limit)) md_sngchn = limit; + + if(!(md_mode & DMODE_SOFT_SNDFX)) + md_hardchn = md_sfxchn; + else + md_hardchn = 0; + + if(!(md_mode & DMODE_SOFT_MUSIC)) + md_hardchn += md_sngchn; + + while(md_hardchn > limit) + { + if(++t & 1) + if(!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn > 4)) md_sfxchn--; + else + if(!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn > 8)) md_sngchn--; + + if(!(md_mode & DMODE_SOFT_SNDFX)) + md_hardchn = md_sfxchn; + else + md_hardchn = 0; + + if(!(md_mode & DMODE_SOFT_MUSIC)) + md_hardchn += md_sngchn; + } + + md_numchn = md_hardchn + md_softchn; +} + + +static void LimitSoftVoices(int limit) + +/* Limits the number of hardware voices to the specified amount. */ +/* This function should only be used by the low-level drivers. */ + +{ + int t = 0; + + if((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn > limit)) md_sfxchn = limit; + if((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn > limit)) md_sngchn = limit; + + if(md_mode & DMODE_SOFT_SNDFX) + md_softchn = md_sfxchn; + else + md_softchn = 0; + + if(md_mode & DMODE_SOFT_MUSIC) + md_softchn += md_sngchn; + + while(md_softchn > limit) + { + if(++t & 1) + if((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn > 4)) md_sfxchn--; + else + if((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn > 8)) md_sngchn--; + + if(!(md_mode & DMODE_SOFT_SNDFX)) + md_softchn = md_sfxchn; + else + md_softchn = 0; + + if(!(md_mode & DMODE_SOFT_MUSIC)) + md_softchn += md_sngchn; + } + + md_numchn = md_hardchn + md_softchn; +} + + +/* Note: 'type' indicates whether the returned value should be for music */ +/* or for sound effects. */ + +ULONG MD_SampleSpace(int type) +{ + if(type==MD_MUSIC) + type = (md_mode & DMODE_SOFT_MUSIC) ? MD_SOFTWARE : MD_HARDWARE; + else if(type==MD_SNDFX) + type = (md_mode & DMODE_SOFT_SNDFX) ? MD_SOFTWARE : MD_HARDWARE; + + return md_driver->FreeSampleSpace(type); +} + + +ULONG MD_SampleLength(int type, SAMPLE *s) +{ + if(type==MD_MUSIC) + type = (md_mode & DMODE_SOFT_MUSIC) ? MD_SOFTWARE : MD_HARDWARE; + else if(type==MD_SNDFX) + type = (md_mode & DMODE_SOFT_SNDFX) ? MD_SOFTWARE : MD_HARDWARE; + + return md_driver->RealSampleLength(type, s); +} + + +UWORD MD_SetDMA(int secs) + +/* Converts the given number of 1/10th seconds into the number of bytes of */ +/* audio that a sample # 1/10th seconds long would require at the current md_* */ +/* settings. */ + +{ + ULONG result; + + result = (md_mixfreq * ((md_mode & DMODE_STEREO) ? 2 : 1) * + ((md_mode & DMODE_16BITS) ? 2 : 1) * secs) * 10; + + if(result > 32000) result = 32000; + return(md_dmabufsize = (result & ~3)); /* round it off to an 8 byte boundry */ +} + + +void MD_InfoDriver(void) +{ + int t; + MDRIVER *l; + + /* list all registered devicedrivers: */ + for(t=1,l=firstdriver; l!=NULL; l=l->next, t++) + printf("%d. %s\n",t,l->Version); +} + + +void MD_RegisterDriver(MDRIVER *drv) +{ + MDRIVER *cruise = firstdriver; + + if(cruise!=NULL) + { while(cruise->next!=NULL) cruise = cruise->next; + cruise->next = drv; + } else + firstdriver = drv; +} + + +SWORD MD_SampleLoad(SAMPLOAD *s, int type, VIRTUAL_FILE *fp) +/* type - sample type .. MD_MUSIC or MD_SNDFX */ +{ + SWORD result; + + if(type==MD_MUSIC) + type = (md_mode & DMODE_SOFT_MUSIC) ? MD_SOFTWARE : MD_HARDWARE; + else if(type==MD_SNDFX) + type = (md_mode & DMODE_SOFT_SNDFX) ? MD_SOFTWARE : MD_HARDWARE; + + SL_Init(s); + result = md_driver->SampleLoad(s, type, fp); + SL_Exit(s); + + return result; +} + + +void MD_SampleUnLoad(SWORD handle) +{ + md_driver->SampleUnLoad(handle); +} + + +void MD_SetBPM(UBYTE bpm) +{ + md_bpm = bpm; +} + + +void MikMod_RegisterPlayer(void (*player)(void)) +{ + md_player = player; +} + + +void MikMod_Update(void) +{ + if(isplaying && !(pf->forbid)) md_driver->Update(); +} + + +void Voice_SetVolume(int voice, UWORD vol) +{ + ULONG tmp; + + if((voice<0) || (voice>=md_numchn)) return; + tmp = (ULONG)vol * (ULONG)md_volume * ((voice < md_sngchn) ? (ULONG)md_musicvolume : (ULONG)md_sndfxvolume); + md_driver->VoiceSetVolume(voice,tmp/16384UL); +} + + +void Voice_SetFrequency(int voice, ULONG frq) +{ + if((voice < 0) || (voice >= md_numchn)) return; + if(md_sample[voice]!=NULL && md_sample[voice]->divfactor!=0) frq/=md_sample[voice]->divfactor; + md_driver->VoiceSetFrequency(voice, frq); +} + + +void Voice_SetPanning(int voice, ULONG pan) +{ + if((voice < 0) || (voice >= md_numchn)) return; + if(pan!=PAN_SURROUND) + { if(md_mode & DMODE_REVERSE) pan = 255-pan; + pan = (((SWORD)(pan-128)*md_pansep) / 128)+128; + } + md_driver->VoiceSetPanning(voice, pan); +} + + +void Voice_Play(int voice, SAMPLE *s, ULONG start) +{ + ULONG repend; + + if((voice < 0) || (voice >= md_numchn) || (start >= s->length)) return; + + md_sample[voice] = s; + repend = s->loopend; + + if(s->flags&SF_LOOP) + if(repend > s->length) repend = s->length; /* repend can't be bigger than size */ + + md_driver->VoicePlay(voice,s->handle,start,s->length,s->loopstart,repend,s->flags); +} + + +void Voice_Stop(int voice) +{ + if((voice < 0) || (voice >= md_numchn)) return; + if(voice >= md_sngchn) + { /* It is a sound effects channel, so flag the voice as non-critical! */ + sfxinfo[voice-md_sngchn] = 0; + } + + md_driver->VoiceStop(voice); +} + + +BOOL Voice_Stopped(int voice) +{ + if((voice < 0) || (voice >= md_numchn)) return 0; + return(md_driver->VoiceStopped(voice)); +} + + +SLONG Voice_GetPosition(int voice) +{ + if((voice < 0) || (voice >= md_numchn)) return 0; + return(md_driver->VoiceGetPosition(voice)); +} + + +ULONG Voice_RealVolume(int voice) +{ + if((voice < 0) || (voice >= md_numchn)) return 0; + return(md_driver->VoiceRealVolume(voice)); +} + + +/* ================================ */ +/* Functions prefixed with MikMod */ +/* ================================ */ + +BOOL MikMod_Init(void) +{ + UWORD t; + + _mm_critical = 1; + + /* if md_device==0, try to find a device number */ + + if(md_device==0) + { for(t=1,md_driver=firstdriver; md_driver!=NULL; md_driver=md_driver->next, t++) + { if(md_driver->IsPresent()) break; + } + + if(md_driver==NULL) + { _mm_errno = MMERR_DETECTING_DEVICE; + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + md_driver = &drv_nos; + return 1; + } + + md_device = t; + } else + { /* if n>0 use that driver */ + for(t=1,md_driver=firstdriver; (md_driver!=NULL) && (t!=md_device); md_driver=md_driver->next, t++); + + if(md_driver==NULL) + { _mm_errno = MMERR_INVALID_DEVICE; + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + md_driver = &drv_nos; + return 1; + } + + if(!md_driver->IsPresent()) + { _mm_errno = MMERR_DETECTING_DEVICE; + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + md_driver = &drv_nos; + return 1; + } + } + + if(md_driver->Init()) + { MikMod_Exit(); + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + return 1; + } + + idevice = md_device; imode = md_mode; + imixfreq = md_mixfreq; idmabufsize = md_dmabufsize; + initialized = 1; + _mm_critical = 0; + + return 0; +} + + +void MikMod_Exit(void) +{ + MikMod_DisableOutput(); + md_driver->Exit(); + md_numchn = md_sfxchn = md_sngchn = 0; + md_driver = &drv_nos; + initialized = 0; +} + + +BOOL MikMod_Reset(void) + +/* Reset the driver using the new global variable settings. */ +/* If the driver has not been initialized, it will be now. */ + +{ + if(!initialized) return MikMod_Init(); + if((md_driver->Reset == NULL) || (md_device != idevice)) + { /* md_driver->Reset was NULL, or md_device was changed, */ + /* so do a full reset of the driver. */ + + if(isplaying) md_driver->PlayStop(); + md_driver->Exit(); + if(MikMod_Init()) + { MikMod_Exit(); + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + return 1; + } + if(isplaying) md_driver->PlayStart(); + } else + { if(md_driver->Reset()) + { MikMod_Exit(); + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + return 1; + } + } + + return 0; +} + + +BOOL MikMod_SetNumVoices(int music, int sfx) + +/* If either parameter is -1, the current set value will be retained. */ + +{ + BOOL resume = 0; + int t, oldchn = 0; + + if((music==0) && (sfx==0)) return 0; + + _mm_critical = 1; + + if(isplaying) + { MikMod_DisableOutput(); + oldchn = md_numchn; + resume = 1; + } + + if(sfxinfo!=NULL) free(sfxinfo); + if(md_sample!=NULL) free(md_sample); + md_sample = NULL; + sfxinfo = NULL; + + /*md_softchn = md_hardchn = 0; + + if(md_mode & DMODE_SOFT_SNDFX) + md_softchn = sfx; else md_hardchn = sfx; + + if(md_mode & DMODE_SOFT_MUSIC) + md_softchn += music; else md_hardchn += music; + */ + + if(music != -1) md_sngchn = music; + if(sfx != -1) md_sfxchn = sfx; + + md_numchn = md_sngchn + md_sfxchn; + + LimitHardVoices(md_driver->HardVoiceLimit); + LimitSoftVoices(md_driver->SoftVoiceLimit); + + if(md_driver->SetNumVoices()) + { MikMod_Exit(); + md_numchn = md_softchn = md_hardchn = md_sfxchn = md_sngchn = 0; + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + return 1; + } + + if(md_sngchn || md_sfxchn) + md_sample = (SAMPLE **)_mm_calloc(md_sngchn+md_sfxchn, sizeof(SAMPLE *)); + if(md_sfxchn) + sfxinfo = (UBYTE *)_mm_calloc(md_sfxchn, sizeof(UBYTE)); + + /* make sure the player doesn't start with garbage */ + for(t=oldchn; tPlayStart()) return 1; + isplaying = 1; + } + _mm_critical = 0; + return 0; +} + + +void MikMod_DisableOutput(void) +{ + /* safety valve, prevents calling playStop when playstart */ + /* hasn't been called: */ + + if(isplaying && md_driver!=NULL) + { isplaying = 0; + md_driver->PlayStop(); + } +} + + +BOOL MikMod_Active(void) +{ + return isplaying; +} + + +int MikMod_PlaySample(SAMPLE *s, ULONG start, UBYTE flags) + +/* Plays a sound effects sample. Picks a voice from the number of voices */ +/* allocated for use as sound effects (loops through voices, skipping all */ +/* active criticals). */ +/* */ +/* Returns the voice that the sound is being played on. */ + +{ + int orig = sfxpool; /* for cases where all channels are critical */ + int c; + + if(md_sfxchn==0) return -1; + if(s->volume > 64) s->volume = 64; + + /* check the first location after sfxpool */ + do + { if(sfxinfo[sfxpool] & SFX_CRITICAL) + { if(md_driver->VoiceStopped(c=sfxpool+md_sngchn)) + { sfxinfo[sfxpool] = flags; + Voice_Play(c, s, start); + md_driver->VoiceSetVolume(c,s->volume<<2); + md_driver->VoiceSetPanning(c,s->panning); + md_driver->VoiceSetFrequency(c,s->speed); + sfxpool++; + if(sfxpool >= md_sfxchn) sfxpool = 0; + return c; + } + } else + { sfxinfo[sfxpool] = flags; + Voice_Play(c=sfxpool+md_sngchn, s, start); + md_driver->VoiceSetVolume(c,s->volume<<2); + md_driver->VoiceSetPanning(c,s->panning); + md_driver->VoiceSetFrequency(c,s->speed); + sfxpool++; + if(sfxpool >= md_sfxchn) sfxpool = 0; + return c; + } + + sfxpool++; + if(sfxpool >= md_sfxchn) sfxpool = 0; + } while(sfxpool!=orig); + + return -1; +} + diff --git a/mikmod/mikmod.h b/mikmod/mikmod.h new file mode 100644 index 0000000..0a4f723 --- /dev/null +++ b/mikmod/mikmod.h @@ -0,0 +1,417 @@ +#ifndef _MIKMOD_H +#define _MIKMOD_H + +#include "mmio.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define MUTE_EXCLUSIVE 32000 +#define MUTE_INCLUSIVE 32001 + +#define PAN_LEFT 0 +#define PAN_CENTER 128 +#define PAN_RIGHT 255 +#define PAN_SURROUND 512 /* panning value for Dolby Surround */ + + +#define MikMod_RegisterDriver(x) MD_RegisterDriver(&x) +#define MikMod_RegisterLoader(x) ML_RegisterLoader(&x) +#define MikMod_RegisterErrorHandler(x) _mm_RegisterErrorHandler(x) + + +/* The following #define macros are for retaining API compatiability */ +/* with the beta version of MikMod 3.0, and are TEMPORARY! They WILL */ +/* be removed in the future! */ + +#define MD_RegisterPlayer(x) MikMod_RegisterPlayer(x) +#define MD_Init MikMod_Init +#define MD_Exit MikMod_Exit +#define MD_Update MikMod_Update +#define ML_Free(x) MikMod_FreeSong(x) +#define MD_SetNumChannels(x,y) MikMod_SetNumVoices(x,y) +#define MD_SetNumVoices(x,y) MikMod_SetNumVoices(x,y) +#define MD_PlayStart MikMod_EnableOutput +#define MD_PlayStop MikMod_DisableOutput + +#define MD_VoiceSetVolume(x,y) Voice_SetVolume(x,y) +#define MD_VoiceSetFrequency(x,y) Voice_SetFrequency(x,y) +#define MD_VoiceSetPanning(x,y) Voice_SetPanning(x,y) +#define MD_VoicePlay(x,y,z) Voice_Play(x,y,z) +#define MD_VoiceStop(x) Voice_Stop(x) +#define MD_VoiceReleaseSustain(x) Voice_ReleaseSustain(x) +#define MD_VoiceStopped(x) Voice_Stopped(x) +#define MD_VoiceGetPosition(x) Voice_GetPosition(x) +#define MD_VoiceRealVolume(x) Voice_RealVolume(x) + + +#define SFX_CRITICAL 1 + + +/************************************************************************** +****** mikmod types: ****************************************************** +**************************************************************************/ + +/* Sample format [loading and in-memory] flags: */ +#define SF_16BITS 1 +#define SF_SIGNED 2 +#define SF_STEREO 4 +#define SF_DELTA 8 +#define SF_BIG_ENDIAN 16 + +/* General Playback flags */ + +#define SF_LOOP 32 +#define SF_BIDI 64 +#define SF_SUSTAIN 128 +#define SF_REVERSE 256 + +/* Module-only Playback Flags */ + +#define SF_OWNPAN 512 +#define SF_UST_LOOP 1024 + + +typedef struct SAMPLE +{ ULONG speed; /* Base playing speed/frequency of note (Middle C in player) */ + UBYTE volume; /* volume 0-64 */ + UWORD panning; /* panning (0-255 or PAN_SURROUND) */ + ULONG length; /* length of sample (in samples!) */ + ULONG loopstart; /* repeat position (relative to start, in samples) */ + ULONG loopend; /* repeat end */ + ULONG susbegin; /* sustain loop begin (in samples) \ Not Supported */ + ULONG susend; /* sustain loop end / Yet! */ + + UWORD flags; /* sample format in memory */ + +/* Variables used by the module player only! (ignored for sound effects) */ + + UBYTE globvol; /* global volume */ + UBYTE vibflags; /* autovibrato flag stuffs */ + UBYTE vibtype; /* Vibratos moved from INSTRUMENT to SAMPLE */ + UBYTE vibsweep; + UBYTE vibdepth; + UBYTE vibrate; + + CHAR *samplename; /* name of the sample */ + +/* Values used internally only (not saved in disk formats) */ + + UWORD avibpos; /* autovibrato pos [player use] */ + UBYTE divfactor; /* for sample scaling (maintains proper period slides) */ + ULONG seekpos; /* seek position in file */ + SWORD handle; /* sample handle used by individual drivers */ +} SAMPLE; + + + +/* --> Struct : SAMPLOAD */ +/* This is a handle of sorts attached to any sample registered with */ +/* SL_RegisterSample. Generally, this only need be used or changed by the */ +/* loaders and drivers of mikmod. */ + +typedef struct SAMPLOAD +{ struct SAMPLOAD *next; + + ULONG length; /* length of sample (in samples!) */ + ULONG loopstart; /* repeat position (relative to start, in samples) */ + ULONG loopend; /* repeat end */ + + UWORD infmt, outfmt; + int scalefactor; + SAMPLE *sample; + VIRTUAL_FILE *fp; +} SAMPLOAD; + +extern void SL_HalveSample(SAMPLOAD *s); +extern void SL_Sample8to16(SAMPLOAD *s); +extern void SL_Sample16to8(SAMPLOAD *s); +extern void SL_SampleSigned(SAMPLOAD *s); +extern void SL_SampleUnsigned(SAMPLOAD *s); +extern BOOL SL_LoadSamples(void); /* Returns 1 on error! */ +extern SAMPLOAD *SL_RegisterSample(SAMPLE *s, int type, VIRTUAL_FILE *fp); /* Returns 1 on error! */ +extern void SL_Load(void *buffer, SAMPLOAD *smp, int length); +extern BOOL SL_Init(SAMPLOAD *s); +extern void SL_Exit(SAMPLOAD *s); + + +/************************************************************************** +****** Wavload stuff: ***************************************************** +**************************************************************************/ + +SAMPLE *WAV_LoadFP(VIRTUAL_FILE *fp); +SAMPLE *WAV_LoadFN(CHAR *filename); +void WAV_Free(SAMPLE *si); + + +#include "ptform.h" + + +/************************************************************************** +****** Driver stuff: ****************************************************** +**************************************************************************/ + +/* max. number of handles a driver has to provide. (not strict) */ + +#define MAXSAMPLEHANDLES 384 + + +enum +{ MD_MUSIC = 0, + MD_SNDFX +}; + +enum +{ MD_HARDWARE = 0, + MD_SOFTWARE +}; + + +/* possible mixing mode bits: */ +/* -------------------------- */ +/* These take effect only after MikMod_Init or MikMod_Reset. */ + +#define DMODE_16BITS 1 /* enable 16 bit output */ +#define DMODE_SURROUND 2 /* enable Dolby surround sound (not yet supported) */ +#define DMODE_SOFT_SNDFX 4 /* Process sound effects via software mixer (not yet supported) */ +#define DMODE_SOFT_MUSIC 8 /* Process music via software mixer (not yet supported) */ + +/* These take effect immidiately. */ + +#define DMODE_STEREO 16 /* enable stereo output */ +#define DMODE_REVERSE 32 /* reverse stereo */ +#define DMODE_INTERP 64 /* enable interpolation (not yet supported) */ + + +/* driver structure: */ + +typedef struct MDRIVER +{ struct MDRIVER *next; + CHAR *Name; + CHAR *Version; + UBYTE HardVoiceLimit, /* Limit of hardware mixer voices for this driver */ + SoftVoiceLimit; /* Limit of software mixer voices for this driver */ + + BOOL (*IsPresent) (void); + SWORD (*SampleLoad) (SAMPLOAD *s, int type, VIRTUAL_FILE *fp); + void (*SampleUnLoad) (SWORD handle); + ULONG (*FreeSampleSpace) (int type); + ULONG (*RealSampleLength) (int type, SAMPLE *s); + BOOL (*Init) (void); + void (*Exit) (void); + BOOL (*Reset) (void); + BOOL (*SetNumVoices) (void); + BOOL (*PlayStart) (void); + void (*PlayStop) (void); + void (*Update) (void); + void (*VoiceSetVolume) (UBYTE voice, UWORD vol); + void (*VoiceSetFrequency) (UBYTE voice, ULONG frq); + void (*VoiceSetPanning) (UBYTE voice, ULONG pan); + void (*VoicePlay) (UBYTE voice, SWORD handle, ULONG start, ULONG size, ULONG reppos, ULONG repend, UWORD flags); + void (*VoiceStop) (UBYTE voice); + BOOL (*VoiceStopped) (UBYTE voice); + void (*VoiceReleaseSustain)(UBYTE voice); + SLONG (*VoiceGetPosition) (UBYTE voice); + ULONG (*VoiceRealVolume) (UBYTE voice); + + BOOL (*StreamInit) (ULONG speed, UWORD flags); + void (*StreamExit) (void); + void (*StreamSetSpeed) (ULONG speed); + SLONG (*StreamGetPosition) (void); + void (*StreamLoadFP) (VIRTUAL_FILE *fp); +} MDRIVER; + + +/* These variables can be changed at ANY time and results */ +/* will be immidiate: */ + +extern UBYTE md_bpm; /* current song / hardware BPM rate */ +extern UBYTE md_volume; /* Global sound volume (0-128) */ +extern UBYTE md_musicvolume; /* volume of song */ +extern UBYTE md_sndfxvolume; /* volume of sound effects */ +extern UBYTE md_reverb; /* 0 = none; 15 = chaos */ +extern UBYTE md_pansep; /* 0 = mono; 128 == 100% (full left/right) */ + + +/* The variables below can be changed at any time, but changes will */ +/* not be implimented until MikMod_Reset is called. A call to */ +/* MikMod_Reset may result in a skip or pop in audio (depending on */ +/* the soundcard driver and the settings changed). */ + +extern UWORD md_device; /* Device. 0 = autodetect, other # depend on driver register order. */ +extern UWORD md_mixfreq; /* mixing frequency. Valid 5000 -> 44100 */ +extern UWORD md_mixshift; +extern UWORD md_dmabufsize; /* DMA buffer size. Valid 512 -> 32000 */ +extern UWORD md_mode; /* Mode. See DMODE_? flags above */ + + +/* Variables below can be changed via MD_SetNumVoices at any time. */ +/* However, a call to MD_SetNumVoicess while the driver */ +/* is active will cause the sound to skip slightly. */ + +extern UBYTE md_numchn, /* number of song + sound effects voices */ + md_sngchn, /* number of song voices */ + md_sfxchn, /* number of sound effects voices */ + md_hardchn, /* number of hardware mixed voices */ + md_softchn; /* number of software mixed voices */ + + +/* Following variables should not be changed! */ +extern MDRIVER *md_driver; /* Current driver in use. See MDRIVER struct */ + /* above for structure info contents. */ + +/* This is for use by the hardware drivers only. It points to the */ +/* registered tickhandler function. */ +extern void (*md_player)(void); + + +/* main driver prototypes: */ + +extern void MikMod_RegisterAllDrivers(void); +extern void MikMod_RegisterAllLoaders(void); + +extern BOOL MikMod_Init(void); +extern void MikMod_Exit(void); +extern BOOL MikMod_Reset(void); +extern int MikMod_PlaySample(SAMPLE *s, ULONG start, UBYTE flags); +extern BOOL MikMod_SetNumVoices(int music, int sndfx); +extern BOOL MikMod_Active(void); +extern BOOL MikMod_EnableOutput(void); +extern void MikMod_DisableOutput(void); +extern void MikMod_RegisterPlayer(void (*plr)(void)); +extern void MikMod_Update(void); + +extern void Voice_SetVolume(int voice, UWORD ivol); +extern void Voice_SetFrequency(int voice, ULONG frq); +extern void Voice_SetPanning(int voice, ULONG pan); +extern void Voice_Play(int voice,SAMPLE *s, ULONG start); +extern void Voice_Stop(int voice); +extern void Voice_ReleaseSustain(int voice); +extern BOOL Voice_Stopped(int voice); +extern SLONG Voice_GetPosition(int voice); +extern ULONG Voice_RealVolume(int voice); + +extern void MD_InfoDriver(void); +extern void MD_RegisterDriver(MDRIVER *drv); +extern SWORD MD_SampleLoad(SAMPLOAD *s, int type, VIRTUAL_FILE *fp); +extern void MD_SampleUnLoad(SWORD handle); +extern void MD_SetBPM(UBYTE bpm); +extern ULONG MD_SampleSpace(int type); +extern ULONG MD_SampleLength(int type, SAMPLE *s); + +/* Declare external drivers: */ + +extern MDRIVER drv_awe; /* experimental SB-AWE driver */ +extern MDRIVER drv_gus; /* gravis ultrasound driver [hardware / software mixing] */ +extern MDRIVER drv_gus2; /* gravis ultrasound driver [hardware mixing only] */ +extern MDRIVER drv_sb; /* soundblaster 1.5 / 2.0 DSP driver */ +extern MDRIVER drv_sbpro; /* soundblaster Pro DSP driver */ +extern MDRIVER drv_sb16; /* soundblaster 16 DSP driver */ +extern MDRIVER drv_ss; /* ensoniq soundscape driver */ +extern MDRIVER drv_pas; /* PAS16 driver */ +extern MDRIVER drv_wss; /* Windows Sound System driver */ +extern MDRIVER drv_nos; /* nosound driver */ +extern MDRIVER drv_raw; /* raw file output driver [music.raw] */ +extern MDRIVER drv_wav; /* RIFF WAVE file output driver [music.wav] */ + +extern MDRIVER drv_w95; /* win95 driver */ +extern MDRIVER drv_oss; /* linux voxware driver */ +extern MDRIVER drv_stdout; /* linux voxware driver */ +extern MDRIVER drv_AF; /* Dec Alpha AudioFile driver */ +extern MDRIVER drv_sun; /* Sun driver */ +extern MDRIVER drv_os2; /* Os2 driver */ +extern MDRIVER drv_hp; /* HP-UX /dev/audio driver */ +extern MDRIVER drv_aix; /* AIX audio-device driver */ +extern MDRIVER drv_sgi; /* SGI audio-device driver */ +extern MDRIVER drv_tim; /* timing driver */ +extern MDRIVER drv_ultra; /* ultra driver for linux */ +extern MDRIVER drv_psp; /* PSP driver */ + +/************************************************************************** +****** Streaming Audio stuff: ********************************************* +**************************************************************************/ + + +typedef struct MSTREAM +{ struct MSTREAM *next; + CHAR *type; + CHAR *version; + BOOL (*Init)(void); + BOOL (*Test)(void); + BOOL (*Load)(void); + void (*Cleanup)(void); +} MSTREAM; + + +extern int stream_bufsize; +extern VIRTUAL_FILE *stream_fp; +extern SLONG stream_seekpos; +extern SLONG stream_reppos; + + +/************************************************************************** +****** Virtual channel stuff: ********************************************* +**************************************************************************/ + +extern BOOL VC_Init(void); +extern void VC_Exit(void); +extern BOOL VC_SetNumVoices(void); +extern ULONG VC_SampleSpace(int type); +extern ULONG VC_SampleLength(int type, SAMPLE *s); + +extern BOOL VC_PlayStart(void); +extern void VC_PlayStop(void); + +/* extern SWORD VC_SampleLoad(SAMPLOAD *sload, int type, VIRTUAL_FILE *fp); */ +extern SWORD VC_SampleLoad(SAMPLOAD *sload, int type); +extern void VC_SampleUnload(SWORD handle); + +extern void VC_WriteSamples(SBYTE *buf,ULONG todo); +extern ULONG VC_WriteBytes(SBYTE *buf,ULONG todo); +extern void VC_SilenceBytes(SBYTE *buf,ULONG todo); + +extern void VC_VoiceSetVolume(UBYTE voice, UWORD vol); +extern void VC_VoiceSetFrequency(UBYTE voice, ULONG frq); +extern void VC_VoiceSetPanning(UBYTE voice, ULONG pan); +extern void VC_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags); + +extern void VC_VoiceStop(UBYTE voice); +extern BOOL VC_VoiceStopped(UBYTE voice); +extern void VC_VoiceReleaseSustain(UBYTE voice); +extern SLONG VC_VoiceGetPosition(UBYTE voice); +extern ULONG VC_VoiceRealVolume(UBYTE voice); + + +extern BOOL VC2_Init(void); +extern void VC2_Exit(void); +extern BOOL VC2_SetNumVoices(void); +extern ULONG VC2_SampleSpace(int type); +extern ULONG VC2_SampleLength(int type, SAMPLE *s); + +extern BOOL VC2_PlayStart(void); +extern void VC2_PlayStop(void); + +extern SWORD VC2_SampleLoad(SAMPLOAD *sload, int type, VIRTUAL_FILE *fp); +extern void VC2_SampleUnload(SWORD handle); + +extern void VC2_WriteSamples(SBYTE *buf,ULONG todo); +extern ULONG VC2_WriteBytes(SBYTE *buf,ULONG todo); +extern void VC2_SilenceBytes(SBYTE *buf,ULONG todo); + +extern void VC2_VoiceSetVolume(UBYTE voice, UWORD vol); +extern void VC2_VoiceSetFrequency(UBYTE voice, ULONG frq); +extern void VC2_VoiceSetPanning(UBYTE voice, ULONG pan); +extern void VC2_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags); + +extern void VC2_VoiceStop(UBYTE voice); +extern BOOL VC2_VoiceStopped(UBYTE voice); +extern void VC2_VoiceReleaseSustain(UBYTE voice); +extern SLONG VC2_VoiceGetPosition(UBYTE voice); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mikmod/mloader.c b/mikmod/mloader.c new file mode 100644 index 0000000..b99e49c --- /dev/null +++ b/mikmod/mloader.c @@ -0,0 +1,505 @@ +/* + +Name: MLOADER.C + +Description: + These routines are used to access the available module loaders + +Portability: + All systems - all compilers + +*/ + +#include +#include "mikmod.h" + + enum {OSL_MB_OK=1, OSL_MB_CANCEL, OSL_MB_YES, OSL_MB_NO, OSL_MB_QUIT}; + enum {OSL_KEY_SELECT=1, OSL_KEY_START=4, OSL_KEY_UP=5, OSL_KEY_RIGHT=6, OSL_KEY_DOWN=7, OSL_KEY_LEFT=8, OSL_KEY_L=9, OSL_KEY_R=10, + OSL_KEY_TRIANGLE=13, OSL_KEY_CIRCLE=14, OSL_KEY_CROSS=15, OSL_KEY_SQUARE=16, OSL_KEY_HOME=17, OSL_KEY_HOLD=18, OSL_KEY_NOTE=24}; + extern unsigned int oslMessageBox(const char *text, const char *title, unsigned int flags); + #define oslMake3Buttons(b1,a1,b2,a2,b3,a3) ((b1)|((a1)<<5)|((b2)<<9)|((a2)<<14)|((b3)<<18)|((a3)<<23)) + #define oslDebug(format...) ({ char __str2[1000], __str[1000]; sprintf(__str2, "Debug (%s:%i,%s)",__FUNCTION__,__LINE__,__FILE__); sprintf(__str , ##format); oslMessageBox(__str, __str2, oslMake3Buttons(OSL_KEY_CROSS,OSL_MB_OK,OSL_KEY_TRIANGLE,OSL_MB_QUIT,0,0)); }) + +VIRTUAL_FILE *modfp; +UNIMOD of; + +static MLOADER *firstloader = NULL; + +UWORD finetune[16] = +{ 8363, 8413, 8463, 8529, 8581, 8651, 8723, 8757, + 7895, 7941, 7985, 8046, 8107, 8169, 8232, 8280 +}; + + +void ML_InfoLoader(void) +{ + int t; + MLOADER *l; + + /* list all registered devicedrivers: */ + + for(t=1,l=firstloader; l!=NULL; l=l->next, t++) + printf("%d. %s\n",t,l->version); +} + + +void ML_RegisterLoader(MLOADER *ldr) +{ + MLOADER *cruise = firstloader; + + if(cruise!=NULL) + { while(cruise->next!=NULL) cruise = cruise->next; + cruise->next = ldr; + } else + firstloader = ldr; +} + + +BOOL ReadComment(UWORD len) +{ + /*int t; */ + + if(len) + { if(!(of.comment=(CHAR *)_mm_malloc(len+1))) return 0; + _mm_fread(of.comment,len,1,modfp); + of.comment[len] = 0; + } + return 1; +} + + +BOOL AllocPositions(int total) +{ + if((of.positions = _mm_calloc(total,sizeof(UWORD))) == NULL) return 0; + return 1; +} + + +BOOL AllocPatterns(void) +{ + int s,t,tracks = 0; + + /* Allocate track sequencing array */ + + if(!(of.patterns = (UWORD *)_mm_calloc((ULONG)(of.numpat+1)*of.numchn,sizeof(UWORD)))) return 0; + if(!(of.pattrows = (UWORD *)_mm_calloc(of.numpat+1,sizeof(UWORD)))) return 0; + + for(t=0; tlength) SL_RegisterSample(s,MD_MUSIC,modfp); + + return 1; +} + + +CHAR *DupStr(CHAR *s, UWORD len) +/* Creates a CSTR out of a character buffer of 'len' bytes, but strips */ +/* any terminating non-printing characters like 0, spaces etc. */ +{ + UWORD t; + CHAR *d = NULL; + + /* Scan for first printing char in buffer [includes high ascii up to 254] */ + while(len) + { if(s[len-1] > 0x20) break; + len--; + } + + /* When the buffer wasn't completely empty, allocate */ + /* a cstring and copy the buffer into that string, except */ + /* for any control-chars */ + +#ifdef __GNUC__ + if(len<16) len = 16; +#endif + + if((d=(CHAR *)_mm_malloc(len+1)) != NULL) + { for(t=0; thandle>=0) + MD_SampleUnLoad(s->handle); + if(s->samplename!=NULL) free(s->samplename); +} + + +static void ML_XFreeInstrument(INSTRUMENT *i) +{ + if(i->insname!=NULL) free(i->insname); +} + + +static void ML_FreeEx(UNIMOD *mf) +{ + UWORD t; + + if(mf->songname!=NULL) free(mf->songname); + if(mf->composer!=NULL) free(mf->composer); + if(mf->comment!=NULL) free(mf->comment); + + if(mf->modtype!=NULL) free(mf->modtype); + if(mf->positions!=NULL) free(mf->positions); + if(mf->patterns!=NULL) free(mf->patterns); + if(mf->pattrows!=NULL) free(mf->pattrows); + + if(mf->tracks!=NULL) + { for(t=0; tnumtrk; t++) + if(mf->tracks[t]!=NULL) free(mf->tracks[t]); + free(mf->tracks); + } + + if(mf->instruments != NULL) + { for(t=0; tnumins; t++) + ML_XFreeInstrument(&mf->instruments[t]); + free(mf->instruments); + } + + if(mf->samples != NULL) + { for(t=0; tnumsmp; t++) + if(mf->samples[t].length) ML_XFreeSample(&mf->samples[t]); + free(mf->samples); + } + + memset(mf,0,sizeof(UNIMOD)); +} + + +static UNIMOD *ML_AllocUniMod(void) +{ + UNIMOD *mf; + + if((mf=_mm_calloc(1,sizeof(UNIMOD))) == NULL) return NULL; + return mf; +} + + +/****************************************** + + Next are the user-callable functions + +******************************************/ + + +void MikMod_FreeSong(UNIMOD *mf) +{ + if(mf!=NULL) + { Player_Exit(mf); + ML_FreeEx(mf); + } +} + + +CHAR *MikMod_LoadSongTitle(CHAR *filename) +{ + MLOADER *l; + CHAR *retval; + VIRTUAL_FILE *fp; + + if((fp = _mm_fopen(filename,"rb"))==NULL) return NULL; + + _mm_errno = 0; + _mm_critical = 0; + _mm_iobase_setcur(modfp); + + /* Try to find a loader that recognizes the module */ + + for(l=firstloader; l!=NULL; l=l->next) + { _mm_rewind(modfp); + if(l->Test()) break; + } + + if(l==NULL) + { _mm_errno = MMERR_NOT_A_MODULE | 0x3000; + _mm_iobase_revert(); + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + return NULL; + } + + retval = l->LoadTitle(); + + _mm_fclose(fp); + return(retval); +} + +UNIMOD *MikMod_LoadSongFP(VIRTUAL_FILE *fp, int maxchan) + +/* Loads a module given a file pointer. */ +/* File is loaded from the current file seek position. */ + +{ + int t; + MLOADER *l; + BOOL ok; + UNIMOD *mf; + + modfp = fp; + _mm_errno = 0; + _mm_critical = 0; + + _mm_iobase_setcur(modfp); + + /* Try to find a loader that recognizes the module */ + + for(l=firstloader; l!=NULL; l=l->next) + { + _mm_rewind(modfp); + if(l->Test()) break; + } + + if(l==NULL) + { _mm_errno = MMERR_NOT_A_MODULE | 0x1000; + _mm_iobase_revert(); + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + return NULL; + } + + /* init unitrk routines */ + if(!UniInit()) + { if(_mm_errorhandler!=NULL) _mm_errorhandler(); + return NULL; + } + + /* load the song using the song's loader variable */ + memset(&of,0,sizeof(UNIMOD)); + of.initvolume = 128; + + /* init panning array */ + for(t=0; t<64; t++) of.panning[t] = ((t+1)&2) ? 255 : 0; + for(t=0; t<64; t++) of.chanvol[t] = 64; + + /* init module loader and load the header / patterns */ + if(l->Init()) + { _mm_rewind(modfp); + ok = l->Load(); + } else ok = 0; + + /* free loader and unitrk allocations */ + l->Cleanup(); + UniCleanup(); + + if(!ok) + { ML_FreeEx(&of); + _mm_iobase_revert(); + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + return NULL; + } + + if(!ML_LoadSamples()) + { ML_FreeEx(&of); + _mm_iobase_revert(); + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + return NULL; + } + + if((mf=ML_AllocUniMod()) == NULL) + { ML_FreeEx(&of); + _mm_iobase_revert(); + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + return NULL; + } + + /* Copy the static UNIMOD contents into the dynamic UNIMOD struct. */ + memcpy(mf,&of,sizeof(UNIMOD)); + + _mm_iobase_revert(); + + if(maxchan > 0) + { if(!(mf->flags & UF_NNA) && (mf->numchn < maxchan)) + maxchan = mf->numchn; + else if((mf->numvoices!=0) && mf->numvoices < maxchan) + maxchan = mf->numvoices; + + if(maxchan < mf->numchn) mf->flags |= UF_NNA; + + if(MikMod_SetNumVoices(maxchan,-1)) + { MikMod_FreeSong(mf); + return NULL; + } + } + + return mf; +} + + +UNIMOD *MikMod_LoadSong(CHAR *filename, int maxchan) + +/* Open a module via it's filename. The loader will initialize the specified */ +/* song-player 'player'. */ + +{ + VIRTUAL_FILE *fp; + UNIMOD *mf; + + if((fp = _mm_fopen(filename,"rb"))==NULL) return NULL; + VirtualFileSeek(fp, 0, SEEK_SET); + if((mf = MikMod_LoadSongFP(fp, maxchan)) != NULL) + { + if(SL_LoadSamples() || Player_Init(mf)) + { MikMod_FreeSong(mf); + mf = NULL; + } + } + + _mm_fclose(fp); + return mf; +} + +UNIMOD *MikMod_LoadSongVF(VIRTUAL_FILE *fp, int maxchan) + +/* Loads a module given a VIRTUAL_FILE. */ +/* File is loaded from the current file seek position. */ + +{ + int t; + MLOADER *l; + BOOL ok; + UNIMOD *mf; + + modfp = fp; + _mm_errno = 0; + _mm_critical = 0; + + _mm_iobase_setcur(modfp); + + /* Try to find a loader that recognizes the module */ + + for(l=firstloader; l!=NULL; l=l->next) + { _mm_rewind(modfp); + if(l->Test()) break; + } + + if(l==NULL) + { _mm_errno = MMERR_NOT_A_MODULE | 0x2000; + _mm_iobase_revert(); + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + return NULL; + } + + /* init unitrk routines */ + if(!UniInit()) + { if(_mm_errorhandler!=NULL) _mm_errorhandler(); + return NULL; + } + + /* load the song using the song's loader variable */ + memset(&of,0,sizeof(UNIMOD)); + of.initvolume = 128; + + /* init panning array */ + for(t=0; t<64; t++) of.panning[t] = ((t+1)&2) ? 255 : 0; + for(t=0; t<64; t++) of.chanvol[t] = 64; + + /* init module loader and load the header / patterns */ + if(l->Init()) + { _mm_rewind(modfp); + ok = l->Load(); + } else ok = 0; + + /* free loader and unitrk allocations */ + l->Cleanup(); + UniCleanup(); + + if(!ok) + { ML_FreeEx(&of); + _mm_iobase_revert(); + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + return NULL; + } + + if(!ML_LoadSamples()) + { ML_FreeEx(&of); + _mm_iobase_revert(); + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + return NULL; + } + + if((mf=ML_AllocUniMod()) == NULL) + { ML_FreeEx(&of); + _mm_iobase_revert(); + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + return NULL; + } + + /* Copy the static UNIMOD contents into the dynamic UNIMOD struct. */ + memcpy(mf,&of,sizeof(UNIMOD)); + + _mm_iobase_revert(); + + if(maxchan > 0) + { if(!(mf->flags & UF_NNA) && (mf->numchn < maxchan)) + maxchan = mf->numchn; + else if((mf->numvoices!=0) && mf->numvoices < maxchan) + maxchan = mf->numvoices; + + if(maxchan < mf->numchn) mf->flags |= UF_NNA; + + if(MikMod_SetNumVoices(maxchan,-1)) + { MikMod_FreeSong(mf); + return NULL; + } + } + + return mf; +} + diff --git a/mikmod/mlreg.c b/mikmod/mlreg.c new file mode 100644 index 0000000..9612801 --- /dev/null +++ b/mikmod/mlreg.c @@ -0,0 +1,31 @@ +/* + + Name: MLREG.C + + Description: + A single routine for registering all loaders in MikMod for the current + platform. + + Portability: + All systems - all compilers + +*/ + +#include "mikmod.h" + +void MikMod_RegisterAllLoaders(void) +{ + //Removed to save space +// MikMod_RegisterLoader(load_uni); + MikMod_RegisterLoader(load_it); + MikMod_RegisterLoader(load_xm); + MikMod_RegisterLoader(load_s3m); + MikMod_RegisterLoader(load_mod); +/* MikMod_RegisterLoader(load_mtm); + MikMod_RegisterLoader(load_stm); + MikMod_RegisterLoader(load_dsm); + MikMod_RegisterLoader(load_med); + MikMod_RegisterLoader(load_far); + MikMod_RegisterLoader(load_ult); + MikMod_RegisterLoader(load_669);*/ +} diff --git a/mikmod/mmio.h b/mikmod/mmio.h new file mode 100644 index 0000000..db5f90c --- /dev/null +++ b/mikmod/mmio.h @@ -0,0 +1,272 @@ +#ifndef _MMIO_H_ +#define _MMIO_H_ + +#include +#include "VirtualFile.h" +#include "tdefs.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* LOG.C Prototypes */ +/* ================ */ + +#define LOG_SILENT 0 +#define LOG_VERBOSE 1 + +extern int log_init(CHAR *logfile, BOOL val); +extern void log_exit(void); +extern void log_verbose(void); +extern void log_silent(void); +extern void printlog(CHAR *fmt, ... ); +extern void printlogv(CHAR *fmt, ... ); + +#ifdef __WATCOMC__ +#pragma aux log_init parm nomemory modify nomemory; +#pragma aux log_exit parm nomemory modify nomemory; +#pragma aux log_verbose parm nomemory modify nomemory; +#pragma aux log_silent parm nomemory modify nomemory; +#pragma aux printlog parm nomemory modify nomemory; +#pragma aux printlogv parm nomemory modify nomemory; +#endif + + + +/* MikMod's new error handling routines */ +/* ==================================== */ + +/* Specific Errors [referenced by _mm_errno] */ + +enum +{ MMERR_OPENING_FILE = 1, + MMERR_OUT_OF_MEMORY, + MMERR_END_OF_FILE, + MMERR_DISK_FULL, + MMERR_SAMPLE_TOO_BIG, + MMERR_OUT_OF_HANDLES, + MMERR_ALLOCATING_DMA, + MMERR_UNKNOWN_WAVE_TYPE, + MMERR_NOT_A_STREAM, + MMERR_LOADING_PATTERN, + MMERR_LOADING_TRACK, + MMERR_LOADING_HEADER, + MMERR_LOADING_SAMPLEINFO, + MMERR_NOT_A_MODULE, + MMERR_DETECTING_DEVICE, + MMERR_INVALID_DEVICE, + MMERR_INITIALIZING_MIXER +#ifdef SUN +#elif defined(SOLARIS) +#elif defined(__alpha) + ,MMERR_AF_AUDIO_PORT +#elif defined(OSS) + #ifdef ULTRA + #endif +#elif defined(__hpux) + ,MMERR_OPENING_DEVAUDIO, + MMERR_SETTING_NONBLOCKING, + MMERR_SETTING_SAMPLEFORMAT, + MMERR_SETTING_SAMPLERATE, + MMERR_SETTING_CHANNELS, + MMERR_SELECTING_AUDIO_OUTPUT, + MMERR_GETTING_AUDIO_DESC, + MMERR_GETTING_GAINS, + MMERR_SETTING_GAINS, + MMERR_SETTING_BUFFERSIZE +#elif defined(AIX) + ,MMERR_OPENING_AIX, + MMERR_AIX_CONFIG_INIT, + MMERR_AIX_CONFIG_CONTROL, + MMERR_AIX_CONFIG_START, + MMERR_AIX_NON_BLOCK +#elif defined(SGI) +#elif defined(__OS2__) +#elif defined(__WIN32__) +#else + ,MMERR_DETECTING_SOUNDCARD, + MMERR_SETTING_HIDMA +#endif +}; + +/* Memory allocation with error handling - MMALLOC.C */ +/* ================================================= */ + +extern void *_mm_malloc(size_t size); +extern void *_mm_calloc(size_t nitems, size_t size); + +extern void (*_mm_errorhandler)(void); +extern int _mm_errno; +extern BOOL _mm_critical; +extern CHAR *_mm_errmsg[]; + +extern void _mm_RegisterErrorHandler(void (*proc)(void)); +extern BOOL _mm_FileExists(CHAR *fname); + +extern void StringWrite(CHAR *s, VIRTUAL_FILE *fp); +extern CHAR *StringRead(VIRTUAL_FILE *fp); + + +/* MikMod/DivEnt style file input / output - */ +/* Solves several portability issues. */ +/* Notibly little vs. big endian machine complications. */ + +#define _mm_write_SBYTE(x,y) VirtualFilePutc((int)x,y) +#define _mm_write_UBYTE(x,y) VirtualFilePutc((int)x,y) + +#define _mm_read_SBYTE(x) (SBYTE)_mm_fgetc(x) +#define _mm_read_UBYTE(x) (UBYTE)_mm_fgetc(x) + +#define _mm_write_SBYTES(x,y,z) VirtualFileWrite((void *)x,1,y,z) +#define _mm_write_UBYTES(x,y,z) VirtualFileWrite((void *)x,1,y,z) +#define _mm_read_SBYTES(x,y,z) _mm_fread((void *)x,1,y,z) +#define _mm_read_UBYTES(x,y,z) _mm_fread((void *)x,1,y,z) + +#define _mm_rewind(x) _mm_fseek(x,0,SEEK_SET) + + +extern int _mm_fseek(VIRTUAL_FILE *stream, long offset, int whence); +extern long _mm_iobase_get(void); +extern void _mm_iobase_set(long iobase); +extern void _mm_iobase_setcur(VIRTUAL_FILE *fp); +extern void _mm_iobase_revert(void); +extern long _mm_ftell(VIRTUAL_FILE *stream); +extern long _mm_flength(VIRTUAL_FILE *stream); +extern VIRTUAL_FILE *_mm_fopen(CHAR *fname, CHAR *attrib); +extern int _mm_fclose(VIRTUAL_FILE *fp); +extern int _mm_feof(VIRTUAL_FILE *fp); +extern void _mm_fputs(VIRTUAL_FILE *fp, CHAR *data); +extern BOOL _mm_copyfile(VIRTUAL_FILE *fpi, VIRTUAL_FILE *fpo, ULONG len); +extern void _mm_write_string(CHAR *data, VIRTUAL_FILE *fp); +extern int _mm_read_string (CHAR *buffer, int number, VIRTUAL_FILE *fp); + + +/*extern SBYTE _mm_read_SBYTE (VIRTUAL_FILE *fp); */ +/*extern UBYTE _mm_read_UBYTE (VIRTUAL_FILE *fp); */ + +extern SWORD _mm_read_M_SWORD (VIRTUAL_FILE *fp); +extern SWORD _mm_read_I_SWORD (VIRTUAL_FILE *fp); + +extern UWORD _mm_read_M_UWORD (VIRTUAL_FILE *fp); +extern UWORD _mm_read_I_UWORD (VIRTUAL_FILE *fp); + +extern SLONG _mm_read_M_SLONG (VIRTUAL_FILE *fp); +extern SLONG _mm_read_I_SLONG (VIRTUAL_FILE *fp); + +extern ULONG _mm_read_M_ULONG (VIRTUAL_FILE *fp); +extern ULONG _mm_read_I_ULONG (VIRTUAL_FILE *fp); + + +/*extern int _mm_read_SBYTES (SBYTE *buffer, int number, VIRTUAL_FILE *fp); */ +/*extern int _mm_read_UBYTES (UBYTE *buffer, int number, VIRTUAL_FILE *fp); */ + +extern int _mm_read_M_SWORDS (SWORD *buffer, int number, VIRTUAL_FILE *fp); +extern int _mm_read_I_SWORDS (SWORD *buffer, int number, VIRTUAL_FILE *fp); + +extern int _mm_read_M_UWORDS (UWORD *buffer, int number, VIRTUAL_FILE *fp); +extern int _mm_read_I_UWORDS (UWORD *buffer, int number, VIRTUAL_FILE *fp); + +extern int _mm_read_M_SLONGS (SLONG *buffer, int number, VIRTUAL_FILE *fp); +extern int _mm_read_I_SLONGS (SLONG *buffer, int number, VIRTUAL_FILE *fp); + +extern int _mm_read_M_ULONGS (ULONG *buffer, int number, VIRTUAL_FILE *fp); +extern int _mm_read_I_ULONGS (ULONG *buffer, int number, VIRTUAL_FILE *fp); + + +/*extern void _mm_write_SBYTE (SBYTE data, VIRTUAL_FILE *fp); */ +/*extern void _mm_write_UBYTE (UBYTE data, VIRTUAL_FILE *fp); */ + +extern void _mm_write_M_SWORD (SWORD data, VIRTUAL_FILE *fp); +extern void _mm_write_I_SWORD (SWORD data, VIRTUAL_FILE *fp); + +extern void _mm_write_M_UWORD (UWORD data, VIRTUAL_FILE *fp); +extern void _mm_write_I_UWORD (UWORD data, VIRTUAL_FILE *fp); + +extern void _mm_write_M_SLONG (SLONG data, VIRTUAL_FILE *fp); +extern void _mm_write_I_SLONG (SLONG data, VIRTUAL_FILE *fp); + +extern void _mm_write_M_ULONG (ULONG data, VIRTUAL_FILE *fp); +extern void _mm_write_I_ULONG (ULONG data, VIRTUAL_FILE *fp); + +/*extern void _mm_write_SBYTES (SBYTE *data, int number, VIRTUAL_FILE *fp); */ +/*extern void _mm_write_UBYTES (UBYTE *data, int number, VIRTUAL_FILE *fp); */ + +extern void _mm_write_M_SWORDS (SWORD *data, int number, VIRTUAL_FILE *fp); +extern void _mm_write_I_SWORDS (SWORD *data, int number, VIRTUAL_FILE *fp); + +extern void _mm_write_M_UWORDS (UWORD *data, int number, VIRTUAL_FILE *fp); +extern void _mm_write_I_UWORDS (UWORD *data, int number, VIRTUAL_FILE *fp); + +extern void _mm_write_M_SLONGS (SLONG *data, int number, VIRTUAL_FILE *fp); +extern void _mm_write_I_SLONGS (SLONG *data, int number, VIRTUAL_FILE *fp); + +extern void _mm_write_M_ULONGS (ULONG *data, int number, VIRTUAL_FILE *fp); +extern void _mm_write_I_ULONGS (ULONG *data, int number, VIRTUAL_FILE *fp); + +#ifdef __WATCOMC__ +#pragma aux _mm_fseek parm nomemory modify nomemory +#pragma aux _mm_ftell parm nomemory modify nomemory +#pragma aux _mm_flength parm nomemory modify nomemory +#pragma aux _mm_fopen parm nomemory modify nomemory +#pragma aux _mm_fputs parm nomemory modify nomemory +#pragma aux _mm_copyfile parm nomemory modify nomemory +#pragma aux _mm_iobase_get parm nomemory modify nomemory +#pragma aux _mm_iobase_set parm nomemory modify nomemory +#pragma aux _mm_iobase_setcur parm nomemory modify nomemory +#pragma aux _mm_iobase_revert parm nomemory modify nomemory +#pragma aux _mm_write_string parm nomemory modify nomemory +#pragma aux _mm_read_string parm nomemory modify nomemory + +#pragma aux _mm_read_M_SWORD parm nomemory modify nomemory; +#pragma aux _mm_read_I_SWORD parm nomemory modify nomemory; +#pragma aux _mm_read_M_UWORD parm nomemory modify nomemory; +#pragma aux _mm_read_I_UWORD parm nomemory modify nomemory; +#pragma aux _mm_read_M_SLONG parm nomemory modify nomemory; +#pragma aux _mm_read_I_SLONG parm nomemory modify nomemory; +#pragma aux _mm_read_M_ULONG parm nomemory modify nomemory; +#pragma aux _mm_read_I_ULONG parm nomemory modify nomemory; + +#pragma aux _mm_read_M_SWORDS parm nomemory modify nomemory; +#pragma aux _mm_read_I_SWORDS parm nomemory modify nomemory; +#pragma aux _mm_read_M_UWORDS parm nomemory modify nomemory; +#pragma aux _mm_read_I_UWORDS parm nomemory modify nomemory; +#pragma aux _mm_read_M_SLONGS parm nomemory modify nomemory; +#pragma aux _mm_read_I_SLONGS parm nomemory modify nomemory; +#pragma aux _mm_read_M_ULONGS parm nomemory modify nomemory; +#pragma aux _mm_read_I_ULONGS parm nomemory modify nomemory; + +#pragma aux _mm_write_M_SWORD parm nomemory modify nomemory; +#pragma aux _mm_write_I_SWORD parm nomemory modify nomemory; +#pragma aux _mm_write_M_UWORD parm nomemory modify nomemory; +#pragma aux _mm_write_I_UWORD parm nomemory modify nomemory; +#pragma aux _mm_write_M_SLONG parm nomemory modify nomemory; +#pragma aux _mm_write_I_SLONG parm nomemory modify nomemory; +#pragma aux _mm_write_M_ULONG parm nomemory modify nomemory; +#pragma aux _mm_write_I_ULONG parm nomemory modify nomemory; + +#pragma aux _mm_write_M_SWORDS parm nomemory modify nomemory; +#pragma aux _mm_write_I_SWORDS parm nomemory modify nomemory; +#pragma aux _mm_write_M_UWORDS parm nomemory modify nomemory; +#pragma aux _mm_write_I_UWORDS parm nomemory modify nomemory; +#pragma aux _mm_write_M_SLONGS parm nomemory modify nomemory; +#pragma aux _mm_write_I_SLONGS parm nomemory modify nomemory; +#pragma aux _mm_write_M_ULONGS parm nomemory modify nomemory; +#pragma aux _mm_write_I_ULONGS parm nomemory modify nomemory; +#endif + + +#ifndef __WATCOMC__ +#ifndef __GNUC__ +#ifndef SGI +extern CHAR *strdup(CHAR *str); +#endif +#endif +#endif + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/mikmod/mmio/Makefile b/mikmod/mmio/Makefile new file mode 100644 index 0000000..e11ffbd --- /dev/null +++ b/mikmod/mmio/Makefile @@ -0,0 +1,29 @@ +# MMIO Library Makefile for Linux +# Divine Entertainment Game Programming Pack +# + +########################## +## User settable macros ## +########################## + +Compiler = gcc +Librarian = ar +Compiler_Options = -O2 -I. -I../mikmod -I../include -g + +Lib_file = ../lib/libmmio.a + +Object_files = mmio.o mmalloc.o mmerror.o + +#################### +## Makefile rules ## +#################### + +$(Lib_file): $(Object_files) + $(Librarian) r $(Lib_file) $(Object_files) + +%.o: %.c + $(CC) -c $(Compiler_Options) $< + +clean: + rm -f *.o + rm -f $(Lib_file) diff --git a/mikmod/mmio/makefile.freebsd b/mikmod/mmio/makefile.freebsd new file mode 100644 index 0000000..6afded9 --- /dev/null +++ b/mikmod/mmio/makefile.freebsd @@ -0,0 +1,29 @@ +# MMIO Library Makefile for FreeBSD +# Divine Entertainment Game Programming Pack +# + +########################## +## User settable macros ## +########################## + +Compiler = gcc +Librarian = ar +Compiler_Options = -Wall -O6 -funroll-loops -ffast-math -finline-functions -fomit-frame-pointer -pipe -I. -I../mikmod -I../include + +Lib_file = ../lib/libmmio.a + +Object_files = mmio.o mmalloc.o mmerror.o + +#################### +## Makefile rules ## +#################### + +$(Lib_file): $(Object_files) + $(Librarian) r $(Lib_file) $(Object_files) + +%.o: %.c + $(CC) -c $(Compiler_Options) $< + +clean: + rm -f *.o + rm -f $(Lib_file) diff --git a/mikmod/mmio/makefile.linux b/mikmod/mmio/makefile.linux new file mode 100644 index 0000000..e11ffbd --- /dev/null +++ b/mikmod/mmio/makefile.linux @@ -0,0 +1,29 @@ +# MMIO Library Makefile for Linux +# Divine Entertainment Game Programming Pack +# + +########################## +## User settable macros ## +########################## + +Compiler = gcc +Librarian = ar +Compiler_Options = -O2 -I. -I../mikmod -I../include -g + +Lib_file = ../lib/libmmio.a + +Object_files = mmio.o mmalloc.o mmerror.o + +#################### +## Makefile rules ## +#################### + +$(Lib_file): $(Object_files) + $(Librarian) r $(Lib_file) $(Object_files) + +%.o: %.c + $(CC) -c $(Compiler_Options) $< + +clean: + rm -f *.o + rm -f $(Lib_file) diff --git a/mikmod/mmio/makefile.psp b/mikmod/mmio/makefile.psp new file mode 100644 index 0000000..bed34d5 --- /dev/null +++ b/mikmod/mmio/makefile.psp @@ -0,0 +1,29 @@ +# MMIO Library Makefile for PSP +# Divine Entertainment Game Programming Pack +# + +########################## +## User settable macros ## +########################## +Compiler = psp-gcc +Librarian = psp-ar +Compiler_Options = -O2 -I. -I../mikmod -I../include -g +CC = $(Compiler) + +Lib_file = libmmio.a + +Object_files = mmio.o mmalloc.o mmerror.o + +#################### +## Makefile rules ## +#################### + +$(Lib_file): $(Object_files) + $(Librarian) r $(Lib_file) $(Object_files) + +%.o: %.c + $(CC) -c $(Compiler_Options) $< + +clean: + rm -f *.o + rm -f $(Lib_file) diff --git a/mikmod/mmio/makefile.sgi b/mikmod/mmio/makefile.sgi new file mode 100644 index 0000000..a40cbe6 --- /dev/null +++ b/mikmod/mmio/makefile.sgi @@ -0,0 +1,26 @@ +# MMIO Library Makefile for UNIX/Linux +# Divine Entertainment Game Programming Pack +# + +########################## +## User settable macros ## +########################## + +CC = cc +Librarian = ar +CFLAGS = -O2 -I. -I../mikmod -I../include -DSGI + +Lib_file = ../lib/libmmio.a + +Object_files = mmio.o mmalloc.o mmerror.o + +#################### +## Makefile rules ## +#################### + +$(Lib_file): $(Object_files) + $(Librarian) r $(Lib_file) $(Object_files) + +clean: + rm -f *.o + rm -f $(Lib_file) diff --git a/mikmod/mmio/makefile.sun b/mikmod/mmio/makefile.sun new file mode 100644 index 0000000..5f2e659 --- /dev/null +++ b/mikmod/mmio/makefile.sun @@ -0,0 +1,26 @@ +# MMIO Library Makefile for Sun/Solaris +# Divine Entertainment Game Programming Pack +# + +########################## +## User settable macros ## +########################## + +CC = gcc +Librarian = ar +CFLAGS = -O2 -I. -I../mikmod -I../include -DSOLARIS + +Lib_file = ../lib/libmmio.a + +Object_files = mmio.o mmalloc.o mmerror.o + +#################### +## Makefile rules ## +#################### + +$(Lib_file): $(Object_files) + $(Librarian) r $(Lib_file) $(Object_files) + +clean: + rm -f *.o + rm -f $(Lib_file) diff --git a/mikmod/mmio/mmalloc.c b/mikmod/mmio/mmalloc.c new file mode 100644 index 0000000..35538cc --- /dev/null +++ b/mikmod/mmio/mmalloc.c @@ -0,0 +1,58 @@ +/* + --> The MMIO Portable Memory Management functions + -> Divine Entertainment GameDev Libraries + + Copyright © 1997 by Jake Stine and Divine Entertainment + +*/ + +#include +#include "mmio.h" + +/* Same as malloc, but sets error variable _mm_error when it failed */ +void *_mm_malloc(size_t size) +{ + void *d; + + if((d=malloc(size))==NULL) + { _mm_errno = MMERR_OUT_OF_MEMORY; + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + } + + return d; +} + + +/* Same as calloc, but sets error variable _mm_error when it failed */ +void *_mm_calloc(size_t nitems, size_t size) +{ + void *d; + + if((d=calloc(nitems,size))==NULL) + { _mm_errno = MMERR_OUT_OF_MEMORY; + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + } + + return d; +} + + +#ifndef __WATCOMC__ +#ifndef __GNUC__ +/* Same as Watcom's strdup function - allocates memory for a string */ +/* and makes a copy of it. Ruturns NULL if failed. */ +CHAR *strdup(CHAR *src) +{ + CHAR *buf; + + if((buf = (CHAR *)_mm_malloc(strlen(src)+1)) == NULL) + { _mm_errno = MMERR_OUT_OF_MEMORY; + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + return NULL; + } + + strcpy(buf,src); + return buf; +} +#endif +#endif diff --git a/mikmod/mmio/mmerror.c b/mikmod/mmio/mmerror.c new file mode 100644 index 0000000..6090bc2 --- /dev/null +++ b/mikmod/mmio/mmerror.c @@ -0,0 +1,103 @@ +/* + --> The MM_Error Portable Error Handling Functions + -> Divine Entertainment GameDev Libraries + + File: MMERROR.C + + Description: + Error handling functions for use with the DivEnt MMIO and MikMod + libraries. Register an error handler with _mm_RegisterErrorHandler() + and you're all set. + + NOTES: + + - the global variables _mm_error, _mm_errno, and _mm_critical are + set before the error handler in called. See below for the values + of these variables. + +-------------------------- + + +*/ + + +#include "mmio.h" + +CHAR *_mm_errmsg[] = +{ + "", + +/* Generic MikMod Errors [referenced by _mm_error] */ +/* ----------------------------------------------- */ + + "Cannot open requested file", + "Out of memory", + "Unexpected end of file", + "Cannot write to file - Disk full", + +/* Specific Misceallenous Errors: */ + + "Sample load failed - Out of memory", + "Sample load failed - Out of sample handles", + "Could not allocate page-contiguous dma-buffer", + "Unknown wave file or sample type", + "Unknown streaming audio type", + +/* Specific Module Loader [MLOADER.C] errors: */ + + "Failure loading module pattern", + "Failure loading module track", + "Failure loading module header", + "Failure loading sampleinfo", + "Unknown module format", + +/* Specific Driver [MDRIVER.C / drivers] errors: */ + + "None of the supported sound-devices were detected", + "Device number out of range", + "Software mixer failure - Out of memory", + +#ifdef SUN +#elif defined(SOLARIS) +#elif defined(__alpha) + "Cannot find suitable audio port!" +#elif defined(OSS) + #ifdef ULTRA + #endif +#elif defined(__hpux) + "Unable to open /dev/audio", + "Unable to set non-blocking mode for /dev/audio", + "Unable to select 16bit-linear sample format", + "Could not select requested sample-rate", + "Could not select requested number of channels", + "Unable to select audio output", + "Unable to get audio description", + "Unable to get gain values", + "Unable to set gain values", + "Could not set transmission buffer size" +#elif defined(AIX) + "Could not open AIX audio device", + "Configuration (init) of AIX audio device failed", + "Configuration (control) of AIX audio device failed", + "Configuration (start) of AIX audio device failed", + "Unable to set non-blocking mode for /dev/audio", +#elif defined(SGI) +#elif defined(__OS2__) +#elif defined(__WIN32__) +#else + "The requested soundcard was not found", + "Could not open a High-DMA channel" +#endif +}; + + +void (*_mm_errorhandler)(void) = NULL; +int _mm_errno = 0; +BOOL _mm_critical = 0; + + +void _mm_RegisterErrorHandler(void (*proc)(void)) +{ + _mm_errorhandler = proc; +} + diff --git a/mikmod/mmio/mmio.c b/mikmod/mmio/mmio.c new file mode 100644 index 0000000..f1d9381 --- /dev/null +++ b/mikmod/mmio/mmio.c @@ -0,0 +1,532 @@ +/* + --> The MMIO Portable Input/Output functions + -> Divine Entertainment GameDev Libraries + + File: MMIO.C + + Description: + Miscellaneous I/O routines.. used to solve some portability issues + (like big/little endian machines and word alignment in structures ) + Also includes mikmod's ingenious error handling variable. + + Portability: + All systems - all compilers + + + ----------------------------------- + The way this module works - By Jake Stine [Air Richter] + + - _mm_fopen and _mm_copyfile will call the errorhandler [see mmerror.c] in + addition to setting _mm_errno on exit. + + - _mm_iobase is for internal use. It is used by ML_LoadFP() to ensure that it + works properly with wad files. + + - _mm_read_I_UWORD and _mm_read_M_UWORD have distinct differences: + the first is for reading data written by a little endian (intel) machine, + and the second is for reading big endian (Mac, RISC, Alpha) machine data. + + - _mm_write functions work the same as the _mm_read functions. + + - _mm_read_string is for reading binary strings. It is basically the same + as an fread of bytes. +*/ + +#include +#include "mmio.h" +#include + + enum {OSL_MB_OK=1, OSL_MB_CANCEL, OSL_MB_YES, OSL_MB_NO, OSL_MB_QUIT}; + enum {OSL_KEY_SELECT=1, OSL_KEY_START=4, OSL_KEY_UP=5, OSL_KEY_RIGHT=6, OSL_KEY_DOWN=7, OSL_KEY_LEFT=8, OSL_KEY_L=9, OSL_KEY_R=10, + OSL_KEY_TRIANGLE=13, OSL_KEY_CIRCLE=14, OSL_KEY_CROSS=15, OSL_KEY_SQUARE=16, OSL_KEY_HOME=17, OSL_KEY_HOLD=18, OSL_KEY_NOTE=24}; + extern unsigned int oslMessageBox(const char *text, const char *title, unsigned int flags); + #define oslMake3Buttons(b1,a1,b2,a2,b3,a3) ((b1)|((a1)<<5)|((b2)<<9)|((a2)<<14)|((b3)<<18)|((a3)<<23)) + #define oslDebug(format...) ({ char __str2[1000], __str[1000]; sprintf(__str2, "Debug (%s:%i,%s)",__FUNCTION__,__LINE__,__FILE__); sprintf(__str , ##format); oslMessageBox(__str, __str2, oslMake3Buttons(OSL_KEY_CROSS,OSL_MB_OK,OSL_KEY_TRIANGLE,OSL_MB_QUIT,0,0)); }) + +#define COPY_BUFSIZE 1024 + +static long _mm_iobase = 0, + temp_iobase = 0; + +UBYTE _mm_cpybuf[COPY_BUFSIZE]; + + +void StringWrite(CHAR *s, VIRTUAL_FILE *fp) +/* Specialized file output procedure. Writes a UWORD length and then a */ +/* string of the specified length (no NULL terminator) afterward. */ +{ + int slen; + + if(s==NULL) + { _mm_write_I_UWORD(0,fp); + } else + { _mm_write_I_UWORD(slen = strlen(s),fp); + _mm_write_UBYTES(s,slen,fp); + } +} + +CHAR *StringRead(VIRTUAL_FILE *fp) +/* Reads strings written out by StringWrite above: a UWORD length followed */ +/* by length characters. A NULL is added to the string after loading. */ +{ + CHAR *s; + UWORD len; + + len = _mm_read_I_UWORD(fp); + if(len==0) + { s = _mm_calloc(16, sizeof(CHAR)); + } else + { if((s = (CHAR *)_mm_malloc(len+1)) == NULL) return NULL; + _mm_read_UBYTES(s,len,fp); + s[len] = 0; + } + + return s; +} + +static unsigned char *_mm_io_buffer, *_mm_io_pos; +static long _mm_io_size; +static char _mm_eof; + +VIRTUAL_FILE *_mm_fopen(CHAR *fname, CHAR *attrib) +{ + VIRTUAL_FILE *fp; + + //ATTENTION! + if((fp=VirtualFileOpen(fname,0, VF_AUTO, VF_O_READ)) == NULL) + { _mm_errno = _mm_errno = MMERR_OPENING_FILE; + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + } + if (fp) { + _mm_io_size = _mm_flength(fp); + if (_mm_io_size) + { + _mm_io_buffer = _mm_malloc(_mm_io_size); + VirtualFileRead(_mm_io_buffer, _mm_io_size, 1, fp); + } + else + { + _mm_io_buffer = NULL; + } + _mm_io_pos = _mm_io_buffer; + _mm_eof = 0; + } + return fp; +} + +int _mm_fclose(VIRTUAL_FILE *fp) +{ + if (_mm_io_buffer) + free(_mm_io_buffer); + _mm_io_buffer = _mm_io_pos = NULL; + return VirtualFileClose(fp); +} + +int _mm_fgetc(VIRTUAL_FILE *fp) +{ + //return fgetc(fp); + if (_mm_eof) return EOF; + if (_mm_io_pos < _mm_io_buffer + _mm_io_size) + return (int)*_mm_io_pos++; + _mm_eof = 1; + return EOF; +} + +int _mm_feof(VIRTUAL_FILE *fp) +{ + return _mm_eof; +} + +int _mm_fread(void *buffer, size_t size, size_t count, VIRTUAL_FILE *fp) +{ + //return VirtualFileRead(buffer, size, count, fp); + unsigned int x, y; + unsigned char *b; + int c; + if (_mm_eof) return EOF; + + b = (unsigned char *)buffer; + for (x = 0; x < count; x++) + { + for (y = 0; y < size; y++) + { + c = _mm_fgetc(fp); + if (c == EOF) break; + *b++ = c; + } + if (c == EOF) break; + } + return x; +} + +int _mm_fseek(VIRTUAL_FILE *stream, long offset, int whence) +{ +// return fseek(stream,(whence==SEEK_SET) ? offset+_mm_iobase : offset, whence); + _mm_eof = 0; + if (whence == SEEK_SET) + _mm_io_pos = _mm_io_buffer + offset + _mm_iobase; + else + _mm_io_pos += offset; + return 0; +} + + +long _mm_ftell(VIRTUAL_FILE *stream) +{ +// return ftell(stream)-_mm_iobase; + return _mm_io_pos - _mm_io_buffer - _mm_iobase; +} + + +BOOL _mm_FileExists(CHAR *fname) +{ + VIRTUAL_FILE *fp; + + if((fp=VirtualFileOpen(fname, 0, VF_AUTO, VF_O_READ)) == NULL) return 0; + VirtualFileClose(fp); + + return 1; +} + +long _mm_flength(VIRTUAL_FILE *stream) +{ + long tmp,tmp2; + + tmp = VirtualFileTell(stream); + VirtualFileSeek(stream,0,SEEK_END); + tmp2 = VirtualFileTell(stream); + VirtualFileSeek(stream,tmp,SEEK_SET); + return tmp2-tmp; +} + + +long _mm_iobase_get(void) +{ + return _mm_iobase; +} + + +void _mm_iobase_set(long iobase) +{ + temp_iobase = _mm_iobase; /* store old value in case of revert */ + _mm_iobase = iobase; +} + + +/* Sets the current file-position as the new _mm_iobase */ +void _mm_iobase_setcur(VIRTUAL_FILE *fp) +{ + temp_iobase = _mm_iobase; /* store old value in case of revert */ + _mm_iobase = VirtualFileTell(fp); +} + + +/* Reverts to the last known _mm_iobase value. */ +void _mm_iobase_revert(void) +{ + _mm_iobase = temp_iobase; +} + + +/* Procedure: _mm_copyfile */ +/* Copies a given number of bytes from the source file to the destination */ +/* file. Returns 1 on error, and calls the _mm_errnohandler, if registered. */ +BOOL _mm_copyfile(VIRTUAL_FILE *fpi, VIRTUAL_FILE *fpo, ULONG len) +{ + ULONG todo; + + while(len) + { todo = (len > COPY_BUFSIZE) ? COPY_BUFSIZE : len; + if(!VirtualFileRead(_mm_cpybuf, todo, 1, fpi)) + { _mm_errno = _mm_errno = MMERR_END_OF_FILE; + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + return 1; + } + if(!VirtualFileWrite(_mm_cpybuf, todo, 1, fpo)) + { _mm_errno = _mm_errno = MMERR_DISK_FULL; + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + return 1; + } + len -= todo; + } + + return 0; +} + + +void _mm_write_string(CHAR *data, VIRTUAL_FILE *fp) +{ + if(data!=NULL) + _mm_write_UBYTES(data, strlen(data), fp); +} + + +void _mm_fputs(VIRTUAL_FILE *fp, CHAR *data) +{ + if(data != NULL) + _mm_write_UBYTES(data, strlen(data), fp); + +#ifndef __UNIX__ + _mm_write_UBYTE(13,fp); +#endif + _mm_write_UBYTE(10,fp); +} + + + +#if 0 +/* These have accompanying #define's in mmio.h */ + +void _mm_write_SBYTE(SBYTE data, VIRTUAL_FILE *fp) +{ + VirtualFilePutc(data,fp); +} + +void _mm_write_UBYTE(UBYTE data,VIRTUAL_FILE *fp) +{ + VirtualFilePutc(data,fp); +} +#endif + + +#ifdef MM_BIG_ENDIAN + +/* --> Big Endian Write Functions */ + +void _mm_write_M_UWORD(UWORD data,VIRTUAL_FILE *fp) +{ + _mm_write_UBYTE(data&0xff,fp); + _mm_write_UBYTE(data>>8,fp); +} + + +void _mm_write_I_UWORD(UWORD data,VIRTUAL_FILE *fp) +{ + _mm_write_UBYTE(data>>8,fp); + _mm_write_UBYTE(data&0xff,fp); +} + + +void _mm_write_M_ULONG(ULONG data,VIRTUAL_FILE *fp) +{ + _mm_write_M_UWORD(data&0xffff,fp); + _mm_write_M_UWORD(data>>16,fp); +} + + +void _mm_write_I_ULONG(ULONG data,VIRTUAL_FILE *fp) +{ + _mm_write_I_UWORD(data>>16,fp); + _mm_write_I_UWORD(data&0xffff,fp); +} + +#else + +/* --> Little Endian Write Functions */ + +void _mm_write_M_UWORD(UWORD data,VIRTUAL_FILE *fp) +{ + _mm_write_UBYTE(data>>8,fp); + _mm_write_UBYTE(data&0xff,fp); +} + + +void _mm_write_I_UWORD(UWORD data,VIRTUAL_FILE *fp) +{ + _mm_write_UBYTE(data&0xff,fp); + _mm_write_UBYTE(data>>8,fp); +} + + +void _mm_write_M_ULONG(ULONG data,VIRTUAL_FILE *fp) +{ + _mm_write_M_UWORD(data>>16,fp); + _mm_write_M_UWORD(data&0xffff,fp); +} + + +void _mm_write_I_ULONG(ULONG data,VIRTUAL_FILE *fp) +{ + _mm_write_I_UWORD(data&0xffff,fp); + _mm_write_I_UWORD(data>>16,fp); +} + +#endif + + +void _mm_write_M_SWORD(SWORD data,VIRTUAL_FILE *fp) +{ + _mm_write_M_UWORD((UWORD)data,fp); +} + + +void _mm_write_I_SWORD(SWORD data,VIRTUAL_FILE *fp) +{ + _mm_write_I_UWORD((UWORD)data,fp); +} + + +void _mm_write_M_SLONG(SLONG data,VIRTUAL_FILE *fp) +{ + _mm_write_M_ULONG((ULONG)data,fp); +} + + +void _mm_write_I_SLONG(SLONG data,VIRTUAL_FILE *fp) +{ + _mm_write_I_ULONG((ULONG)data,fp); +} + + +#define DEFINE_MULTIPLE_WRITE_FUNCTION(type_name, type) \ +void \ +_mm_write_##type_name##S (type *buffer, int number, VIRTUAL_FILE *fp) \ +{ \ + while(number>0) \ + { _mm_write_##type_name(*(buffer++),fp); \ + number--; \ + } \ +} + +/*DEFINE_MULTIPLE_WRITE_FUNCTION (SBYTE, SBYTE) */ +/*DEFINE_MULTIPLE_WRITE_FUNCTION (UBYTE, UBYTE) */ + +DEFINE_MULTIPLE_WRITE_FUNCTION (M_SWORD, SWORD) +DEFINE_MULTIPLE_WRITE_FUNCTION (M_UWORD, UWORD) +DEFINE_MULTIPLE_WRITE_FUNCTION (I_SWORD, SWORD) +DEFINE_MULTIPLE_WRITE_FUNCTION (I_UWORD, UWORD) + +DEFINE_MULTIPLE_WRITE_FUNCTION (M_SLONG, SLONG) +DEFINE_MULTIPLE_WRITE_FUNCTION (M_ULONG, ULONG) +DEFINE_MULTIPLE_WRITE_FUNCTION (I_SLONG, SLONG) +DEFINE_MULTIPLE_WRITE_FUNCTION (I_ULONG, ULONG) + + +/********** +SBYTE _mm_read_SBYTE(VIRTUAL_FILE *fp) +{ + return(_mm_fgetc(fp)); +} + +UBYTE _mm_read_UBYTE(VIRTUAL_FILE *fp) +{ + return(_mm_fgetc(fp)); +} +**********/ + + +#ifdef MM_BIG_ENDIAN + +UWORD _mm_read_I_UWORD(VIRTUAL_FILE *fp) +{ + UWORD result=((UWORD)_mm_read_UBYTE(fp))<<8; + result|=_mm_read_UBYTE(fp); + return result; +} + +UWORD _mm_read_M_UWORD(VIRTUAL_FILE *fp) +{ + UWORD result=_mm_read_UBYTE(fp); + result|=((UWORD)_mm_read_UBYTE(fp))<<8; + return result; +} + +ULONG _mm_read_I_ULONG(VIRTUAL_FILE *fp) +{ + ULONG result=((ULONG)_mm_read_M_UWORD(fp))<<16; + result|=_mm_read_M_UWORD(fp); + return result; +} + +ULONG _mm_read_M_ULONG(VIRTUAL_FILE *fp) +{ + ULONG result=_mm_read_I_UWORD(fp); + result|=((ULONG)_mm_read_I_UWORD(fp))<<16; + return result; +} + +#else + +UWORD _mm_read_M_UWORD(VIRTUAL_FILE *fp) +{ + UWORD result=((UWORD)_mm_read_UBYTE(fp))<<8; + result|=_mm_read_UBYTE(fp); + return result; +} + +UWORD _mm_read_I_UWORD(VIRTUAL_FILE *fp) +{ + UWORD result=_mm_read_UBYTE(fp); + result|=((UWORD)_mm_read_UBYTE(fp))<<8; + return result; +} + +ULONG _mm_read_M_ULONG(VIRTUAL_FILE *fp) +{ + ULONG result=((ULONG)_mm_read_M_UWORD(fp))<<16; + result|=_mm_read_M_UWORD(fp); + return result; +} + +ULONG _mm_read_I_ULONG(VIRTUAL_FILE *fp) +{ + ULONG result=_mm_read_I_UWORD(fp); + result|=((ULONG)_mm_read_I_UWORD(fp))<<16; + return result; +} + +#endif + +SWORD _mm_read_M_SWORD(VIRTUAL_FILE *fp) +{ + return((SWORD)_mm_read_M_UWORD(fp)); +} + +SWORD _mm_read_I_SWORD(VIRTUAL_FILE *fp) +{ + return((SWORD)_mm_read_I_UWORD(fp)); +} + +SLONG _mm_read_M_SLONG(VIRTUAL_FILE *fp) +{ + return((SLONG)_mm_read_M_ULONG(fp)); +} + +SLONG _mm_read_I_SLONG(VIRTUAL_FILE *fp) +{ + return((SLONG)_mm_read_I_ULONG(fp)); +} + + +int _mm_read_string(CHAR *buffer, int number, VIRTUAL_FILE *fp) +{ + _mm_fread(buffer,1,number,fp); + return !_mm_feof(fp); +} + + + +#define DEFINE_MULTIPLE_READ_FUNCTION(type_name, type) \ +int \ +_mm_read_##type_name##S (type *buffer, int number, VIRTUAL_FILE *fp) \ +{ \ + while(number>0) \ + { *(buffer++)=_mm_read_##type_name(fp); \ + number--; \ + } \ + return !_mm_feof(fp); \ +} + +/*DEFINE_MULTIPLE_READ_FUNCTION (SBYTE, SBYTE) */ +/*DEFINE_MULTIPLE_READ_FUNCTION (UBYTE, UBYTE) */ + +DEFINE_MULTIPLE_READ_FUNCTION (M_SWORD, SWORD) +DEFINE_MULTIPLE_READ_FUNCTION (M_UWORD, UWORD) +DEFINE_MULTIPLE_READ_FUNCTION (I_SWORD, SWORD) +DEFINE_MULTIPLE_READ_FUNCTION (I_UWORD, UWORD) + +DEFINE_MULTIPLE_READ_FUNCTION (M_SLONG, SLONG) +DEFINE_MULTIPLE_READ_FUNCTION (M_ULONG, ULONG) +DEFINE_MULTIPLE_READ_FUNCTION (I_SLONG, SLONG) +DEFINE_MULTIPLE_READ_FUNCTION (I_ULONG, ULONG) + diff --git a/mikmod/mplayer.c b/mikmod/mplayer.c new file mode 100644 index 0000000..01d842a --- /dev/null +++ b/mikmod/mplayer.c @@ -0,0 +1,2759 @@ +/* + --> The Protracker Player Driver + -> Part of the SPLAYER pack for MikMod 3.0 + + The protracker driver supports all base Protracker 3.x commands and fea- + tures. +*/ + +#include +#include +#include "mikmod.h" + + +static void DoNNAEffects(UBYTE dat); + +/* Set forbid to 1 when you want to modify any of the pf->sngpos, pf->patpos etc. */ +/* variables and clear it when you're done. This prevents getting strange */ +/* results due to intermediate interrupts. */ + +UNIMOD *pf; /* <- this modfile is being played */ +static SWORD mp_channel; /* channel it's working on */ +static MP_CONTROL *a; /* current AUDTMP it's working on */ +static int isfirst; + +static MP_VOICE aout_dummy; + +UWORD mytab[12] = +{ 1712*16, 1616*16, 1524*16, 1440*16, 1356*16, 1280*16, + 1208*16, 1140*16, 1076*16, 1016*16, 960*16, 907*16 +}; + + +UBYTE VibratoTable[32] = +{ 0,24,49,74,97,120,141,161, + 180,197,212,224,235,244,250,253, + 255,253,250,244,235,224,212,197, + 180,161,141,120,97,74,49,24 +}; + + +UBYTE avibtab[128] = +{ 0,1,3,4,6,7,9,10,12,14,15,17,18,20,21,23, + 24,25,27,28,30,31,32,34,35,36,38,39,40,41,42,44, + 45,46,47,48,49,50,51,52,53,54,54,55,56,57,57,58, + 59,59,60,60,61,61,62,62,62,63,63,63,63,63,63,63, + 64,63,63,63,63,63,63,63,62,62,62,61,61,60,60,59, + 59,58,57,57,56,55,54,54,53,52,51,50,49,48,47,46, + 45,44,42,41,40,39,38,36,35,34,32,31,30,28,27,25, + 24,23,21,20,18,17,15,14,12,10,9,7,6,4,3,1 +}; + + +/* ** Triton's linear periods to frequency translation table (for */ +/* ** Fast Tracker 2 [XM] modules): */ + +ULONG lintab[768] = +{ 535232,534749,534266,533784,533303,532822,532341,531861, + 531381,530902,530423,529944,529466,528988,528511,528034, + 527558,527082,526607,526131,525657,525183,524709,524236, + 523763,523290,522818,522346,521875,521404,520934,520464, + 519994,519525,519057,518588,518121,517653,517186,516720, + 516253,515788,515322,514858,514393,513929,513465,513002, + 512539,512077,511615,511154,510692,510232,509771,509312, + 508852,508393,507934,507476,507018,506561,506104,505647, + 505191,504735,504280,503825,503371,502917,502463,502010, + 501557,501104,500652,500201,499749,499298,498848,498398, + 497948,497499,497050,496602,496154,495706,495259,494812, + 494366,493920,493474,493029,492585,492140,491696,491253, + 490809,490367,489924,489482,489041,488600,488159,487718, + 487278,486839,486400,485961,485522,485084,484647,484210, + 483773,483336,482900,482465,482029,481595,481160,480726, + 480292,479859,479426,478994,478562,478130,477699,477268, + 476837,476407,475977,475548,475119,474690,474262,473834, + 473407,472979,472553,472126,471701,471275,470850,470425, + 470001,469577,469153,468730,468307,467884,467462,467041, + 466619,466198,465778,465358,464938,464518,464099,463681, + 463262,462844,462427,462010,461593,461177,460760,460345, + 459930,459515,459100,458686,458272,457859,457446,457033, + 456621,456209,455797,455386,454975,454565,454155,453745, + 453336,452927,452518,452110,451702,451294,450887,450481, + 450074,449668,449262,448857,448452,448048,447644,447240, + 446836,446433,446030,445628,445226,444824,444423,444022, + 443622,443221,442821,442422,442023,441624,441226,440828, + 440430,440033,439636,439239,438843,438447,438051,437656, + 437261,436867,436473,436079,435686,435293,434900,434508, + 434116,433724,433333,432942,432551,432161,431771,431382, + 430992,430604,430215,429827,429439,429052,428665,428278, + 427892,427506,427120,426735,426350,425965,425581,425197, + 424813,424430,424047,423665,423283,422901,422519,422138, + 421757,421377,420997,420617,420237,419858,419479,419101, + 418723,418345,417968,417591,417214,416838,416462,416086, + 415711,415336,414961,414586,414212,413839,413465,413092, + 412720,412347,411975,411604,411232,410862,410491,410121, + 409751,409381,409012,408643,408274,407906,407538,407170, + 406803,406436,406069,405703,405337,404971,404606,404241, + 403876,403512,403148,402784,402421,402058,401695,401333, + 400970,400609,400247,399886,399525,399165,398805,398445, + 398086,397727,397368,397009,396651,396293,395936,395579, + 395222,394865,394509,394153,393798,393442,393087,392733, + 392378,392024,391671,391317,390964,390612,390259,389907, + 389556,389204,388853,388502,388152,387802,387452,387102, + 386753,386404,386056,385707,385359,385012,384664,384317, + 383971,383624,383278,382932,382587,382242,381897,381552, + 381208,380864,380521,380177,379834,379492,379149,378807, + + 378466,378124,377783,377442,377102,376762,376422,376082, + 375743,375404,375065,374727,374389,374051,373714,373377, + 373040,372703,372367,372031,371695,371360,371025,370690, + 370356,370022,369688,369355,369021,368688,368356,368023, + 367691,367360,367028,366697,366366,366036,365706,365376, + 365046,364717,364388,364059,363731,363403,363075,362747, + 362420,362093,361766,361440,361114,360788,360463,360137, + 359813,359488,359164,358840,358516,358193,357869,357547, + 357224,356902,356580,356258,355937,355616,355295,354974, + 354654,354334,354014,353695,353376,353057,352739,352420, + 352103,351785,351468,351150,350834,350517,350201,349885, + 349569,349254,348939,348624,348310,347995,347682,347368, + 347055,346741,346429,346116,345804,345492,345180,344869, + 344558,344247,343936,343626,343316,343006,342697,342388, + 342079,341770,341462,341154,340846,340539,340231,339924, + 339618,339311,339005,338700,338394,338089,337784,337479, + 337175,336870,336566,336263,335959,335656,335354,335051, + 334749,334447,334145,333844,333542,333242,332941,332641, + 332341,332041,331741,331442,331143,330844,330546,330247, + 329950,329652,329355,329057,328761,328464,328168,327872, + 327576,327280,326985,326690,326395,326101,325807,325513, + 325219,324926,324633,324340,324047,323755,323463,323171, + 322879,322588,322297,322006,321716,321426,321136,320846, + 320557,320267,319978,319690,319401,319113,318825,318538, + 318250,317963,317676,317390,317103,316817,316532,316246, + 315961,315676,315391,315106,314822,314538,314254,313971, + 313688,313405,313122,312839,312557,312275,311994,311712, + 311431,311150,310869,310589,310309,310029,309749,309470, + 309190,308911,308633,308354,308076,307798,307521,307243, + 306966,306689,306412,306136,305860,305584,305308,305033, + 304758,304483,304208,303934,303659,303385,303112,302838, + 302565,302292,302019,301747,301475,301203,300931,300660, + 300388,300117,299847,299576,299306,299036,298766,298497, + 298227,297958,297689,297421,297153,296884,296617,296349, + 296082,295815,295548,295281,295015,294749,294483,294217, + 293952,293686,293421,293157,292892,292628,292364,292100, + 291837,291574,291311,291048,290785,290523,290261,289999, + 289737,289476,289215,288954,288693,288433,288173,287913, + 287653,287393,287134,286875,286616,286358,286099,285841, + 285583,285326,285068,284811,284554,284298,284041,283785, + 283529,283273,283017,282762,282507,282252,281998,281743, + 281489,281235,280981,280728,280475,280222,279969,279716, + 279464,279212,278960,278708,278457,278206,277955,277704, + 277453,277203,276953,276703,276453,276204,275955,275706, + 275457,275209,274960,274712,274465,274217,273970,273722, + 273476,273229,272982,272736,272490,272244,271999,271753, + 271508,271263,271018,270774,270530,270286,270042,269798, + 269555,269312,269069,268826,268583,268341,268099,267857 +}; + + +#define LOGFAC 2*16 + +UWORD logtab[104] = +{ LOGFAC*907,LOGFAC*900,LOGFAC*894,LOGFAC*887,LOGFAC*881,LOGFAC*875,LOGFAC*868,LOGFAC*862, + LOGFAC*856,LOGFAC*850,LOGFAC*844,LOGFAC*838,LOGFAC*832,LOGFAC*826,LOGFAC*820,LOGFAC*814, + LOGFAC*808,LOGFAC*802,LOGFAC*796,LOGFAC*791,LOGFAC*785,LOGFAC*779,LOGFAC*774,LOGFAC*768, + LOGFAC*762,LOGFAC*757,LOGFAC*752,LOGFAC*746,LOGFAC*741,LOGFAC*736,LOGFAC*730,LOGFAC*725, + LOGFAC*720,LOGFAC*715,LOGFAC*709,LOGFAC*704,LOGFAC*699,LOGFAC*694,LOGFAC*689,LOGFAC*684, + LOGFAC*678,LOGFAC*675,LOGFAC*670,LOGFAC*665,LOGFAC*660,LOGFAC*655,LOGFAC*651,LOGFAC*646, + LOGFAC*640,LOGFAC*636,LOGFAC*632,LOGFAC*628,LOGFAC*623,LOGFAC*619,LOGFAC*614,LOGFAC*610, + LOGFAC*604,LOGFAC*601,LOGFAC*597,LOGFAC*592,LOGFAC*588,LOGFAC*584,LOGFAC*580,LOGFAC*575, + LOGFAC*570,LOGFAC*567,LOGFAC*563,LOGFAC*559,LOGFAC*555,LOGFAC*551,LOGFAC*547,LOGFAC*543, + LOGFAC*538,LOGFAC*535,LOGFAC*532,LOGFAC*528,LOGFAC*524,LOGFAC*520,LOGFAC*516,LOGFAC*513, + LOGFAC*508,LOGFAC*505,LOGFAC*502,LOGFAC*498,LOGFAC*494,LOGFAC*491,LOGFAC*487,LOGFAC*484, + LOGFAC*480,LOGFAC*477,LOGFAC*474,LOGFAC*470,LOGFAC*467,LOGFAC*463,LOGFAC*460,LOGFAC*457, + LOGFAC*453,LOGFAC*450,LOGFAC*447,LOGFAC*443,LOGFAC*440,LOGFAC*437,LOGFAC*434,LOGFAC*431 +}; + +SBYTE PanbrelloTable[256] = +{ 0,2,3,5,6,8,9,11,12,14,16,17,19,20,22,23, + 24,26,27,29,30,32,33,34,36,37,38,39,41,42,43,44, + 45,46,47,48,49,50,51,52,53,54,55,56,56,57,58,59, + 59,60,60,61,61,62,62,62,63,63,63,64,64,64,64,64, + 64,64,64,64,64,64,63,63,63,62,62,62,61,61,60,60, + 59,59,58,57,56,56,55,54,53,52,51,50,49,48,47,46, + 45,44,43,42,41,39,38,37,36,34,33,32,30,29,27,26, + 24,23,22,20,19,17,16,14,12,11,9,8,6,5,3,2, + 0,-2,-3,-5,-6,-8,-9,-11,-12,-14,-16,-17,-19,-20,-22,-23, + -24,-26,-27,-29,-30,-32,-33,-34,-36,-37,-38,-39,-41,-42,-43,-44, + -45,-46,-47,-48,-49,-50,-51,-52,-53,-54,-55,-56,-56,-57,-58,-59, + -59,-60,-60,-61,-61,-62,-62,-62,-63,-63,-63,-64,-64,-64,-64,-64, + -64,-64,-64,-64,-64,-64,-63,-63,-63,-62,-62,-62,-61,-61,-60,-60, + -59,-59,-58,-57,-56,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46, + -45,-44,-43,-42,-41,-39,-38,-37,-36,-34,-33,-32,-30,-29,-27,-26, + -24,-23,-22,-20,-19,-17,-16,-14,-12,-11,-9,-8,-6,-5,-3,-2 +}; + + +/* New Note Action Scoring System: + --------------------------------- + 1) total-volume (fadevol, chanvol, volume) is the main scorer. + 2) a looping sample is a bonus x2 + 3) a forground channel is a bonus x4 + 4) an active envelope with keyoff is a handicap -x2 +*/ +static int MP_FindEmptyChannel(int curchan) /* returns mp_control index of free channel */ +{ + MP_VOICE *a; + ULONG t,k,tvol,p,pp; + + /*for(t=md_sngchn; t; t--, audpool++) + { if(audpool == md_sngchn) audpool = 0; + if(!(pf->voice[audpool].kick) && Voice_Stopped(audpool)) + { audpool++; + return audpool-1; + } + }*/ + + for(t=0; tvoice[t].kick) && Voice_Stopped(t)) + { return t; + } + } + + tvol = 0xffffffUL; t = 0; p = 0; a = pf->voice; + for(k=0; kkick) + { pp = a->totalvol << ((a->s->flags & SF_LOOP) ? 1 : 0); + if((a->master!=NULL) && (a==a->master->slave)) + pp <<= 2; + + /*if(a->volflg & EF_ON) + { if(a->volflg & (EF_SUSTAIN | EF_LOOP)) + { if(a->keyoff & KEY_OFF) + { pp >>= 1; + if(a->venv.env[a->venv.end].val < 32) pp>>=1; + } else + pp <<= 1; + } else pp <<= 1; + }*/ + + if(pp < tvol) + { tvol = pp; + t = k; + } + } + } + + if(tvol>8000*7) return -1; /*mp_channel; */ + + return t; +} + + +static SWORD Interpolate(SWORD p, SWORD p1, SWORD p2, SWORD v1, SWORD v2) +{ + SWORD dp,dv,di; + + if(p1==p2) return v1; + + dv = v2-v1; + dp = p2-p1; + di = p-p1; + + return v1 + ((SLONG)(di*dv) / dp); +} + + +UWORD getlinearperiod(UBYTE note, ULONG fine) +{ + return((10L*12*16*4)-((ULONG)note*16*4)-(fine/2)+64); +} + + +static UWORD getlogperiod(UBYTE note,ULONG fine) +{ + UBYTE n,o; + UWORD p1,p2; + ULONG i; + + n = note%12; + o = note/12; + i = (n<<3) + (fine>>4); /* n*8 + fine/16 */ + + p1 = logtab[i]; + p2 = logtab[i+1]; + + return(Interpolate(fine/16,0,15,p1,p2)>>o); +} + + +static UWORD getoldperiod(UBYTE note, ULONG speed) +{ + UBYTE n, o; + ULONG period; + + if(!speed) return 4242; /* <- prevent divide overflow.. (42 eheh) */ + + n = note % 12; + o = note / 12; + period = ((8363l*(ULONG)mytab[n]) >> o ) / speed; + return period; +} + + +static UWORD GetPeriod(UBYTE note, ULONG speed) +{ + if(pf->flags & UF_XMPERIODS) + return (pf->flags & UF_LINEAR) ? getlinearperiod(note,speed) : getlogperiod(note,speed); + + return getoldperiod(note,speed); +} + + +static SWORD InterpolateEnv(SWORD p, ENVPT *a, ENVPT *b) +{ + return(Interpolate(p,a->pos,b->pos,a->val,b->val)); +} + + +static SWORD DoPan(SWORD envpan, SWORD pan) +{ + return(pan + (((envpan-128)*(128-abs(pan-128)))/128)); +} + + +static void StartEnvelope(ENVPR *t, UBYTE flg, UBYTE pts, UBYTE susbeg, UBYTE susend, UBYTE beg, UBYTE end, ENVPT *p, UBYTE keyoff) +{ + t->flg = flg; + t->pts = pts; + t->susbeg = susbeg; + t->susend = susend; + t->beg = beg; + t->end = end; + t->env = p; + t->p = 0; + t->a = 0; + t->b = ((t->flg & EF_SUSTAIN) && !(keyoff & KEY_OFF)) ? 0 : 1; +} + + +static SWORD ProcessEnvelope(ENVPR *t, SWORD v, UBYTE keyoff) + +/* This procedure processes all envelope types, include volume, pitch, and */ +/* panning. Envelopes are defined by a set of points, each with a magnitude */ +/* [relating either to volume, panniong position, or pitch modifier] and a */ +/* tick position. */ +/* */ +/* Envelopes work in the following manner: */ +/* */ +/* (a) Each tick the envelope is moved a point further in its progression. */ +/* 1. For an accurate progression, magnitudes between two envelope points */ +/* are interpolated. */ +/* */ +/* (b) When progression reaches a defined point on the envelope, values */ +/* are shifted to interpolate between this point and the next, */ +/* and checks for loops or envelope end are done. */ +/* */ +/* Misc: */ +/* Sustain loops are loops that are only active as long as the keyoff */ +/* flag is clear. When a volume envelope terminates, so does the current */ +/* fadeout. */ + +{ + if(t->flg & EF_ON) + { UBYTE a, b; /* actual points in the envelope */ + UWORD p; /* the 'tick counter' - real point being played */ + + a = t->a; + b = t->b; + p = t->p; + + /* compute the current envelope value between points a and b */ + + if(a == b) + v = t->env[a].val; + else + v = InterpolateEnv(p, &t->env[a], &t->env[b]); + + p++; + + /* pointer reached point b? */ + + if(p >= t->env[b].pos) + { a = b++; /* shift points a and b */ + + /* Check for loops, sustain loops, or end of envelope. */ + + if((t->flg & EF_SUSTAIN) && !(keyoff & KEY_OFF) && (b > t->susend)) + { a = t->susbeg; + if(t->susbeg == t->susend) b = a; else b = a + 1; + p = t->env[a].pos; + } else if((t->flg & EF_LOOP) && (b > t->end)) + { a = t->beg; + if(t->beg == t->end) b = a; else b = a + 1; + p = t->env[a].pos; + } else + { if(b >= t->pts) + { if((t->flg & EF_VOLENV) && (mp_channel != -1)) + { pf->voice[mp_channel].keyoff |= KEY_FADE; + if(v==0) + pf->voice[mp_channel].fadevol = 0; + } + b--; p--; + } + } + } + t->a = a; + t->b = b; + t->p = p; + } + return v; +} + + +ULONG getfrequency(UBYTE flags, ULONG period) + +/* XM linear period to frequency conversion */ + +{ + ULONG result; + + if(flags & UF_LINEAR) + result = lintab[period % 768] >> (period / 768); + else + result = (8363L*1712L) / period; + + return result; +} + + +static void DoEEffects(UBYTE dat) +{ + UBYTE nib; + + nib = dat & 0xf; + + switch(dat>>4) + { case 0x0: /* filter toggle, not supported */ + break; + + case 0x1: /* fineslide up */ + if(!pf->vbtick) a->tmpperiod-=(nib<<2); + break; + + case 0x2: /* fineslide dn */ + if(!pf->vbtick) a->tmpperiod+=(nib<<2); + break; + + case 0x3: /* glissando ctrl */ + a->glissando = nib; + break; + + case 0x4: /* set vibrato waveform */ + a->wavecontrol &= 0xf0; + a->wavecontrol |= nib; + break; + + case 0x5: /* set finetune */ +/* a->speed=finetune[nib]; */ +/* a->tmpperiod=GetPeriod(a->note,pf->samples[a->sample].transpose,a->speed); */ + break; + + case 0x6: /* set patternloop */ + if(pf->vbtick) break; + /* hmm.. this one is a real kludge. But now it */ + /* works */ + if(nib) /* set reppos or repcnt ? */ + { /* set repcnt, so check if repcnt already is set, */ + /* which means we are already looping */ + + if(pf->pat_repcnt > 0) + pf->pat_repcnt--; /* already looping, decrease counter */ + else + pf->pat_repcnt = nib; /* not yet looping, so set repcnt */ + + if(pf->pat_repcnt) /* jump to reppos if repcnt>0 */ + pf->patpos = pf->pat_reppos; + } else + { pf->pat_reppos = pf->patpos-1; /* set reppos */ + } + break; + + + case 0x7: /* set tremolo waveform */ + a->wavecontrol &= 0x0f; + a->wavecontrol |= nib << 4; + break; + + case 0x8: /* set panning */ + if(pf->panflag) + { if(nib<=8) nib*=16; else nib*=17; + a->panning = nib; + pf->panning[mp_channel] = nib; + } + break; + + case 0x9: /* retrig note */ + /* only retrigger if */ + /* data nibble > 0 */ + + if(nib > 0) + { if(a->retrig==0) + { /* when retrig counter reaches 0, */ + /* reset counter and restart the sample */ + a->kick = 1; + a->retrig = nib; + } + a->retrig--; /* countdown */ + } + break; + + case 0xa: /* fine volume slide up */ + if(pf->vbtick) break; + + a->tmpvolume += nib; + if(a->tmpvolume > 64) a->tmpvolume = 64; + break; + + case 0xb: /* fine volume slide dn */ + if(pf->vbtick) break; + + a->tmpvolume -= nib; + if(a->tmpvolume < 0) a->tmpvolume = 0; + break; + + case 0xc: /* cut note */ + /* When pf->vbtick reaches the cut-note value, */ + /* turn the volume to zero ( Just like */ + /* on the amiga) */ + if(pf->vbtick>=nib) + a->tmpvolume = 0; /* just turn the volume down */ + break; + + case 0xd: /* note delay */ + /* delay the start of the */ + /* sample until pf->vbtick==nib */ + if(pf->vbtick==nib) + { /*a->kick = 1; */ + a->notedelay = 0; + } else if(pf->vbtick==0) + { /*a->kick = 0; */ + a->notedelay = 1; + } + break; + + case 0xe: /* pattern delay */ + if(pf->vbtick) break; + if(!pf->patdly2) pf->patdly = nib+1; /* only once (when pf->vbtick=0) */ + break; + + case 0xf: /* invert loop, not supported */ + break; + } +} + + +static void DoVibrato(void) +{ + UBYTE q; + UWORD temp; + + q = (a->vibpos>>2)&0x1f; + + switch(a->wavecontrol&3) + { case 0: /* sine */ + temp = VibratoTable[q]; + break; + + case 1: /* ramp down */ + q<<=3; + if(a->vibpos<0) q = 255-q; + temp = q; + break; + + case 2: /* square wave */ + temp = 255; + break; + + case 3: /* Evil random wave */ + temp = rand() & 255; + break; + } + + temp*=a->vibdepth; + temp>>=7; + temp<<=2; + + if(a->vibpos>=0) + a->period = a->tmpperiod+temp; + else + a->period = a->tmpperiod-temp; + + if(pf->vbtick) a->vibpos+=a->vibspd; /* do not update when pf->vbtick==0 */ +} + + +static void DoTremolo(void) +{ + UBYTE q; + UWORD temp; + + q = (a->trmpos>>2) & 0x1f; + + switch((a->wavecontrol>>4) & 3) + { case 0: /* sine */ + temp = VibratoTable[q]; + break; + + case 1: /* ramp down */ + q<<=3; + if(a->trmpos<0) q = 255-q; + temp = q; + break; + + case 2: /* square wave */ + temp = 255; + break; + + case 3: /* Evil random wave */ + temp = rand() & 255; + break; + } + + temp *= a->trmdepth; + temp >>= 6; + + if(a->trmpos >= 0) + { a->volume = a->tmpvolume + temp; + if(a->volume > 64) a->volume = 64; + } else + { a->volume = a->tmpvolume - temp; + if(a->volume < 0) a->volume = 0; + } + + if(pf->vbtick) a->trmpos+=a->trmspd; /* do not update when pf->vbtick==0 */ +} + + +static void DoVolSlide(UBYTE dat) +{ + if(!pf->vbtick) return; /* do not update when pf->vbtick==0 */ + + a->tmpvolume += dat >> 4; /* volume slide */ + a->tmpvolume -= dat & 0xf; + if(a->tmpvolume < 0) a->tmpvolume = 0; + if(a->tmpvolume > 64) a->tmpvolume = 64; +} + + +static void DoToneSlide(void) +{ + int dist; + + if(a->period==0) return; + + if(!pf->vbtick) + { a->tmpperiod = a->period; + return; + } + + /* We have to slide a->period towards a->wantedperiod, so */ + /* compute the difference between those two values */ + + dist = a->period-a->wantedperiod; + + if( dist==0 || a->portspeed>abs(dist) ) /* if they are equal or if portamentospeed is too big */ + a->period = a->wantedperiod; /* make tmpperiod equal tperiod */ + else if(dist>0) /* dist>0 ? */ + a->period-=a->portspeed; /* then slide up */ + else + a->period+=a->portspeed; /* dist<0 -> slide down */ + + a->tmpperiod = a->period; +} + + +static void DoPTEffect0(UBYTE dat) +{ + UBYTE note; + + note = a->note; + + if(dat!=0) + { switch(pf->vbtick%3) + { case 1: + note+=(dat>>4); break; + case 2: + note+=(dat&0xf); break; + } + a->period = GetPeriod(note,a->speed); + a->ownper = 1; + } +} + + +/* ----------------------------------------- */ +/* --> ScreamTreacker 3 Specific Effects <-- */ +/* ----------------------------------------- */ + +static void DoS3MVolSlide(UBYTE inf) +{ + UBYTE lo, hi; + + if(inf) a->s3mvolslide = inf; + + inf = a->s3mvolslide; + lo = inf & 0xf; + hi = inf >> 4; + + if(hi==0) a->tmpvolume -= lo; + else if(lo==0) a->tmpvolume += hi; + else if(hi==0xf) + { if(!pf->vbtick) a->tmpvolume -= lo; + } else if(lo==0xf) + { if(!pf->vbtick) a->tmpvolume += hi; + } + if(a->tmpvolume < 0) a->tmpvolume = 0; + if(a->tmpvolume > 64) a->tmpvolume = 64; +} + + +static void DoS3MSlideDn(UBYTE inf) +{ + UBYTE hi,lo; + + if(inf!=0) a->slidespeed = inf; + else inf = a->slidespeed; + + hi = inf>>4; + lo = inf&0xf; + + if(hi==0xf) + { if(!pf->vbtick) a->tmpperiod+=(UWORD)lo<<2; + } else if(hi==0xe) + { if(!pf->vbtick) a->tmpperiod+=lo; + } else + { if(pf->vbtick) a->tmpperiod+=(UWORD)inf<<2; + } +} + + +static void DoS3MSlideUp(UBYTE inf) +{ + UBYTE hi,lo; + + if(inf!=0) a->slidespeed = inf; + else inf = a->slidespeed; + + hi = inf>>4; + lo = inf&0xf; + + if(hi==0xf) + { if(!pf->vbtick) a->tmpperiod-=(UWORD)lo<<2; + } else if(hi==0xe) + { if(!pf->vbtick) a->tmpperiod-=lo; + } else + { if(pf->vbtick) a->tmpperiod-=(UWORD)inf<<2; + } +} + + +static void DoS3MTremor(UBYTE inf) +{ + UBYTE on,off; + + if(inf!=0) a->s3mtronof = inf; + else inf = a->s3mtronof; + + if(!pf->vbtick) return; + + on = (inf>>4)+1; + off = (inf&0xf)+1; + + a->s3mtremor %= (on+off); + a->volume = (a->s3mtremor < on ) ? a->tmpvolume : 0; + a->s3mtremor++; +} + + +static void DoS3MRetrig(UBYTE inf) +{ + UBYTE hi,lo; + + hi = inf >> 4; + lo = inf & 0xf; + + if(inf) + { a->s3mrtgslide = hi; + a->s3mrtgspeed = lo; + } + + /* only retrigger if */ + /* lo nibble > 0 */ + + if(a->s3mrtgspeed > 0) + { if(a->retrig == 0) + { /* when retrig counter reaches 0, */ + /* reset counter and restart the sample */ + + if(!a->kick) a->kick = 2; + a->retrig = a->s3mrtgspeed; + + if(pf->vbtick) /* don't slide on first retrig */ + { switch(a->s3mrtgslide) + { case 1: + case 2: + case 3: + case 4: + case 5: + a->tmpvolume-=(1<<(a->s3mrtgslide-1)); + break; + + case 6: + a->tmpvolume = (2*a->tmpvolume)/3; + break; + + case 7: + a->tmpvolume = a->tmpvolume>>1; + break; + + case 9: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + a->tmpvolume+=(1<<(a->s3mrtgslide-9)); + break; + + case 0xe: + a->tmpvolume=(3*a->tmpvolume)/2; + break; + + case 0xf: + a->tmpvolume=a->tmpvolume<<1; + break; + } + if(a->tmpvolume<0) a->tmpvolume = 0; + if(a->tmpvolume>64) a->tmpvolume = 64; + } + } + a->retrig--; /* countdown */ + } +} + + +static void DoS3MSpeed(UBYTE speed) +{ + if(pf->vbtick || pf->patdly2) return; + + if(speed) + { pf->sngspd = speed; + pf->vbtick = 0; + } +} + + +static void DoS3MTempo(UBYTE tempo) +{ + if(pf->vbtick || pf->patdly2) return; + pf->bpm = tempo; +} + + +static void DoS3MFineVibrato(void) +{ + UBYTE q; + UWORD temp; + + q = (a->vibpos>>2)&0x1f; + + switch(a->wavecontrol&3) + { case 0: /* sine */ + temp=VibratoTable[q]; + break; + + case 1: /* ramp down */ + q<<=3; + if(a->vibpos<0) q=255-q; + temp=q; + break; + + case 2: /* square wave */ + temp=255; + break; + + case 3: /* evil random */ + temp = rand() & 255; /* (range 0 to 255) */ + } + + temp*=a->vibdepth; + temp>>=8; + + if(a->vibpos>=0) + a->period = a->tmpperiod+temp; + else + a->period = a->tmpperiod-temp; + + a->vibpos += a->vibspd; +} + + +static void DoS3MTremolo(void) +{ + UBYTE q; + UWORD temp; + + q = (a->trmpos>>2)&0x1f; + + switch((a->wavecontrol>>4)&3) + { case 0: /* sine */ + temp = VibratoTable[q]; + break; + + case 1: /* ramp down */ + q<<=3; + if(a->trmpos<0) q = 255-q; + temp = q; + break; + + case 2: /* square wave */ + temp=255; + break; + + case 3: /* evil random */ + temp = rand() & 255; /* (range 0 to 255) */ + } + + temp*=a->trmdepth; + temp>>=7; + + if(a->trmpos>=0) + { a->volume = a->tmpvolume + temp; + if(a->volume>64) a->volume = 64; + } else + { a->volume = a->tmpvolume - temp; + if(a->volume<0) a->volume = 0; + } + + if(pf->vbtick) a->trmpos += a->trmspd; /* do not update when pf->vbtick==0 */ +} + + +/* -------------------------------------- */ +/* --> FastTracker 2 Specific Effects <-- */ +/* -------------------------------------- */ + +static void DoXMVolSlide(UBYTE inf) +{ + UBYTE lo,hi; + + if(inf) + a->s3mvolslide = inf; + + inf = a->s3mvolslide; + if(!pf->vbtick) return; + + lo = inf&0xf; + hi = inf>>4; + + if(hi==0) + a->tmpvolume-=lo; + else + a->tmpvolume+=hi; + + if(a->tmpvolume<0) a->tmpvolume=0; + else if(a->tmpvolume>64) a->tmpvolume=64; +} + + +static void DoXMGlobalSlide(UBYTE inf) +{ + if(pf->vbtick) + { if(inf) pf->globalslide=inf; else inf=pf->globalslide; + if(inf & 0xf0) inf &= 0xf0; + pf->volume = pf->volume + ((inf >> 4) - (inf & 0xf))*2; + + if(pf->volume<0) pf->volume = 0; + else if(pf->volume>128) pf->volume = 128; + } +} + + +static void DoXMPanSlide(UBYTE inf) +{ + UBYTE lo,hi; + SWORD pan; + + + if(inf!=0) a->pansspd = inf; + else inf = a->pansspd; + + if(!pf->vbtick) return; + + lo = inf & 0xf; + hi = inf >> 4; + + /* slide right has absolute priority: */ + + if(hi) lo = 0; + + pan = (a->panning == PAN_SURROUND) ? 128 : a->panning; + + pan -= lo; + pan += hi; + + if(pan < 0) pan = 0; + if(pan > 255) pan = 255; + + a->panning = pan; +} + + +static void DoXMExtraFineSlideUp(UBYTE inf) +{ + if(!pf->vbtick) + { if(inf) a->ffportupspd = inf; else inf = a->ffportupspd; + a->period -= inf; + } + a->tmpperiod = a->period; +} + + +static void DoXMExtraFineSlideDown(UBYTE inf) +{ + if(!pf->vbtick) + { if(inf) a->ffportdnspd = inf; else inf = a->ffportdnspd; + a->period += inf; + } + a->tmpperiod = a->period; +} + + +/* --------------------------------------- */ +/* --> ImpulseTracker Player Functions <-- */ +/* --------------------------------------- */ + +static void DoITChanVolSlide(UBYTE inf) +{ + UBYTE lo, hi; + + if(inf) a->chanvolslide = inf; + inf = a->chanvolslide; + + lo = inf&0xf; + hi = inf>>4; + + if(hi==0) + { a->chanvol-=lo; + } else if(lo==0) + { a->chanvol+=hi; + } else if(hi==0xf) + { if(!pf->vbtick) a->chanvol-=lo; + } else if(lo==0xf) + { if(!pf->vbtick) a->chanvol+=hi; + } + + if(a->chanvol<0) a->chanvol = 0; + if(a->chanvol>64) a->chanvol = 64; +} + + +static void DoITGlobalSlide(UBYTE inf) +{ + UBYTE lo,hi; + + if(inf) pf->globalslide = inf; + inf = pf->globalslide; + + lo = inf&0xf; + hi = inf>>4; + + if(lo==0) + { pf->volume += hi; + } else if(hi==0) + { pf->volume -= lo; + } else if(lo==0xf) + { if(!pf->vbtick) pf->volume += hi; + } else if(hi==0xf) + { if(!pf->vbtick) pf->volume -= lo; + } + + if(pf->volume < 0) pf->volume = 0; + if(pf->volume > 128) pf->volume = 128; +} + + +static void DoITPanSlide(UBYTE inf) +{ + UBYTE lo,hi; + SWORD pan; + + if(inf) a->pansspd = inf; + inf = a->pansspd; + + lo = inf & 0xf; + hi = inf >> 4; + + pan = (a->panning == PAN_SURROUND) ? 128 : a->panning; + + if(hi==0) + { pan += lo << 2; + } else if(lo==0) + { pan -= hi << 2; + } else if(hi==0xf) + { if(!pf->vbtick) pan += lo << 2; + } else if(lo==0xf) + { if(!pf->vbtick) pan -= hi << 2; + } + if(pan > 255) pan = 255; + if(pan < 0) pan = 0; + a->panning = /*pf->panning[mp_channel] =*/ pan; +} + + +static void DoITVibrato(void) +{ + UBYTE q; + UWORD temp; + + q = (a->vibpos>>2)&0x1f; + + switch(a->wavecontrol&3) + { case 0: /* sine */ + temp=VibratoTable[q]; + break; + + case 1: /* ramp down */ + q<<=3; + if(a->vibpos<0) q=255-q; + temp=q; + break; + + case 2: /* square wave */ + temp=255; + break; + + case 3: /* evil random */ + temp = rand() & 255; /* (range 0 to 255) */ + break; + } + + temp*=a->vibdepth; + temp>>=8; + temp<<=2; + + if(a->vibpos>=0) + a->period = a->tmpperiod+temp; + else + a->period = a->tmpperiod-temp; + + a->vibpos+=a->vibspd; +} + + +static void DoITFineVibrato(void) +{ + UBYTE q; + UWORD temp; + + q = (a->vibpos>>2)&0x1f; + + switch(a->wavecontrol&3) + { case 0: /* sine */ + temp=VibratoTable[q]; + break; + + case 1: /* ramp down */ + q<<=3; + if(a->vibpos<0) q = 255-q; + temp = q; + break; + + case 2: /* square wave */ + temp = 255; + break; + + case 3: /* evil random */ + temp = rand() & 255; /* (range 0 to 255) */ + break; + } + + temp*=a->vibdepth; + temp>>=8; + + if(a->vibpos>=0) + a->period = a->tmpperiod+temp; + else + a->period = a->tmpperiod-temp; + + a->vibpos+=a->vibspd; +} + + +static void DoITTremor(UBYTE inf) +{ + UBYTE on,off; + + if(inf!=0) a->s3mtronof = inf; + else inf = a->s3mtronof; + + if(!pf->vbtick) return; + + on=(inf>>4); + off=(inf&0xf); + + a->s3mtremor%=(on+off); + a->volume = (a->s3mtremor < on ) ? a->tmpvolume : 0; + a->s3mtremor++; +} + + +static void DoITPanbrello(void) +{ + UBYTE q; + static SLONG temp; + + q = a->panbpos; + + switch(a->panbwave) + { case 0: /* sine */ + temp = PanbrelloTable[q]; + break; + + /* only sinewave is correctly supported right now */ + + case 1: /* ramp down */ + q<<=3; + temp = q; + break; + + case 2: /* square wave */ + temp = 64; + break; + + case 3: /* evil random */ + if(a->panbpos >= a->panbspd) + { a->panbpos = 0; + temp = rand() & 255; + } + } + + temp*=a->panbdepth; + temp/=8; + + a->panning = pf->panning[mp_channel] + temp; + a->panbpos += a->panbspd; +} + + +static void DoITToneSlide(void) +{ + int dist; + + if(a->period == 0) return; + + if(!pf->vbtick) + { a->tmpperiod = a->period; + return; + } + + /* We have to slide a->period towards a->wantedperiod, */ + /* compute the difference between those two values */ + + dist = a->period - a->wantedperiod; + + if( (dist == 0) || /* if they are equal */ + ((a->slidespeed<<2) > abs(dist)) ) /* or if portamentospeed is too big */ + { a->period = a->wantedperiod; /* make tmpperiod equal tperiod */ + } else if(dist > 0) /* dist>0 ? */ + { a->period -= a->slidespeed << 2; /* then slide up */ + } else + { a->period += a->slidespeed << 2; /* dist<0 -> slide down */ + } + a->tmpperiod = a->period; +} + + +static void DoSSEffects(UBYTE dat) + +/* Impulse/Scream Tracker Sxx effects. */ +/* All Sxx effects share the same memory space. */ + +{ + UBYTE inf,c; + + inf = dat&0xf; + c = dat>>4; + + if(dat==0) + { c = a->sseffect; + inf = a->ssdata; + } else + { a->sseffect = c; + a->ssdata = inf; + } + + switch(c) + { case SS_GLISSANDO: /* S1x set glissando voice */ + DoEEffects(0x30|inf); + break; + + case SS_FINETUNE: /* S2x set finetune */ + DoEEffects(0x50|inf); + break; + + case SS_VIBWAVE: /* S3x set vibrato waveform */ + DoEEffects(0x40|inf); + break; + + case SS_TREMWAVE: /* S4x set tremolo waveform */ + DoEEffects(0x70|inf); + break; + + case SS_PANWAVE: /* The Satanic Panbrello waveform */ + a->panbwave = (UniGetByte()); + break; + + case SS_FRAMEDELAY: /* S6x Delay x number of frames (patdly) */ + DoEEffects(0xe0|inf); + break; + + case SS_S7EFFECTS: /* S7x Instrument / NNA commands */ + DoNNAEffects(UniGetByte()); + break; + + case SS_PANNING: /* S8x set panning position */ + DoEEffects(0x80 | inf); + break; + + case SS_SURROUND: /* S9x Set Surround Sound */ + a->panning = pf->panning[mp_channel] = PAN_SURROUND; + break; + + case SS_HIOFFSET: /* SAy Set high order sample offset yxx00h */ + a->hioffset |= UniGetByte() << 16; + break; + + case SS_PATLOOP: /* SBx pattern loop */ + DoEEffects(0x60|inf); + break; + + case SS_NOTECUT: /* SCx notecut */ + DoEEffects(0xC0|inf); + break; + + case SS_NOTEDELAY: /* SDx notedelay */ + DoEEffects(0xD0|inf); + break; + + case SS_PATDELAY: /* SEx patterndelay */ + DoEEffects(0xE0|inf); + break; + } +} + + +static void DoVolEffects(UBYTE c) + +/* Impulse Tracker Volume/Pan Column effects. */ +/* All volume/pan column effects share the same memory space. */ + +{ + UBYTE inf; + + inf = UniGetByte(); + + if(c==0 && inf==0) + { c = a->voleffect; + inf = a->voldata; + } else + { a->voleffect = c; + a->voldata = inf; + } + + switch(c) + { case 0: break; /* do nothing */ + case VOL_VOLUME: + if(pf->vbtick) break; + if(inf>64) inf = 64; + a->tmpvolume = inf; + break; + + case VOL_PANNING: + if(pf->panflag) + { a->panning = inf; + pf->panning[mp_channel] = inf; + } + break; + + case VOL_VOLSLIDE: + DoS3MVolSlide(inf); + break; + + case VOL_PITCHSLIDEDN: + DoS3MSlideDn(UniGetByte()); + break; + + case VOL_PITCHSLIDEUP: + DoS3MSlideUp(UniGetByte()); + break; + + case VOL_PORTAMENTO: + if(inf != 0) a->slidespeed = inf; + + if(a->period != 0) + { if(!(pf->vbtick==pf->sngspd-1) && (a->newsamp)) + { a->kick = 1; + a->start = -1; + /*a->period *= a->speed * a->newsamp; */ + } else + a->kick = 0; + + DoITToneSlide(); + a->ownper = 1; + } + break; + + case VOL_VIBRATO: + if(inf & 0x0f) a->vibdepth = inf & 0xf; + if(inf & 0xf0) a->vibspd = (inf & 0xf0) >> 2; + DoITVibrato(); + a->ownper = 1; + break; + } +} + + + +/* -------------------------------- */ +/* --> General Player Functions <-- */ +/* -------------------------------- */ + +static void pt_playeffects(void) +{ + UBYTE dat,c; + + while(c = UniGetByte()) + switch(c) + { case UNI_NOTE: + case UNI_INSTRUMENT: + UniSkipOpcode(c); + break; + + case UNI_PTEFFECT0: + DoPTEffect0(UniGetByte()); + break; + + case UNI_PTEFFECT1: + dat = UniGetByte(); + if(dat != 0) a->slidespeed = (UWORD)dat << 2; + if(pf->vbtick) a->tmpperiod -= a->slidespeed; + break; + + case UNI_PTEFFECT2: + dat = UniGetByte(); + if(dat != 0) a->slidespeed = (UWORD)dat << 2; + if(pf->vbtick) a->tmpperiod += a->slidespeed; + break; + + case UNI_PTEFFECT3: + dat = UniGetByte(); + + if(dat!=0) + { a->portspeed = dat; + a->portspeed <<= 2; + } + + if(a->period != 0) + { a->kick = 0; /* temp XM fix */ + DoToneSlide(); + a->ownper = 1; + } + break; + + case UNI_PTEFFECT4: + dat = UniGetByte(); + if(dat & 0x0f) a->vibdepth = dat & 0xf; + if(dat & 0xf0) a->vibspd = (dat & 0xf0) >> 2; + DoVibrato(); + a->ownper = 1; + break; + + case UNI_PTEFFECT5: + dat = UniGetByte(); + a->kick = 0; + DoToneSlide(); + DoVolSlide(dat); + a->ownper = 1; + break; + + case UNI_PTEFFECT6: + dat = UniGetByte(); + DoVibrato(); + DoVolSlide(dat); + a->ownper = 1; + break; + + case UNI_PTEFFECT7: + dat = UniGetByte(); + if(dat & 0x0f) a->trmdepth = dat & 0xf; + if(dat & 0xf0) a->trmspd = (dat & 0xf0) >> 2; + DoTremolo(); + a->ownvol = 1; + break; + + case UNI_PTEFFECT8: + dat = UniGetByte(); + if(pf->panflag) + { a->panning = dat; + pf->panning[mp_channel] = dat; + } + break; + + case UNI_PTEFFECT9: + dat = UniGetByte(); + if(dat) a->soffset = (UWORD)dat << 8; + a->start = a->hioffset | a->soffset; + if((a->s != NULL) && (a->start > a->s->length)) a->start = a->s->loopstart; + break; + + case UNI_PTEFFECTA: + DoVolSlide(UniGetByte()); + break; + + case UNI_PTEFFECTB: + dat = UniGetByte(); + if(pf->patdly2) break; + pf->patbrk = 0; + pf->sngpos = dat-1; + pf->posjmp = 3; + break; + + case UNI_PTEFFECTC: + dat = UniGetByte(); + if(pf->vbtick) break; + if(dat>64) dat = 64; + a->tmpvolume = dat; + break; + + case UNI_PTEFFECTD: + dat = UniGetByte(); + if(pf->patdly2) break; + pf->patbrk = dat; + if(pf->patbrk>pf->pattrows[mp_channel]) + pf->patbrk = pf->pattrows[mp_channel]; + pf->posjmp = 3; + break; + + case UNI_PTEFFECTE: + DoEEffects(UniGetByte()); + break; + + case UNI_PTEFFECTF: + dat = UniGetByte(); + + if(pf->vbtick || pf->patdly2) break; + + if(pf->extspd && (dat >= 0x20)) + pf->bpm = dat; + else + { if(dat) + { pf->sngspd = dat; + pf->vbtick = 0; + } + } + break; + + case UNI_S3MEFFECTA: + DoS3MSpeed(UniGetByte()); + break; + + case UNI_S3MEFFECTD: + DoS3MVolSlide(UniGetByte()); + break; + + case UNI_S3MEFFECTE: + DoS3MSlideDn(UniGetByte()); + break; + + case UNI_S3MEFFECTF: + DoS3MSlideUp(UniGetByte()); + break; + + case UNI_S3MEFFECTI: + DoS3MTremor(UniGetByte()); + a->ownvol = 1; + break; + + case UNI_S3MEFFECTQ: + DoS3MRetrig(UniGetByte()); + break; + + case UNI_S3MEFFECTR: + dat = UniGetByte(); + if(dat & 0x0f) a->trmdepth = dat & 0xf; + if(dat & 0xf0) a->trmspd = (dat & 0xf0) >> 2; + DoS3MTremolo(); + a->ownvol = 1; + break; + + case UNI_S3MEFFECTT: + DoS3MTempo(UniGetByte()); + break; + + case UNI_S3MEFFECTU: + dat = UniGetByte(); + if(dat & 0x0f) a->vibdepth = dat & 0xf; + if(dat & 0xf0) a->vibspd = (dat & 0xf0) >> 2; + DoS3MFineVibrato(); + a->ownper = 1; + break; + + case UNI_KEYOFF: + a->keyoff |= KEY_OFF; + if(a->i != NULL) + { if(!(a->i->volflg & EF_ON) || (a->i->volflg & EF_LOOP)) + a->keyoff = KEY_KILL; + } + break; + + case UNI_KEYFADE: + if(pf->vbtick >= UniGetByte()) + { a->keyoff = KEY_KILL; + if((a->i != NULL) && !(a->i->volflg & EF_ON)) + a->fadevol = 0; + } + break; + + case UNI_VOLEFFECTS: + DoVolEffects(UniGetByte()); + break; + + case UNI_XMEFFECT4: + dat = UniGetByte(); + if(pf->vbtick) + { if(dat & 0x0f) a->vibdepth = dat & 0xf; + if(dat & 0xf0) a->vibspd = (dat & 0xf0) >> 2; + } + DoVibrato(); + a->ownper = 1; + break; + + case UNI_XMEFFECTA: + DoXMVolSlide(UniGetByte()); + break; + + case UNI_XMEFFECTE1: /* xm fineslide up */ + dat = UniGetByte(); + if(!pf->vbtick) + { if(dat) a->fportupspd = dat; else dat = a->fportupspd; + a->tmpperiod -= (dat << 2); + } + break; + + case UNI_XMEFFECTE2: /* xm fineslide dn */ + dat = UniGetByte(); + if(!pf->vbtick) + { if(dat) a->fportdnspd = dat; else dat = a->fportdnspd; + a->tmpperiod += (dat<<2); + } + break; + + case UNI_XMEFFECTEA: /* fine volume slide up */ + dat = UniGetByte(); + if(pf->vbtick) break; + if(dat) a->fslideupspd = dat; else dat = a->fslideupspd; + a->tmpvolume+=dat; + if(a->tmpvolume>64) a->tmpvolume = 64; + break; + + case UNI_XMEFFECTEB: /* fine volume slide dn */ + dat = UniGetByte(); + if(pf->vbtick) break; + if(dat) a->fslidednspd = dat; else dat = a->fslidednspd; + a->tmpvolume-=dat; + if(a->tmpvolume<0) a->tmpvolume = 0; + break; + + case UNI_XMEFFECTG: + pf->volume = UniGetByte(); + break; + + case UNI_XMEFFECTH: + DoXMGlobalSlide(UniGetByte()); + break; + + case UNI_XMEFFECTL: + dat = UniGetByte(); + if(!pf->vbtick && a->i!=NULL) + { UWORD points; + INSTRUMENT *i = a->i; + MP_VOICE *aout; + + if((aout = a->slave) != NULL) + { points = i->volenv[i->volpts-1].pos; + aout->venv.p = aout->venv.env[(dat>points) ? points : dat].pos; + + points = i->panenv[i->panpts-1].pos; + aout->penv.p = aout->penv.env[(dat>points) ? points : dat].pos; + } + } + break; + + case UNI_XMEFFECTP: + DoXMPanSlide(UniGetByte()); + break; + + case UNI_XMEFFECTX1: + DoXMExtraFineSlideUp(UniGetByte()); + a->ownper = 1; + break; + + case UNI_XMEFFECTX2: + DoXMExtraFineSlideDown(UniGetByte()); + a->ownper = 1; + break; + + case UNI_ITEFFECTG: + dat = UniGetByte(); + if(dat != 0) a->slidespeed = dat; + + if(a->period != 0) + { if((pf->vbtick < 1) && (a->newsamp)) + { a->kick = 1; + a->start = -1; + /*a->period *= a->speed * a->newsamp; */ + } else + a->kick = 0; + + DoITToneSlide(); + a->ownper = 1; + } + break; + + case UNI_ITEFFECTH: /* it vibrato */ + dat = UniGetByte(); + if(dat & 0x0f) a->vibdepth = dat & 0xf; + if(dat & 0xf0) a->vibspd = (dat & 0xf0) >> 2; + DoITVibrato(); + a->ownper = 1; + break; + + case UNI_ITEFFECTI: /* it tremor */ + DoITTremor(UniGetByte()); + a->ownvol = 1; + break; + + case UNI_ITEFFECTM: + a->chanvol = UniGetByte(); + if(a->chanvol > 64) a->chanvol = 64; + else if(a->chanvol < 0) a->chanvol = 0; + break; + + case UNI_ITEFFECTN: /* Slide / Fineslide Channel Volume */ + DoITChanVolSlide(UniGetByte()); + break; + + case UNI_ITEFFECTP: /* slide / fineslide channel panning */ + DoITPanSlide(UniGetByte()); + break; + + case UNI_ITEFFECTU: /* fine vibrato */ + dat = UniGetByte(); + if(dat & 0x0f) a->vibdepth = dat & 0xf; + if(dat & 0xf0) a->vibspd = (dat & 0xf0) >> 2; + DoITFineVibrato(); + a->ownper = 1; + break; + + case UNI_ITEFFECTW: /* Slide / Fineslide Global volume */ + DoITGlobalSlide(UniGetByte()); + break; + + case UNI_ITEFFECTY: /* The Satanic Panbrello */ + dat = UniGetByte(); + if(dat & 0x0f) a->panbdepth = (dat & 0xf); + if(dat & 0xf0) a->panbspd = (dat & 0xf0) >> 4; + DoITPanbrello(); + break; + + case UNI_ITEFFECTS0: + DoSSEffects(UniGetByte()); + break; + + default: + UniSkipOpcode(c); + break; + } +} + + +static void DoNNAEffects(UBYTE dat) +{ + int t; + MP_VOICE *aout; + + dat &= 0xf; + aout = (a->slave==NULL) ? &aout_dummy : a->slave; + + switch(dat) + { case 0x0: /* Past note cut */ + for(t=0; tvoice[t].master == a) + pf->voice[t].fadevol = 0; + break; + + case 0x1: /* Past note off */ + for(t=0; tvoice[t].master == a) + { pf->voice[t].keyoff |= KEY_OFF; + if(!(pf->voice[t].venv.flg & EF_ON)) + pf->voice[t].keyoff = KEY_KILL; + } + break; + + case 0x2: /* Past note fade */ + for(t=0; tvoice[t].master == a) + pf->voice[t].keyoff |= KEY_FADE; + break; + + case 0x3: /* set NNA note cut */ + a->nna = (a->nna & ~0x3f) | NNA_CUT; + break; + + case 0x4: /* set NNA note continue */ + a->nna = (a->nna & ~0x3f) | NNA_CONTINUE; + break; + + case 0x5: /* set NNA note off */ + a->nna = (a->nna & ~0x3f) | NNA_OFF; + break; + + case 0x6: /* set NNA note fade */ + a->nna = (a->nna & ~0x3f) | NNA_FADE; + break; + + case 0x7: /* disable volume envelope */ + aout->volflg &= ~EF_ON; + break; + + case 0x8: /* enable volume envelope */ + aout->volflg |= EF_ON; + break; + + case 0x9: /* disable panning envelope */ + aout->panflg &= ~EF_ON; + break; + + case 0xa: /* enable panning envelope */ + aout->panflg |= EF_ON; + break; + + case 0xb: /* disable pitch envelope */ + aout->pitflg &= ~EF_ON; + break; + + case 0xc: /* enable pitch envelope */ + aout->pitflg |= EF_ON; + break; + } +} + + +void Player_HandleTick(void) +{ + MP_VOICE *aout; /* current audout (slave of audtmp) it's working on */ + int t, tr, t2, k; + ULONG tmpvol, period; + UBYTE c; + BOOL funky; + SAMPLE *s; + INSTRUMENT *i; + + if(isfirst) + { /* don't handle the very first ticks, this allows the */ + /* other hardware to settle down so we don't loose any */ + /* starting notes */ + isfirst--; + return; + } + + if(pf==NULL || pf->forbid) return; + + if(++pf->vbtick >= pf->sngspd) + { pf->patpos++; + pf->vbtick = 0; + + /* process pattern-delay. pf->patdly2 is the counter and pf->patdly */ + /* is the command memory. */ + + if(pf->patdly) + { pf->patdly2 = pf->patdly; + pf->patdly = 0; + } + + if(pf->patdly2) + { /* patterndelay active */ + if(--pf->patdly2) pf->patpos--; /* so turn back pf->patpos by 1 */ + } + + /* Do we have to get a new patternpointer ? */ + /* (when pf->patpos reaches 64 or when */ + /* a patternbreak is active) */ + + if(pf->patpos == pf->numrow) pf->posjmp = 3; + + if(pf->posjmp) + { pf->patpos = pf->patbrk; + pf->sngpos+=(pf->posjmp-2); + pf->patbrk = pf->posjmp = 0; + if(pf->sngpos>=pf->numpos) + { if(!pf->loop) return; + if((pf->sngpos = pf->reppos) == 0) + { pf->volume = pf->initvolume; + pf->sngspd = pf->initspeed; + pf->bpm = pf->inittempo; + } + } + if(pf->sngpos<0) pf->sngpos = pf->numpos-1; + } + + if(!pf->patdly2) + { for(t=0; tnumchn; t++) + { UBYTE inst; + + tr = pf->patterns[(pf->positions[pf->sngpos]*pf->numchn)+t]; + pf->numrow = pf->pattrows[pf->positions[pf->sngpos]]; + + mp_channel = t; + a = &pf->control[t]; + a->row = (tr < pf->numtrk) ? UniFindRow(pf->tracks[tr],pf->patpos) : NULL; + a->newsamp = 0; + + if(a->row==NULL) continue; + UniSetRow(a->row); + funky = 0; /* Funky is set to indicate note or inst change */ + + while(c = UniGetByte()) + { switch(c) + { case UNI_NOTE: + funky |= 1; + a->anote = UniGetByte(); + a->kick = 1; + a->start = -1; + + /* retrig tremolo and vibrato waves ? */ + + if(!(a->wavecontrol & 0x80)) a->trmpos = 0; + if(!(a->wavecontrol & 0x08)) a->vibpos = 0; + if(!a->panbwave) a->panbpos = 0; + break; + + case UNI_INSTRUMENT: + funky |= 2; + inst = UniGetByte(); + if(inst >= pf->numins) break; /* <- safety valve */ + + a->i = (pf->flags & UF_INST) ? &pf->instruments[inst] : NULL; + a->retrig = 0; + a->s3mtremor = 0; + a->sample = inst; + break; + + default: + UniSkipOpcode(c); + break; + } + } + + if(funky) + { i = a->i; + if(i != NULL) + { if(i->samplenumber[a->anote] >= pf->numsmp) continue; + s = &pf->samples[i->samplenumber[a->anote]]; + a->note = i->samplenote[a->anote]; + } else + { a->note = a->anote; + s = &pf->samples[a->sample]; + } + + if(a->s != s) + { a->s = s; + a->newsamp = a->period; + } + + /* channel or instrument determined panning ? */ + + a->panning = pf->panning[t]; + if(s->flags & SF_OWNPAN) + a->panning = s->panning; + else if((i != NULL) && (i->flags & IF_OWNPAN)) + a->panning = i->panning; + + a->handle = s->handle; + a->speed = s->speed; + + if(i != NULL) + { if(i->flags & IF_PITCHPAN) + a->panning += ((a->anote-i->pitpancenter) * i->pitpansep) / 8; + a->pitflg = i->pitflg; + a->volflg = i->volflg; + a->panflg = i->panflg; + a->nna = i->nnatype; + a->dca = i->dca; + a->dct = i->dct; + } else + { a->pitflg = 0; + a->volflg = 0; + a->panflg = 0; + a->nna = 0; + a->dca = 0; + a->dct = 0; + } + + if(funky & 2) + { /* IT's random volume variations: 0:8 bit fixed, and one bit for sign. */ + a->volume = s->volume; + a->tmpvolume = s->volume; + if((s != NULL) && (i != NULL)) + { a->volume = a->tmpvolume = s->volume + ((s->volume * ((SLONG)i->rvolvar * (SLONG)((rand() & 511)-255))) / 25600); + if(a->panning != PAN_SURROUND) a->panning += ((a->panning * ((SLONG)i->rpanvar * (SLONG)((rand() & 511)-255))) / 25600); + } + } + + period = GetPeriod(a->note, a->speed); + a->wantedperiod = period; + a->tmpperiod = period; + a->keyoff = KEY_KICK; + } + } + } + } + + /* Update effects */ + + for(t=0; tnumchn; t++) + { mp_channel = t; + a = &pf->control[t]; + + if((aout = a->slave) != NULL) + { a->fadevol = aout->fadevol; + a->period = aout->period; + if(a->kick != 1) a->keyoff = aout->keyoff; + } + + if(a->row == NULL) continue; + UniSetRow(a->row); + + a->ownper = a->ownvol = 0; + pt_playeffects(); + if(!a->ownper) a->period = a->tmpperiod; + if(!a->ownvol) a->volume = a->tmpvolume; + + if(a->s != NULL) + { if(a->i != NULL) + a->outvolume = (a->volume * a->s->globvol * a->i->globvol) / 1024; /* max val: 256 */ + else + a->outvolume = (a->volume * a->s->globvol) / 16; /* max val: 256 */ + if(a->outvolume > 256) a->volume = 256; + } + } + + + a = pf->control; + if(pf->flags & UF_NNA) + { for(t=0; tnumchn; t++, a++) + { if(a->kick == 1) + { if(a->slave != NULL) + { aout = a->slave; + if(aout->nna & 0x3f) + { /* oh boy, we have to do an NNA */ + /* Make sure the old MP_VOICE channel knows it has no master now! */ + + a->slave = NULL; /* assume the channel is taken by NNA */ + aout->mflag = 0; + + switch(aout->nna) + { case NNA_CONTINUE: + break; /* continue note, do nothing */ + + case NNA_OFF: /* note off */ + aout->keyoff |= KEY_OFF; + if(!(aout->volflg & EF_ON) || (aout->volflg & EF_LOOP)) + aout->keyoff = KEY_KILL; + break; + + case NNA_FADE: + aout->keyoff |= KEY_FADE; + break; + } + } + } + + k = 0; + if(a->dct != DCT_OFF) + { for(t2=0; t2voice[t2].masterchn == t) && (a->sample == pf->voice[t2].sample)) + { switch(a->dct) + { case DCT_NOTE: + if(a->note == pf->voice[t2].note) + k = 1; + break; + + case DCT_SAMPLE: + if(a->handle == pf->voice[t2].handle) + k = 1; + break; + + case DCT_INST: + k = 1; + break; + } + + if(k==1) + { k = 0; + switch(a->dca) + { case DCA_CUT : + pf->voice[t2].fadevol = 0; + a->slave = &pf->voice[a->slavechn=t2]; + break; + + case DCA_OFF : + /*a->slave = &pf->voice[newchn]; */ + pf->voice[t2].keyoff |= KEY_OFF; + if(!(pf->voice[t2].volflg & EF_ON) || (pf->voice[t2].volflg & EF_LOOP)) + pf->voice[t2].keyoff = KEY_KILL; + break; + + case DCA_FADE: + /*a->slave = &pf->voice[newchn]; */ + pf->voice[t2].keyoff |= KEY_FADE; + break; + } + } + } + } + } /* DCT checking */ + } /* if a->kick */ + } /* for loop */ + } + + a = pf->control; + for(t=0; tnumchn; t++, a++) + { int newchn; + + if(a->notedelay) continue; + + if(a->kick == 1) + { /* If no channel was cut above, find an empty or quiet channel here */ + if(pf->flags & UF_NNA) + { if(a->slave==NULL) + { if((newchn = MP_FindEmptyChannel(t)) != -1) + a->slave = &pf->voice[a->slavechn=newchn]; + } + } else + a->slave = &pf->voice[a->slavechn=t]; + + /* Assign parts of MP_VOICE only done for a KICK! */ + + if((aout = a->slave) != NULL) + { if(aout->mflag && (aout->master!=NULL)) aout->master->slave = NULL; + a->slave = aout; + aout->master = a; + aout->masterchn = t; + aout->mflag = 1; + } + } else + { aout = a->slave; + } + + if(aout != NULL) + { aout->kick = a->kick; + aout->i = a->i; + aout->s = a->s; + aout->sample = a->sample; + aout->handle = a->handle; + aout->period = a->period; + aout->panning = a->panning; + aout->chanvol = a->chanvol; + aout->fadevol = a->fadevol; + aout->start = a->start; + aout->volflg = a->volflg; + aout->panflg = a->panflg; + aout->pitflg = a->pitflg; + aout->volume = a->outvolume; + aout->keyoff = a->keyoff; + aout->note = a->note; + aout->nna = a->nna; + } + a->kick = 0; + + } + + /* Now set up the actual hardware channel playback information */ + + for(t=0; tvoice[mp_channel = t]; + i = aout->i; + s = aout->s; + + if(s==NULL) continue; + + if(aout->period < 40) aout->period = 40; + if(aout->period > 50000) aout->period = 50000; + + if(aout->kick) + { Voice_Play(t,s,(aout->start == -1) ? ((s->flags & SF_UST_LOOP) ? s->loopstart : 0) : aout->start); + /*aout->keyoff = KEY_KICK; */ + aout->fadevol = 32768; + aout->aswppos = 0; + + if((i != NULL) && (aout->kick != 2)) + { StartEnvelope(&aout->venv, aout->volflg, i->volpts, i->volsusbeg, i->volsusend, i->volbeg, i->volend, i->volenv, aout->keyoff); + StartEnvelope(&aout->penv, aout->panflg, i->panpts, i->pansusbeg, i->pansusend, i->panbeg, i->panend, i->panenv, aout->keyoff); + StartEnvelope(&aout->cenv, aout->pitflg, i->pitpts, i->pitsusbeg, i->pitsusend, i->pitbeg, i->pitend, i->pitenv, aout->keyoff); + } + aout->kick = 0; + } + + if(i != NULL) + { envvol = ProcessEnvelope(&aout->venv,256,aout->keyoff); + envpan = ProcessEnvelope(&aout->penv,128,aout->keyoff); + envpit = ProcessEnvelope(&aout->cenv,32,aout->keyoff); + } + + tmpvol = aout->fadevol; /* max 32768 */ + tmpvol *= aout->chanvol; /* * max 64 */ + tmpvol *= aout->volume; /* * max 256 */ + tmpvol /= 16384L; /* tmpvol is max 32768 */ + aout->totalvol = tmpvol>>2; /* totalvolume used to determine samplevolume */ + tmpvol *= envvol; /* * max 256 */ + tmpvol *= pf->volume; /* * max 128 */ + tmpvol /= 4194304UL; + + if((aout->masterchn != -1) && pf->control[aout->masterchn].muted) /* Channel Muting Line */ + Voice_SetVolume(t,0); + else + Voice_SetVolume(t,tmpvol); + + + if(aout->panning == PAN_SURROUND) + Voice_SetPanning(t, PAN_SURROUND); + else + { if(aout->penv.flg & EF_ON) + Voice_SetPanning(t,DoPan(envpan,aout->panning)); + else + Voice_SetPanning(t,aout->panning); + } + + if(aout->period && s->vibdepth) + { switch(s->vibtype) + { case 0: + vibval = avibtab[s->avibpos & 127]; + if(s->avibpos & 0x80) vibval=-vibval; + break; + + case 1: + vibval = 64; + if(s->avibpos & 0x80) vibval=-vibval; + break; + + case 2: + vibval = 63-(((s->avibpos + 128) & 255) >> 1); + break; + + case 3: + vibval = (((s->avibpos + 128) & 255) >> 1) - 64; + break; + } + } + + if(s->vibflags & AV_IT) + { if((aout->aswppos >> 8) < s->vibdepth) + { aout->aswppos += s->vibsweep; + vibdpt = aout->aswppos; + } else + vibdpt = s->vibdepth << 8; + vibval = (vibval*vibdpt) >> 16; + if(aout->mflag) + { if(!(pf->flags & UF_LINEAR)) vibval>>=1; + aout->period -= vibval; + } + } else /* do XM style auto-vibrato */ + { if(!(aout->keyoff & KEY_OFF)) + { if(aout->aswppos < s->vibsweep) + { vibdpt = (aout->aswppos*s->vibdepth) / s->vibsweep; + aout->aswppos++; + } else + vibdpt = s->vibdepth; + } else + { /* key-off -> depth becomes 0 if final depth wasn't reached */ + /* or stays at final level if depth WAS reached */ + if(aout->aswppos>=s->vibsweep) + vibdpt = s->vibdepth; + else + vibdpt = 0; + } + vibval = (vibval*vibdpt)>>8; + aout->period -= vibval; + } + + /* update vibrato position */ + s->avibpos = (s->avibpos+s->vibrate) & 0xff; + + if(aout->cenv.flg & EF_ON) + { envpit = envpit-32; + aout->period -= envpit; + } + + Voice_SetFrequency(t,getfrequency(pf->flags,aout->period)); + + if(aout->fadevol == 0) /* check for a dead note (fadevol = 0) */ + Voice_Stop(t); + else + { /* if keyfade, start substracting */ + /* fadeoutspeed from fadevol: */ + + if((i != NULL) && (aout->keyoff & KEY_FADE)) + { if(aout->fadevol >= i->volfade) + aout->fadevol -= i->volfade; + else + aout->fadevol = 0; + } + } + + MD_SetBPM(pf->bpm); + } +} + + +BOOL Player_Init(UNIMOD *mf) +{ + int t; + + mf->extspd = 1; + mf->panflag = 1; + mf->loop = 0; + + mf->pat_reppos = 0; + mf->pat_repcnt = 0; + mf->sngpos = 0; + mf->sngspd = mf->initspeed; + mf->volume = mf->initvolume; + + mf->vbtick = mf->sngspd; + mf->patdly = 0; + mf->patdly2 = 0; + mf->bpm = mf->inittempo; + + mf->patpos = 0; + mf->posjmp = 2; /* <- make sure the player fetches the first note */ + mf->patbrk = 0; + + /* Make sure the player doesn't start with garbage: */ + + if((mf->control=(MP_CONTROL *)_mm_calloc(mf->numchn,sizeof(MP_CONTROL)))==NULL) return 1; + if((mf->voice=(MP_VOICE *)_mm_calloc(md_sngchn,sizeof(MP_VOICE)))==NULL) return 1; + + for(t=0; tnumchn; t++) + { mf->control[t].chanvol = mf->chanvol[t]; + mf->control[t].panning = mf->panning[t]; + } + + return 0; +} + + +void Player_Exit(UNIMOD *mf) +{ + if(mf==NULL) return; + if(mf==pf) + { Player_Stop(); + pf = NULL; + } + if(mf->control!=NULL) free(mf->control); + if(mf->voice!=NULL) free(mf->voice); + mf->control = NULL; + mf->voice = NULL; + +} + + +void Player_SetVolume(int volume) +{ + if(pf==NULL) return; + + if(volume > 128) volume = 128; + if(volume < 0) volume = 0; + + pf->volume = volume; +} + + +UNIMOD *Player_GetUnimod(void) +{ + return pf; +} + + +void Player_Start(UNIMOD *mf) +{ + int t; + + if(!MikMod_Active()) + { isfirst = 2; + MikMod_EnableOutput(); + } + + if(mf==NULL) return; + + mf->forbid = 0; + if(pf != mf) + { /* new song is being started, so completely stop out the old one. */ + if(pf!=NULL) pf->forbid = 1; + for(t=0; tforbid = 1; + pf = NULL; +} + + +BOOL MP_Playing(UNIMOD *mf) +{ + if((mf==NULL) || (mf!=pf)) return 0; + return(!(mf->sngpos>=mf->numpos)); +} + + +BOOL Player_Active(void) +{ + if(pf==NULL) return 0; + return(!(pf->sngpos>=pf->numpos)); +} + + +void MP_NextPosition(UNIMOD *mf) +{ + int t; + + if(mf==NULL) return; + mf->forbid = 1; + mf->posjmp = 3; + mf->patbrk = 0; + mf->vbtick = mf->sngspd; + + for(t=0; tvoice[t].i = NULL; + mf->voice[t].s = NULL; + } + + for(t=0; tnumchn; t++) + { mf->control[t].i = NULL; + mf->control[t].s = NULL; + } + mf->forbid = 0; +} + + +void Player_NextPosition(void) +{ + MP_NextPosition(pf); +} + + +void MP_PrevPosition(UNIMOD *mf) +{ + int t; + + if(mf==NULL) return; + mf->forbid = 1; + mf->posjmp = 1; + mf->patbrk = 0; + mf->vbtick = mf->sngspd; + + for(t=0; tvoice[t].i = NULL; + mf->voice[t].s = NULL; + } + + for(t=0; tnumchn; t++) + { mf->control[t].i = NULL; + mf->control[t].s = NULL; + } + + mf->forbid = 0; +} + + +void Player_PrevPosition(void) +{ + MP_PrevPosition(pf); +} + + +void MP_SetPosition(UNIMOD *mf, UWORD pos) +{ + int t; + + if(mf==NULL) return; + mf->forbid = 1; + if(pos>=mf->numpos) pos = mf->numpos; + mf->posjmp = 2; + mf->patbrk = 0; + mf->sngpos = pos; + mf->vbtick = mf->sngspd; + + for(t=0; tvoice[t].i = NULL; + mf->voice[t].s = NULL; + } + + for(t=0; tnumchn; t++) + { mf->control[t].i = NULL; + mf->control[t].s = NULL; + } + + mf->forbid = 0; +} + + +void Player_SetPosition(UWORD pos) +{ + MP_SetPosition(pf,pos); +} + + +void MP_Unmute(UNIMOD *mf, SLONG arg1, ...) +{ + va_list ap; + SLONG t, arg2, arg3; + + va_start(ap,arg1); + + if(mf != NULL) + { switch(arg1) + { case MUTE_INCLUSIVE: + if((!(arg2=va_arg(ap,SLONG))) && (!(arg3=va_arg(ap,SLONG))) || (arg2 > arg3) || (arg3 >= mf->numchn)) + { va_end(ap); + return; + } + for(;arg2numchn && arg2<=arg3;arg2++) + mf->control[arg2].muted = 0; + break; + + case MUTE_EXCLUSIVE: + if((!(arg2=va_arg(ap,SLONG))) && (!(arg3=va_arg(ap,SLONG))) || (arg2 > arg3) || (arg3 >= mf->numchn)) + { va_end(ap); + return; + } + for(t=0;tnumchn;t++) + { if ((t>=arg2) && (t<=arg3)) continue; + mf->control[t].muted = 0; + } + break; + + default: + if(arg1numchn) mf->control[arg1].muted = 0; + break; + } + } + va_end(ap); + + return; +} + + +void Player_Unmute(SLONG arg1, ...) +{ + va_list argptr; + MP_Unmute(pf,arg1, argptr); + va_end(argptr); +} + + +void MP_Mute(UNIMOD *mf, SLONG arg1, ...) +{ + va_list ap; + SLONG t, arg2, arg3; + + va_start(ap,arg1); + + if(mf != NULL) + { switch (arg1) + { case MUTE_INCLUSIVE: + if ((!(arg2=va_arg(ap,SLONG))) && (!(arg3=va_arg(ap,SLONG))) || (arg2 > arg3) || (arg3 >= mf->numchn)) + { va_end(ap); + return; + } + for(;arg2numchn && arg2<=arg3;arg2++) + mf->control[arg2].muted = 1; + break; + + case MUTE_EXCLUSIVE: + if ((!(arg2=va_arg(ap,SLONG))) && (!(arg3=va_arg(ap,SLONG))) || (arg2 > arg3) || (arg3 >= mf->numchn)) + { va_end(ap); + return; + } + for (t=0; tnumchn; t++) + { if ((t>=arg2) && (t<=arg3)) continue; + mf->control[t].muted = 1; + } + break; + + default: + if(arg1numchn) + mf->control[arg1].muted = 1; + break; + } + } + va_end(ap); + + return; +} + + +void Player_Mute(SLONG arg1, ...) +{ + va_list argptr; + MP_Mute(pf,arg1, argptr); + va_end(argptr); +} + + +void MP_ToggleMute(UNIMOD *mf, SLONG arg1, ...) +{ + va_list ap; + SLONG arg2, arg3; + ULONG t; + + va_start(ap,arg1); + + if(mf != NULL) + { switch (arg1) + { case MUTE_INCLUSIVE: + if ((!(arg2=va_arg(ap,SLONG))) && (!(arg3=va_arg(ap,SLONG))) || (arg2 > arg3) || (arg3 >= mf->numchn)) + { va_end(ap); + return; + } + for(; arg2numchn && arg2<=arg3; arg2++) + mf->control[arg2].muted = (mf->control[arg2].muted) ? 0 : 1; + + break; + + case MUTE_EXCLUSIVE: + if ((!(arg2=va_arg(ap,SLONG))) && (!(arg3=va_arg(ap,SLONG))) || (arg2 > arg3) || (arg3 >= mf->numchn)) + { va_end(ap); + return; + } + for (t=0;tnumchn;t++) + { if((t>=arg2) && (t<=arg3)) continue; + mf->control[t].muted = (mf->control[t].muted) ? 0 : 1; + } + break; + + default: + if(arg1numchn) + mf->control[arg1].muted = (mf->control[arg1].muted) ? 0 : 1; + break; + } + } + va_end(ap); + + return; +} + + +void Player_ToggleMute(SLONG arg1, ...) +{ + va_list argptr; + MP_ToggleMute(pf,arg1, argptr); + va_end(argptr); +} + + +BOOL MP_Muted(UNIMOD *mf, int chan) +{ + if(mf==NULL) return 1; + return (channumchn) ? mf->control[chan].muted : 1; +} + + +BOOL Player_Muted(int chan) +{ + if(pf==NULL) return 1; + return (channumchn) ? pf->control[chan].muted : 1; +} + + +int MP_GetChannelVoice(UNIMOD *mf, int chan) +{ + if(mf==NULL) return 0; + return mf->control[chan].slavechn; +} + + +int Player_GetChannelVoice(int chan) +{ + if(pf==NULL) return 0; + return pf->control[chan].slavechn; +} + + +void Player_TogglePause(void) +{ + if(pf==NULL) return; + if(pf->forbid == 1) + pf->forbid = 0; + else + pf->forbid = 1; +} + + +/* --> The following procedures were taken from UNITRK because they */ +/* -> are ProTracker format specific. */ + +void UniInstrument(UBYTE ins) +/* Appends UNI_INSTRUMENT opcode to the unitrk stream. */ +{ + UniWrite(UNI_INSTRUMENT); + UniWrite(ins); +} + +void UniNote(UBYTE note) +/* Appends UNI_NOTE opcode to the unitrk stream. */ +{ + UniWrite(UNI_NOTE); + UniWrite(note); +} + +void UniPTEffect(UBYTE eff, UBYTE dat) +/* Appends UNI_PTEFFECTX opcode to the unitrk stream. */ +{ + if(eff!=0 || dat!=0) /* don't write empty effect */ + { UniWrite(UNI_PTEFFECT0+eff); + UniWrite(dat); + } +} + +void UniVolEffect(UWORD eff, UBYTE dat) +/* Appends UNI_VOLEFFECT + effect/dat to unistream. */ +{ + if(eff!=0 || dat!=0) /* don't write empty effect */ + { UniWrite(UNI_VOLEFFECTS); + UniWrite(eff); UniWrite(dat); + } +} + diff --git a/mikmod/munitrk.c b/mikmod/munitrk.c new file mode 100644 index 0000000..a2fba72 --- /dev/null +++ b/mikmod/munitrk.c @@ -0,0 +1,307 @@ +/* + +Name: +MUNITRK.C + +Description: +All routines dealing with the manipulation of UNITRK(tm) streams + +Portability: +All systems - all compilers + +*/ + +#include +#include "mikmod.h" + +#define BUFPAGE 128 /* smallest unibuffer size */ +#define TRESHOLD 16 + +UWORD unioperands[256] = +{ 0, /* not used */ + 1, /* UNI_NOTE */ + 1, /* UNI_INSTRUMENT */ + 1, /* UNI_PTEFFECT0 */ + 1, /* UNI_PTEFFECT1 */ + 1, /* UNI_PTEFFECT2 */ + 1, /* UNI_PTEFFECT3 */ + 1, /* UNI_PTEFFECT4 */ + 1, /* UNI_PTEFFECT5 */ + 1, /* UNI_PTEFFECT6 */ + 1, /* UNI_PTEFFECT7 */ + 1, /* UNI_PTEFFECT8 */ + 1, /* UNI_PTEFFECT9 */ + 1, /* UNI_PTEFFECTA */ + 1, /* UNI_PTEFFECTB */ + 1, /* UNI_PTEFFECTC */ + 1, /* UNI_PTEFFECTD */ + 1, /* UNI_PTEFFECTE */ + 1, /* UNI_PTEFFECTF */ + 1, /* UNI_S3MEFFECTA */ + 1, /* UNI_S3MEFFECTD */ + 1, /* UNI_S3MEFFECTE */ + 1, /* UNI_S3MEFFECTF */ + 1, /* UNI_S3MEFFECTI */ + 1, /* UNI_S3MEFFECTQ */ + 1, /* UNI_S3MEFFECTR */ + 1, /* UNI_S3MEFFECTT */ + 1, /* UNI_S3MEFFECTU */ + 0, /* UNI_KEYOFF */ + 1, /* UNI_KEYFADE */ + 2, /* UNI_VOLEFFECTS */ + 1, /* UNI_XMEFFECT4 */ + 1, /* UNI_XMEFFECTA */ + 1, /* UNI_XMEFFECTE1 */ + 1, /* UNI_XMEFFECTE2 */ + 1, /* UNI_XMEFFECTEA */ + 1, /* UNI_XMEFFECTEB */ + 1, /* UNI_XMEFFECTG */ + 1, /* UNI_XMEFFECTH */ + 1, /* UNI_XMEFFECTL */ + 1, /* UNI_XMEFFECTP */ + 1, /* UNI_XMEFFECTX1 */ + 1, /* UNI_XMEFFECTX2 */ + 1, /* UNI_ITEFFECTG */ + 1, /* UNI_ITEFFECTH */ + 1, /* UNI_ITEFFECTI */ + 1, /* UNI_ITEFFECTM */ + 1, /* UNI_ITEFFECTN */ + 1, /* UNI_ITEFFECTP */ + 1, /* UNI_ITEFFECTU */ + 1, /* UNI_ITEFFECTW */ + 1, /* UNI_ITEFFECTY */ + 1 /* UNI_ITEFFECTS0 */ +}; + + +/* unibuffer is increased by BUFPAGE */ +/* bytes when unipc reaches unimax-TRESHOLD */ + + +/* + Ok.. I'll try to explain the new internal module format.. so here it goes: + + + The UNITRK(tm) Format: + ====================== + + A UNITRK stream is an array of bytes representing a single track + of a pattern. It's made up of 'repeat/length' bytes, opcodes and + operands (sort of a assembly language): + + rrrlllll + [REP/LEN][OPCODE][OPERAND][OPCODE][OPERAND] [REP/LEN][OPCODE][OPERAND].. + ^ ^ ^ + |-------ROWS 0 - 0+REP of a track---------| |-------ROWS xx - xx+REP of a track... + + + The rep/len byte contains the number of bytes in the current row, + _including_ the length byte itself (So the LENGTH byte of row 0 in the + previous example would have a value of 5). This makes it easy to search + through a stream for a particular row. A track is concluded by a 0-value + length byte. + + The upper 3 bits of the rep/len byte contain the number of times -1 this + row is repeated for this track. (so a value of 7 means this row is repeated + 8 times) + + Opcodes can range from 1 to 255 but currently only opcodes 1 to 45 are + being used. Each opcode can have a different number of operands. You can + find the number of operands to a particular opcode by using the opcode + as an index into the 'unioperands' table. + +*/ + + +/*************************************************************************** +>>>>>>>>>>> Next are the routines for reading a UNITRK stream: <<<<<<<<<<<<< +***************************************************************************/ + + +static UBYTE *rowstart; /* startadress of a row */ +static UBYTE *rowend; /* endaddress of a row (exclusive) */ +static UBYTE *rowpc; /* current unimod(tm) programcounter */ + + +void UniSetRow(UBYTE *t) +{ + rowstart = t; + rowpc = rowstart; + rowend = rowstart+(*(rowpc++)&0x1f); +} + + +UBYTE UniGetByte(void) +{ + return (rowpc end of track.. */ + l = (c>>5)+1; /* extract repeat value */ + if(l>row) break; /* reached wanted row? -> return pointer */ + row -= l; /* haven't reached row yet.. update row */ + t += c&0x1f; /* point t to the next row */ + } + + return t; +} + + + +/*************************************************************************** +>>>>>>>>>>> Next are the routines for CREATING UNITRK streams: <<<<<<<<<<<<< +***************************************************************************/ + + +static UBYTE *unibuf; /* pointer to the temporary unitrk buffer */ +static UWORD unimax; /* maximum number of bytes to be written to this buffer */ + +static UWORD unipc; /* index in the buffer where next opcode will be written */ +static UWORD unitt; /* holds index of the rep/len byte of a row */ +static UWORD lastp; /* holds index to the previous row (needed for compressing) */ + + +void UniReset(void) +/* Resets index-pointers to create a new track. */ +{ + unitt = 0; /* reset index to rep/len byte */ + unipc = 1; /* first opcode will be written to index 1 */ + lastp = 0; /* no previous row yet */ + unibuf[0] = 0; /* clear rep/len byte */ +} + + +void UniWrite(UBYTE data) +/* Appends one byte of data to the current row of a track. */ +{ + /* write byte to current position and update */ + + unibuf[unipc++] = data; + + /* Check if we've reached the end of the buffer */ + + if(unipc > (unimax-TRESHOLD)) + { UBYTE *newbuf; + + /* We've reached the end of the buffer, so expand */ + /* the buffer by BUFPAGE bytes */ + + newbuf = (UBYTE *)realloc(unibuf, unimax+BUFPAGE); + + /* Check if realloc succeeded */ + + if(newbuf!=NULL) + { unibuf = newbuf; + unimax+=BUFPAGE; + } else + { /* realloc failed, so decrease unipc so we won't write beyond */ + /* the end of the buffer.. I don't report the out-of-memory */ + /* here; the UniDup() will fail anyway so that's where the */ + /* loader sees that something went wrong */ + + unipc--; + } + } +} + + +BOOL MyCmp(UBYTE *a, UBYTE *b, UWORD l) +{ + UWORD t; + + for(t=0; t>5)+1; /* repeat of previous row */ + l = (unibuf[lastp]&0x1f); /* length of previous row */ + + len = unipc-unitt; /* length of current row */ + + /* Now, check if the previous and the current row are identical.. */ + /* when they are, just increase the repeat field of the previous row */ + + if(n<8 && len==l && MyCmp(&unibuf[lastp+1],&unibuf[unitt+1],len-1)) + { unibuf[lastp]+=0x20; + unipc = unitt+1; + } else + { /* current and previous row aren't equal.. so just update the pointers */ + + unibuf[unitt] = len; + lastp = unitt; + unitt = unipc; + unipc++; + } +} + + +UBYTE *UniDup(void) +/* Terminates the current unitrk stream and returns a pointer */ +/* to a copy of the stream. */ +{ + UBYTE *d; + + unibuf[unitt] = 0; + + if((d=(UBYTE *)_mm_malloc(unipc))==NULL) return NULL; + memcpy(d,unibuf,unipc); + + return d; +} + + +UWORD TrkLen(UBYTE *t) +/* Determines the length (in rows) of a unitrk stream 't' */ +{ + UWORD len = 0; + UBYTE c; + + while(c = *t & 0x1f) + { len += c; + t += c; + } + len++; + + return len; +} + + +BOOL UniInit(void) +{ + unimax = BUFPAGE; + + if(!(unibuf=(UBYTE *)_mm_malloc(unimax))) return 0; + return 1; +} + + +void UniCleanup(void) +{ + if(unibuf!=NULL) free(unibuf); + unibuf = NULL; +} + diff --git a/mikmod/mwav.c b/mikmod/mwav.c new file mode 100644 index 0000000..e720f4e --- /dev/null +++ b/mikmod/mwav.c @@ -0,0 +1,134 @@ +/* + + Name: MWAV.C + + Description: + WAV sample loader + Stereo .WAV files are not yet supported as samples. + + Portability: + All compilers -- All systems (hopefully) + +*/ + +#include +#include "mikmod.h" + + +typedef struct WAV +{ CHAR rID[4]; + ULONG rLen; + CHAR wID[4]; + CHAR fID[4]; + ULONG fLen; + UWORD wFormatTag; + UWORD nChannels; + ULONG nSamplesPerSec; + ULONG nAvgBytesPerSec; + UWORD nBlockAlign; + UWORD nFormatSpecific; + UWORD cbSize; +} WAV; + + +SAMPLE *WAV_LoadFP(VIRTUAL_FILE *fp) +{ + SAMPLE *si; + static WAV wh; + static CHAR dID[4]; + + /* read wav header */ + + _mm_read_string(wh.rID,4,fp); + wh.rLen = _mm_read_I_ULONG(fp); + _mm_read_string(wh.wID,4,fp); + + while(1) + { _mm_read_string(wh.fID,4,fp); + wh.fLen = _mm_read_I_ULONG(fp); + if(memcmp(wh.fID,"fmt ",4) == 0) break; + _mm_fseek(fp,wh.fLen,SEEK_CUR); + } + + if( _mm_feof(fp) || + memcmp(wh.rID,"RIFF",4) || + memcmp(wh.wID,"WAVE",4)) + { + _mm_errno = MMERR_UNKNOWN_WAVE_TYPE; + return NULL; + } + + wh.wFormatTag = _mm_read_I_UWORD(fp); + wh.nChannels = _mm_read_I_UWORD(fp); + wh.nSamplesPerSec = _mm_read_I_ULONG(fp); + wh.nAvgBytesPerSec = _mm_read_I_ULONG(fp); + wh.nBlockAlign = _mm_read_I_UWORD(fp); + wh.nFormatSpecific = _mm_read_I_UWORD(fp); + + /* check it */ + + if(_mm_feof(fp)) + { _mm_errno = MMERR_UNKNOWN_WAVE_TYPE; + return NULL; + } + + /* skip other crap */ + + _mm_fseek(fp,wh.fLen-16,SEEK_CUR); + _mm_read_string(dID,4,fp); + + if(memcmp(dID,"data",4)) + { _mm_errno = MMERR_UNKNOWN_WAVE_TYPE; + return NULL; + } + + if(wh.nChannels > 1) + { _mm_errno = MMERR_UNKNOWN_WAVE_TYPE; + return NULL; + } + +/* printf("wFormatTag: %x\n",wh.wFormatTag); */ +/* printf("blockalign: %x\n",wh.nBlockAlign); */ +/* prinff("nFormatSpc: %x\n",wh.nFormatSpecific); */ + + if((si=(SAMPLE *)_mm_calloc(1,sizeof(SAMPLE)))==NULL) return NULL; + + si->speed = wh.nSamplesPerSec; + si->volume = 64; + si->length = _mm_read_I_ULONG(fp); + + if(wh.nBlockAlign == 2) + { si->flags = SF_16BITS | SF_SIGNED; + si->length >>= 1; + } + + SL_RegisterSample(si,MD_SNDFX,fp); + + return si; +} + + +SAMPLE *WAV_LoadFN(CHAR *filename) +{ + VIRTUAL_FILE *fp; + SAMPLE *si; + + if(!(md_mode & DMODE_SOFT_SNDFX)) return NULL; + if((fp=_mm_fopen(filename,"rb"))==NULL) return NULL; + + si = WAV_LoadFP(fp); + SL_LoadSamples(); + _mm_fclose(fp); + + return si; +} + + +void WAV_Free(SAMPLE *si) +{ + if(si!=NULL) + { MD_SampleUnLoad(si->handle); + free(si); + } +} + diff --git a/mikmod/npertab.c b/mikmod/npertab.c new file mode 100644 index 0000000..d888ffa --- /dev/null +++ b/mikmod/npertab.c @@ -0,0 +1,14 @@ +/* MOD format period table. Used by both the MOD and */ +/* M15 (15-inst mod) Loaders. */ + +#include "tdefs.h" + +UWORD npertab[60] = +{ /* -> Tuning 0 */ + 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,906, + 856,808,762,720,678,640,604,570,538,508,480,453, + 428,404,381,360,339,320,302,285,269,254,240,226, + 214,202,190,180,170,160,151,143,135,127,120,113, + 107,101,95,90,85,80,75,71,67,63,60,56 +}; + diff --git a/mikmod/ptform.h b/mikmod/ptform.h new file mode 100644 index 0000000..b2b0c51 --- /dev/null +++ b/mikmod/ptform.h @@ -0,0 +1,591 @@ +/* + --> The Protracker Enums + -> For MikMod 3.0 +*/ + +#ifndef _PTFORM_H_ +#define _PTFORM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + +extern UWORD mytab[12],logtab[104]; +extern UBYTE VibratoTable[32],avibtab[128]; +extern SBYTE PanbrelloTable[256]; +extern ULONG lintab[768]; + + +/************************************************************************** +****** Unitrack stuff: **************************************************** +**************************************************************************/ + +/* The UniTrack stuff is generally for internal use only, but would be */ +/* required in making a tracker or a module player tha scrolls pattern */ +/* data. */ + +/* prototypes: */ + +extern void UniSetRow(UBYTE *t); +extern UBYTE UniGetByte(void); +extern UBYTE *UniFindRow(UBYTE *t,UWORD row); +extern void UniReset(void); +extern void UniWrite(UBYTE data); +extern void UniNewline(void); +extern UBYTE *UniDup(void); +extern void UniSkipOpcode(UBYTE op); +extern BOOL UniInit(void); +extern void UniCleanup(void); +extern UWORD TrkLen(UBYTE *t); +extern BOOL MyCmp(UBYTE *a, UBYTE *b, UWORD l); +extern void UniInstrument(UBYTE ins); +extern void UniNote(UBYTE note); +extern void UniPTEffect(UBYTE eff, UBYTE dat); +extern void UniVolEffect(UWORD eff, UBYTE dat); + + +/* Enumaerated UniMod Commands */ + +enum +{ UNI_NOTE = 1, + UNI_INSTRUMENT, + UNI_PTEFFECT0, + UNI_PTEFFECT1, + UNI_PTEFFECT2, + UNI_PTEFFECT3, + UNI_PTEFFECT4, + UNI_PTEFFECT5, + UNI_PTEFFECT6, + UNI_PTEFFECT7, + UNI_PTEFFECT8, + UNI_PTEFFECT9, + UNI_PTEFFECTA, + UNI_PTEFFECTB, + UNI_PTEFFECTC, + UNI_PTEFFECTD, + UNI_PTEFFECTE, + UNI_PTEFFECTF, + UNI_S3MEFFECTA, + UNI_S3MEFFECTD, + UNI_S3MEFFECTE, + UNI_S3MEFFECTF, + UNI_S3MEFFECTI, + UNI_S3MEFFECTQ, + UNI_S3MEFFECTR, + UNI_S3MEFFECTT, + UNI_S3MEFFECTU, + UNI_KEYOFF, + UNI_KEYFADE, + UNI_VOLEFFECTS, + UNI_XMEFFECT4, + UNI_XMEFFECTA, + UNI_XMEFFECTE1, + UNI_XMEFFECTE2, + UNI_XMEFFECTEA, + UNI_XMEFFECTEB, + UNI_XMEFFECTG, + UNI_XMEFFECTH, + UNI_XMEFFECTL, + UNI_XMEFFECTP, + UNI_XMEFFECTX1, + UNI_XMEFFECTX2, + UNI_ITEFFECTG, /* Porta to Note .. no kick=0; */ + UNI_ITEFFECTH, /* IT specific Vibrato */ + UNI_ITEFFECTI, /* IT tremor (xy not incremeneted) */ + UNI_ITEFFECTM, /* Set Channel Volume */ + UNI_ITEFFECTN, /* Slide / Fineslide Channel Volume */ + UNI_ITEFFECTP, /* Slide / Fineslide Channel Panning */ + UNI_ITEFFECTU, /* IT fine vibrato */ + UNI_ITEFFECTW, /* Slide / Fineslide Global volume */ + UNI_ITEFFECTY, /* The Satanic Panbrello */ + UNI_ITEFFECTS0, + UNI_LAST +}; + + +/* IT / S3M Extended SS effects: */ + +enum +{ SS_GLISSANDO = 1, + SS_FINETUNE, + SS_VIBWAVE, + SS_TREMWAVE, + SS_PANWAVE, + SS_FRAMEDELAY, + SS_S7EFFECTS, + SS_PANNING, + SS_SURROUND, + SS_HIOFFSET, + SS_PATLOOP, + SS_NOTECUT, + SS_NOTEDELAY, + SS_PATDELAY +}; + + +/* IT Volume column effects */ + +enum +{ VOL_VOLUME = 1, + VOL_PANNING, + VOL_VOLSLIDE, + VOL_PITCHSLIDEDN, + VOL_PITCHSLIDEUP, + VOL_PORTAMENTO, + VOL_VIBRATO +}; + + +/************************************************************************** +****** Instrument stuff: ************************************************** +**************************************************************************/ + + +/* Instrument format flags */ +#define IF_OWNPAN 1 +#define IF_PITCHPAN 2 + +/* Envelope flags: */ + +#define EF_ON 1 +#define EF_SUSTAIN 2 +#define EF_LOOP 4 +#define EF_VOLENV 8 + +/* New Note Action Flags */ + +#define NNA_CUT 0 +#define NNA_CONTINUE 1 +#define NNA_OFF 2 +#define NNA_FADE 3 + +#define DCT_OFF 0 +#define DCT_NOTE 1 +#define DCT_SAMPLE 2 +#define DCT_INST 3 + +#define DCA_CUT 0 +#define DCA_OFF 1 +#define DCA_FADE 2 + +#define KEY_KICK 0 +#define KEY_OFF 1 +#define KEY_FADE 2 +#define KEY_KILL 3 + +#define AV_IT 1 /* IT vs. XM vibrato info */ + + +typedef struct ENVPT +{ SWORD pos; + SWORD val; +} ENVPT; + + +typedef struct INSTRUMENT +{ + UBYTE flags; + + UBYTE samplenumber[120]; + UBYTE samplenote[120]; + + UBYTE nnatype; + UBYTE dca; /* duplicate check action */ + UBYTE dct; /* duplicate check type */ + UBYTE globvol; + UWORD panning; /* instrument-based panning var */ + + UBYTE pitpansep; /* pitch pan separation (0 to 255) */ + UBYTE pitpancenter; /* pitch pan center (0 to 119) */ + UBYTE rvolvar; /* random volume varations (0 - 100%) */ + UBYTE rpanvar; /* random panning varations (0 - 100%) */ + + UWORD volfade; + + UBYTE volflg; /* bit 0: on 1: sustain 2: loop */ + UBYTE volpts; + UBYTE volsusbeg; + UBYTE volsusend; + UBYTE volbeg; + UBYTE volend; + ENVPT volenv[32]; + + UBYTE panflg; /* bit 0: on 1: sustain 2: loop */ + UBYTE panpts; + UBYTE pansusbeg; + UBYTE pansusend; + UBYTE panbeg; + UBYTE panend; + ENVPT panenv[32]; + + UBYTE pitflg; /* bit 0: on 1: sustain 2: loop */ + UBYTE pitpts; + UBYTE pitsusbeg; + UBYTE pitsusend; + UBYTE pitbeg; + UBYTE pitend; + ENVPT pitenv[32]; + +/* UBYTE vibtype; */ +/* UBYTE vibsweep; */ +/* UBYTE vibdepth; */ +/* UBYTE vibrate; */ + + CHAR *insname; + +} INSTRUMENT; + + + +/************************************************************************** +****** Player stuff: ****************************************************** +**************************************************************************/ + +typedef struct ENVPR +{ UBYTE flg; /* envelope flag */ + UBYTE pts; /* number of envelope points */ + UBYTE susbeg; /* envelope sustain index begin */ + UBYTE susend; /* envelope sustain index end */ + UBYTE beg; /* envelope loop begin */ + UBYTE end; /* envelope loop end */ + SWORD p; /* current envelope counter */ + UWORD a; /* envelope index a */ + UWORD b; /* envelope index b */ + ENVPT *env; /* envelope points */ +} ENVPR; + + + +/* Struct MP_VOICE - Used by NNA only player (audio control. AUDTMP is */ +/* used for full effects control). */ +typedef struct MP_VOICE +{ INSTRUMENT *i; + SAMPLE *s; + UBYTE sample; /* which instrument number */ + + SWORD volume; /* output volume (vol + sampcol + instvol) */ + UWORD panning; /* panning position */ + SBYTE chanvol; /* channel's "global" volume */ + UWORD fadevol; /* fading volume rate */ + UWORD period; /* period to play the sample at */ + + UBYTE volflg; /* volume envelope settings */ + UBYTE panflg; /* panning envelope settings */ + UBYTE pitflg; /* pitch envelope settings */ + + UBYTE keyoff; /* if true = fade out and stuff */ + UBYTE kick; /* if true = sample has to be restarted */ + UBYTE note; /* the audible note (as heard, direct rep of period) */ + UBYTE nna; /* New note action type + master/slave flags */ + SWORD handle; /* which sample-handle */ + SLONG start; /* The start byte index in the sample */ + + + /* ---------------------------------- */ + /* Below here is info NOT in MP_CONTROL!! */ + /* ---------------------------------- */ + + ENVPR venv; + ENVPR penv; + ENVPR cenv; + + UWORD avibpos; /* autovibrato pos */ + UWORD aswppos; /* autovibrato sweep pos */ + + ULONG totalvol; /* total volume of channel (before global mixings) */ + + BOOL mflag; + SWORD masterchn; + struct MP_CONTROL *master;/* index of "master" effects channel */ +} MP_VOICE; + + +typedef struct MP_CONTROL +{ INSTRUMENT *i; + SAMPLE *s; + UBYTE sample; /* which sample number */ + UBYTE note; /* the audible note (as heard, direct rep of period) */ + SWORD outvolume; /* output volume (vol + sampcol + instvol) */ + SBYTE chanvol; /* channel's "global" volume */ + UWORD fadevol; /* fading volume rate */ + UWORD panning; /* panning position */ + UBYTE kick; /* if true = sample has to be restarted */ + UBYTE muted; /* if set, channel not played */ + UWORD period; /* period to play the sample at */ + UBYTE nna; /* New note action type + master/slave flags */ + + UBYTE volflg; /* volume envelope settings */ + UBYTE panflg; /* panning envelope settings */ + UBYTE pitflg; /* pitch envelope settings */ + + UBYTE keyoff; /* if true = fade out and stuff */ + SWORD handle; /* which sample-handle */ + UBYTE notedelay; /* (used for note delay) */ + SLONG start; /* The starting byte index in the sample */ + + struct MP_VOICE *slave;/* Audio Slave of current effects control channel */ + UBYTE slavechn; /* Audio Slave of current effects control channel */ + UBYTE anote; /* the note that indexes the audible (note seen in tracker) */ + SWORD ownper; + SWORD ownvol; + UBYTE dca; /* duplicate check action */ + UBYTE dct; /* duplicate check type */ + UBYTE *row; /* row currently playing on this channel */ + SBYTE retrig; /* retrig value (0 means don't retrig) */ + ULONG speed; /* what finetune to use */ + SWORD volume; /* amiga volume (0 t/m 64) to play the sample at */ + + SBYTE tmpvolume; /* tmp volume */ + UWORD tmpperiod; /* tmp period */ + UWORD wantedperiod; /* period to slide to (with effect 3 or 5) */ + UBYTE pansspd; /* panslide speed */ + UWORD slidespeed; /* */ + UWORD portspeed; /* noteslide speed (toneportamento) */ + + UBYTE s3mtremor; /* s3m tremor (effect I) counter */ + UBYTE s3mtronof; /* s3m tremor ontime/offtime */ + UBYTE s3mvolslide; /* last used volslide */ + UBYTE s3mrtgspeed; /* last used retrig speed */ + UBYTE s3mrtgslide; /* last used retrig slide */ + + UBYTE glissando; /* glissando (0 means off) */ + UBYTE wavecontrol; /* */ + + SBYTE vibpos; /* current vibrato position */ + UBYTE vibspd; /* "" speed */ + UBYTE vibdepth; /* "" depth */ + + SBYTE trmpos; /* current tremolo position */ + UBYTE trmspd; /* "" speed */ + UBYTE trmdepth; /* "" depth */ + + UBYTE fslideupspd; + UBYTE fslidednspd; + UBYTE fportupspd; /* fx E1 (extra fine portamento up) data */ + UBYTE fportdnspd; /* fx E2 (extra fine portamento dn) data */ + UBYTE ffportupspd; /* fx X1 (extra fine portamento up) data */ + UBYTE ffportdnspd; /* fx X2 (extra fine portamento dn) data */ + + ULONG hioffset; /* last used high order of sample offset */ + UWORD soffset; /* last used low order of sample-offset (effect 9) */ + + UBYTE sseffect; /* last used Sxx effect */ + UBYTE ssdata; /* last used Sxx data info */ + UBYTE chanvolslide; /* last used channel volume slide */ + + UBYTE panbwave; /* current panbrello waveform */ + UBYTE panbpos; /* current panbrello position */ + SBYTE panbspd; /* "" speed */ + UBYTE panbdepth; /* "" depth */ + + UWORD newsamp; /* set to 1 upon a sample / inst change */ + UBYTE voleffect; /* Volume Column Effect Memory as used by Impulse Tracker */ + UBYTE voldata; /* Volume Column Data Memory */ +} MP_CONTROL; + + +/****************************************************** +******** MikMod UniMod type: ************************** +*******************************************************/ + +/* UniMod flags */ +#define UF_XMPERIODS 1 /* XM periods / finetuning */ +#define UF_LINEAR 2 /* LINEAR periods (UF_XMPERIODS must be set as well) */ +#define UF_INST 4 /* Instruments are used */ +#define UF_NNA 8 /* New Note Actions used (set numvoices rather than numchn) */ + + +typedef struct UNIMOD +{ + /* This section of elements are all file-storage related. */ + /* all of this information can be found in the UNIMOD disk format. */ + /* For further details about there variables, see the MikMod Docs. */ + + UWORD flags; /* See UniMod Flags above */ + UBYTE numchn; /* number of module channels */ + UBYTE numvoices; /* max # voices used for full NNA playback */ + UWORD numpos; /* number of positions in this song */ + UWORD numpat; /* number of patterns in this song */ + UWORD numtrk; /* number of tracks */ + UWORD numins; /* number of instruments */ + UWORD numsmp; /* number of samples */ + UWORD reppos; /* restart position */ + UBYTE initspeed; /* initial song speed */ + UBYTE inittempo; /* initial song tempo */ + UBYTE initvolume; /* initial global volume (0 - 128) */ + UWORD panning[64]; /* 64 panning positions */ + UBYTE chanvol[64]; /* 64 channel positions */ + CHAR *songname; /* name of the song */ + CHAR *composer; /* name of the composer */ + CHAR *comment; /* module comments */ + UBYTE **tracks; /* array of numtrk pointers to tracks */ + UWORD *patterns; /* array of Patterns [pointers to tracks for each channel]. */ + UWORD *pattrows; /* array of number of rows for each pattern */ + UWORD *positions; /* all positions */ + INSTRUMENT *instruments; /* all instruments */ + SAMPLE *samples; /* all samples */ + + /* following are the player-instance variables. They are in no way file */ + /* storage related - they are for internal replay use only. */ + + /* All following variables can be modified at any time. */ + + CHAR *modtype; /* string type of module loaded */ + UBYTE bpm; /* current beats-per-minute speed */ + UWORD sngspd; /* current song speed */ + SWORD volume; /* song volume (0-128) (or user volume) */ + BOOL extspd; /* extended speed flag (default enabled) */ + BOOL panflag; /* panning flag (default enabled) */ + BOOL loop; /* loop module ? (default disabled) */ + BOOL forbid; /* if true, no player update! */ + + /* The following variables are considered useful for reading, and should */ + /* should not be directly modified by the end user. */ + + MP_CONTROL *control; /* Effects Channel information (pf->numchn alloc'ed) */ + MP_VOICE *voice; /* Audio Voice information (md_numchn alloc'ed) */ + UWORD numrow; /* number of rows on current pattern */ + UWORD vbtick; /* tick counter (counts from 0 to sngspd) */ + UWORD patpos; /* current row number */ + SWORD sngpos; /* current song position. This should not */ + /* be modified directly. Use MikMod_NextPosition, */ + /* MikMod_PrevPosition, and MikMod_SetPosition. */ + + /* The following variables should not be modified, and have information */ + /* that is pretty useless outside the internal player, so just ignore :) */ + + UBYTE globalslide; /* global volume slide rate */ + UWORD pat_reppos; /* patternloop position */ + UWORD pat_repcnt; /* times to loop */ + UWORD patbrk; /* position where to start a new pattern */ + UBYTE patdly; /* patterndelay counter (command memory) */ + UBYTE patdly2; /* patterndelay counter (real one) */ + SWORD posjmp; /* flag to indicate a position jump is needed... */ + /* changed since 1.00: now also indicates the */ + /* direction the position has to jump to: */ + /* 0: Don't do anything */ + /* 1: Jump back 1 position */ + /* 2: Restart on current position */ + /* 3: Jump forward 1 position */ + +} UNIMOD; + + +/*************************************************** +****** Loader stuff: ******************************* +****************************************************/ + +/* loader structure: */ + +typedef struct MLOADER +{ struct MLOADER *next; + CHAR *type; + CHAR *version; + BOOL (*Init)(void); + BOOL (*Test)(void); + BOOL (*Load)(void); + void (*Cleanup)(void); + CHAR *(*LoadTitle)(void); +} MLOADER; + +/* public loader variables: */ + +extern VIRTUAL_FILE *modfp; +extern UWORD finetune[16]; +extern UNIMOD of; /* static unimod loading space */ +extern UWORD npertab[60]; /* used by the original MOD loaders */ + +/* main loader prototypes: */ + +void ML_InfoLoader(void); +void ML_RegisterLoader(MLOADER *ldr); +UNIMOD *MikMod_LoadSongFP(VIRTUAL_FILE *fp, int maxchan); +UNIMOD *MikMod_LoadSong(CHAR *filename, int maxchan); +void MikMod_FreeSong(UNIMOD *mf); + + +/* other loader prototypes: (used by the loader modules) */ + +BOOL InitTracks(void); +void AddTrack(UBYTE *tr); +BOOL ReadComment(UWORD len); +BOOL AllocPositions(int total); +BOOL AllocPatterns(void); +BOOL AllocTracks(void); +BOOL AllocInstruments(void); +BOOL AllocSamples(void); +CHAR *DupStr(CHAR *s, UWORD len); + + +/* Declare external loaders: */ + +extern MLOADER load_uni; /* Internal UniMod Loader (Current version of UniMod only) */ +extern MLOADER load_mod; /* Standard 31-instrument Module loader (Protracker, StarTracker, FastTracker, etc) */ +extern MLOADER load_m15; /* 15-instrument (SoundTracker and Ultimate SoundTracker) */ +extern MLOADER load_mtm; /* Multi-Tracker Module (by Renaissance) */ +extern MLOADER load_s3m; /* ScreamTracker 3 (by Future Crew) */ +extern MLOADER load_stm; /* ScreamTracker 2 (by Future Crew) */ +extern MLOADER load_ult; /* UltraTracker */ +extern MLOADER load_xm; /* FastTracker 2 (by Trition) */ +extern MLOADER load_it; /* Impulse Tracker (by Jeffrey Lim) */ +extern MLOADER load_669; /* 669 and Extended-669 (by Tran / Renaissance) */ +extern MLOADER load_dsm; /* DSIK internal module format */ +extern MLOADER load_med; /* MMD0 and MMD1 Amiga MED modules (by OctaMED) */ +extern MLOADER load_far; /* Farandole Composer Module */ + +/* used to convert c4spd to linear XM periods (IT loader). */ +extern UWORD getlinearperiod(UBYTE note, ULONG fine); +extern ULONG getfrequency(UBYTE flags, ULONG period); + + +#define MP_HandleTick Player_HandleTick +#define ML_LoadFN(x,y) MikMod_LoadSong(x,y) +#define ML_LoadFP(x,y) MikMod_LoadSongFP(x,y) +#define MP_PlayStart(x) Player_Start(x) +#define MP_PlayStop Player_Stop + + +/* MikMod Player Prototypes: */ +/* =========================================================== */ +/* This batch of prototypes affects the currently ACTIVE module */ +/* set with MikMod_PlayStart) */ + +extern void Player_Start(UNIMOD *mf); +extern BOOL Player_Active(void); +extern void Player_Stop(void); +extern void Player_TogglePause(void); +extern void Player_NextPosition(void); +extern void Player_PrevPosition(void); +extern void Player_SetPosition(UWORD pos); +extern void Player_Mute(SLONG arg1, ...); +extern void Player_UnMute(SLONG arg1, ...); +extern void Player_ToggleMute(SLONG arg1, ...); +extern BOOL Player_Muted(int chan); +extern void Player_HandleTick(void); +extern void Player_SetVolume(int volume); +extern UNIMOD *Player_GetUnimod(void); + +extern BOOL Player_Init(UNIMOD *mf); /* internal use only [by loader] */ +extern void Player_Exit(UNIMOD *mf); /* internal use only [by loader] */ + +/* This batch of prototypes adheres closely to the old MikMod 2.10 */ +/* naming, and affects ANY specified module (need not be active, */ +/* only loaded and initialized) */ + +extern BOOL MP_Playing(UNIMOD *mf); +extern void MP_TogglePause(UNIMOD *mf); +extern void MP_NextPosition(UNIMOD *mf); +extern void MP_PrevPosition(UNIMOD *mf); +extern void MP_SetPosition(UNIMOD *mf, UWORD pos); +extern void MP_Mute(UNIMOD *mf, SLONG arg1, ...); +extern void MP_UnMute(UNIMOD *mf, SLONG arg1, ...); +extern void MP_ToggleMute(UNIMOD *mf, SLONG arg1, ...); +extern BOOL MP_Muted(UNIMOD *mf, int chan); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/mikmod/resample.S b/mikmod/resample.S new file mode 100644 index 0000000..1b594e0 --- /dev/null +++ b/mikmod/resample.S @@ -0,0 +1,316 @@ +/* GCC port of mixing code by Barubary (barubary@dal.net) + This should work on both Linux and DJGPP... I have confirmed that + self-modifying code works just fine in Linux without causing signals. + This may change in the future, so I recommend that the Linux MikMod + developers look out for new kernel releases. The critical thing is that + CS.base = DS.base in Linux, which makes DS an alias for CS, and that the + code pages remain writable. */ + +.data /* self-modifying code... keep in data segment */ + +#define _AsmStereoNormal AsmStereoNormal +#define _AsmStereoSurround AsmStereoSurround +#define _AsmMonoNormal AsmMonoNormal +#define _AsmMix32To16Surround AsmMix32To16Surround +#define _AsmMix32To8Surround AsmMix32To8Surround +#define _bitshift bitshift +#define _lvoltab lvoltab +#define _rvoltab rvoltab + + .globl _AsmStereoNormal + .globl _AsmStereoSurround + .globl _AsmMonoNormal + .globl _AsmMix32To16Surround + .globl _AsmMix32To8Surround + + +#define STUBSTART \ + pushl %eax; \ + pushl %ebx; \ + pushl %ecx; \ + pushl %edx; \ + pushl %esi; \ + pushl %edi; \ + pushl %ebp + +#define STUBEND \ + popl %ebp; \ + popl %edi; \ + popl %esi; \ + popl %edx; \ + popl %ecx; \ + popl %ebx; \ + popl %eax + +#define SS2F(index,lab1,lab2,lab3,lab4) \ + movb (%edx),%al; \ + .byte 0x081,0x0c3; \ + lab1: .int 0; \ + .byte 0x081,0x0d2; \ + lab2: .int 0; \ + movl index*8(%edi),%esi; \ + .byte 0x08b,0x0c,0x085; \ + lab3: .int 0; \ + movl index*8+4(%edi),%ebp; \ + addl %ecx,%esi; \ + .byte 0x08b,0x0c,0x085; \ + lab4: .int 0; \ + movl %esi,index*8(%edi); \ + addl %ecx,%ebp + +#define SS2M(index,lab1,lab2,lab3,lab4) \ + movb (%edx),%al; \ + movl %ebp,index*8-4(%edi); \ + .byte 0x081,0x0c3; \ + lab1: .int 0; \ + .byte 0x081,0x0d2; \ + lab2: .int 0; \ + movl index*8(%edi),%esi; \ + .byte 0x08b,0x0c,0x085; \ + lab3: .int 0; \ + movl index*8+4(%edi),%ebp; \ + addl %ecx,%esi; \ + .byte 0x08b,0x0c,0x085; \ + lab4: .int 0; \ + movl %esi,index*8(%edi); \ + addl %ecx,%ebp + +#define SS3F(index,lab1,lab2,lab3) \ + movb (%edx),%al; \ + .byte 0x081,0x0c3; \ + lab1: .int 0; \ + .byte 0x081,0x0d2; \ + lab2: .int 0; \ + movl index*8(%edi),%esi; \ + .byte 0x08b,0x0c,0x085; \ + lab3: .int 0; \ + movl index*8+4(%edi),%ebp; \ + addl %ecx,%esi; \ + subl %ecx,%ebp; \ + movl %esi,index*8(%edi); \ + +#define SS3M(index,lab1,lab2,lab3) \ + movb (%edx),%al; \ + movl %ebp,index*8-4(%edi); \ + .byte 0x081,0x0c3; \ + lab1: .int 0; \ + .byte 0x081,0x0d2; \ + lab2: .int 0; \ + movl index*8(%edi),%esi; \ + .byte 0x08b,0x0c,0x085; \ + lab3: .int 0; \ + movl index*8+4(%edi),%ebp; \ + addl %ecx,%esi; \ + subl %ecx,%ebp; \ + movl %esi,index*8(%edi); \ + +#define SS2L(index) \ + movl %ebp,index*8-4(%edi) + +#define SM2F(index,lab1,lab2,lab3) \ + movb (%edx),%al; \ + .byte 0x081,0x0c3; \ + lab1: .int 0; \ + .byte 0x081,0x0d2; \ + lab2: .int 0; \ + movl index*4(%edi),%esi; \ + .byte 0x08b,0x0c,0x085; \ + lab3: .int 0 + +#define SM2M(index,lab1,lab2,lab3) \ + movb (%edx),%al; \ + addl %ecx,%esi; \ + .byte 0x081,0x0c3; \ + lab1: .int 0; \ + movl %esi,index*4-4(%edi); \ + .byte 0x081,0x0d2; \ + lab2: .int 0; \ + movl index*4(%edi),%esi; \ + .byte 0x08b,0x0c,0x085; \ + lab3: .int 0 + +#define SM2L(index) \ + addl %ecx,%esi; \ + movl %esi,index*4-4(%edi) + +_AsmStereoNormal: + STUBSTART + movl 32(%esp),%esi /* get src */ + movl 36(%esp),%edi /* get dst */ + movl 40(%esp),%ebx /* get index */ + movl 44(%esp),%ecx /* get increment */ + movl 48(%esp),%ebp /* get todo */ + movl %ecx,%eax + movl %ebx,%edx + sarl $31,%eax + sarl $31,%edx + shldl $21,%ecx,%eax /* convert to 32:32 */ + shll $21,%ecx + shldl $21,%ebx,%edx /* convert to 32:32 */ + shll $21,%ebx + addl %esi,%edx + movl %eax,shi1 + movl %eax,shi2 + movl %eax,shi3 + movl %eax,shi4 + movl %eax,shi5 + movl _lvoltab,%eax + movl %ecx,slo1 + movl %ecx,slo2 + movl %ecx,slo3 + movl %ecx,slo4 + movl %ecx,slo5 + movl %eax,sltab1 + movl %eax,sltab2 + movl %eax,sltab3 + movl %eax,sltab4 + movl %eax,sltab5 + movl _rvoltab,%eax + pushl %ebp + movl %eax,srtab1 + movl %eax,srtab2 + movl %eax,srtab3 + movl %eax,srtab4 + movl %eax,srtab5 + xorl %eax,%eax + jmp s1 /* flush code cache */ +s1: + shrl $2,%ebp + jz sskip16 + pushl %ebp +sagain16: + SS2F(0,slo1,shi1,sltab1,srtab1) + SS2M(1,slo2,shi2,sltab2,srtab2) + SS2M(2,slo3,shi3,sltab3,srtab3) + SS2M(3,slo4,shi4,sltab4,srtab4) + SS2L(4) + addl $32,%edi + decl (%esp) + jnz sagain16 + popl %ebp +sskip16: + popl %ebp + andl $3,%ebp + jz sskip1 + pushl %ebp +sagain1: + SS2F(0,slo5,shi5,sltab5,srtab5) + SS2L(1) + addl $8,%edi + decl (%esp) + jnz sagain1 + popl %ebp +sskip1: + STUBEND + ret + + +_AsmStereoSurround: + STUBSTART + movl 32(%esp),%esi /* get src */ + movl 36(%esp),%edi /* get dst */ + movl 40(%esp),%ebx /* get index */ + movl 44(%esp),%ecx /* get increment */ + movl 48(%esp),%ebp /* get todo */ + movl %ecx,%eax + movl %ebx,%edx + sarl $31,%eax + sarl $31,%edx + shldl $21,%ecx,%eax /* convert to 32:32 */ + shll $21,%ecx + shldl $21,%ebx,%edx /* convert to 32:32 */ + shll $21,%ebx + addl %esi,%edx + movl %eax,s2hi1 + movl %eax,s2hi2 + movl %eax,s2hi3 + movl %eax,s2hi4 + movl %eax,s2hi5 + movl _lvoltab,%eax + movl %ecx,s2lo1 + movl %ecx,s2lo2 + movl %ecx,s2lo3 + movl %ecx,s2lo4 + movl %ecx,s2lo5 + movl %eax,s2ltab1 + movl %eax,s2ltab2 + movl %eax,s2ltab3 + movl %eax,s2ltab4 + movl %eax,s2ltab5 + pushl %ebp + xorl %eax,%eax + jmp s3 /* flush code cache */ +s3: + shrl $2,%ebp + jz s2skip16 + pushl %ebp +s2again16: + SS3F(0,s2lo1,s2hi1,s2ltab1) + SS3M(1,s2lo2,s2hi2,s2ltab2) + SS3M(2,s2lo3,s2hi3,s2ltab3) + SS3M(3,s2lo4,s2hi4,s2ltab4) + SS2L(4) + addl $32,%edi + decl (%esp) + jnz s2again16 + popl %ebp +s2skip16: + popl %ebp + andl $3,%ebp + jz s2skip1 + pushl %ebp +s2again1: + SS3F(0,s2lo5,s2hi5,s2ltab5) + SS2L(1) + addl $8,%edi + decl (%esp) + jnz s2again1 + popl %ebp +s2skip1: + STUBEND + ret + + +_AsmMonoNormal: + STUBSTART + movl 32(%esp),%esi /* get src */ + movl 36(%esp),%edi /* get dst */ + movl 40(%esp),%ebx /* get index */ + movl 44(%esp),%ecx /* get increment */ + movl 48(%esp),%ebp /* get todo */ + movl %ecx,%eax + movl %ebx,%edx + sarl $31,%eax + sarl $31,%edx + shldl $21,%ecx,%eax /* convert to 32:32 */ + shll $21,%ecx + shldl $21,%ebx,%edx /* convert to 32:32 */ + shll $21,%ebx + addl %esi,%edx + movl %eax,mhi1 + movl %eax,mhi2 + movl %eax,mhi3 + movl %eax,mhi4 + movl %eax,mhi5 + movl _lvoltab,%eax + movl %ecx,mlo1 + movl %ecx,mlo2 + movl %ecx,mlo3 + movl %ecx,mlo4 + movl %ecx,mlo5 + movl %eax,mltab1 + movl %eax,mltab2 + movl %eax,mltab3 + movl %eax,mltab4 + movl %eax,mltab5 + xorl %eax,%eax + + jmp m1 /* flush code cache */ +m1: + pushl %ebp + shrl $2,%ebp + jz mskip16 +magain16: + SM2F(0,mlo1,mhi1,mltab1) + SM2M(1,mlo2,mhi2,mltab2) + diff --git a/mikmod/resample.asm b/mikmod/resample.asm new file mode 100644 index 0000000..93267ff --- /dev/null +++ b/mikmod/resample.asm @@ -0,0 +1,455 @@ +.386p +.model flat +.data ; self-modifying code... keep in data segment + + NAME resample + EXTRN _rvoltab :DWORD + EXTRN _lvoltab :DWORD + EXTRN _bitshift :BYTE + + PUBLIC _AsmStereoNormal + PUBLIC _AsmStereoSurround + PUBLIC _AsmMonoNormal +IFDEF __ASMSTUFF__ + PUBLIC _AsmMix32To16_Normal + PUBLIC _AsmMix32To8_Normal +ENDIF + + +STUBSTART macro + push eax + push ebx + push ecx + push edx + push esi + push edi + push ebp + endm + + +STUBEND macro + pop ebp + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + endm + + +SS2F MACRO index,lab1,lab2,lab3,lab4 ; 486+ + mov al,[edx] + db 081h,0c3h +lab1 dd 0 ; add ebx,lo + db 081h,0d2h +lab2 dd 0 ; adc edx,hi + mov esi,(index*8)[edi] + db 08bh,0ch,085h +lab3 dd 0 ; mov ecx,[eax*4+table1] + mov ebp,(index*8+4)[edi] + add esi,ecx + db 08bh,0ch,085h +lab4 dd 0 ; mov ecx,[eax*4+table2] + mov (index*8)[edi],esi + add ebp,ecx + ENDM + +SS2M MACRO index,lab1,lab2,lab3,lab4 ; 486+ + mov al,[edx] + mov (index*8-4)[edi],ebp + db 081h,0c3h +lab1 dd 0 ; add ebx,lo + db 081h,0d2h +lab2 dd 0 ; adc edx,hi + mov esi,(index*8)[edi] + db 08bh,0ch,085h +lab3 dd 0 ; mov ecx,[eax*4+table1] + mov ebp,(index*8+4)[edi] + add esi,ecx + db 08bh,0ch,085h +lab4 dd 0 ; mov ecx,[eax*4+table2] + mov (index*8)[edi],esi + add ebp,ecx + ENDM + +SS3F MACRO index,lab1,lab2,lab3 ; 486+ + mov al,[edx] + db 081h,0c3h +lab1 dd 0 ; add ebx,lo + db 081h,0d2h +lab2 dd 0 ; adc edx,hi + mov esi,(index*8)[edi] + db 08bh,0ch,085h +lab3 dd 0 ; mov ecx,[eax*4+table1] + mov ebp,(index*8+4)[edi] + add esi,ecx + sub ebp,ecx + mov (index*8)[edi],esi + ENDM + +SS3M MACRO index,lab1,lab2,lab3 ; 486+ + mov al,[edx] + mov (index*8-4)[edi],ebp + db 081h,0c3h +lab1 dd 0 ; add ebx,lo + db 081h,0d2h +lab2 dd 0 ; adc edx,hi + mov esi,(index*8)[edi] + db 08bh,0ch,085h +lab3 dd 0 ; mov ecx,[eax*4+table1] + mov ebp,(index*8+4)[edi] + add esi,ecx + sub ebp,ecx + mov (index*8)[edi],esi + ENDM + +SS2L MACRO index ; 486+ + mov (index*8-4)[edi],ebp + ENDM + +SM2F MACRO index,lab1,lab2,lab3 ; 486+ + mov al,[edx] ; AGI-3 + db 081h,0c3h +lab1 dd 0 ; add ebx,lo + db 081h,0d2h +lab2 dd 0 ; adc edx,hi + mov esi,(index*4)[edi] + db 08bh,0ch,085h +lab3 dd 0 ; mov ecx,[eax*4+table1] + ENDM + +SM2M MACRO index,lab1,lab2,lab3 ; 486+ + mov al,[edx] ; AGI-3 + add esi,ecx + db 081h,0c3h +lab1 dd 0 ; add ebx,lo + mov (index*4-4)[edi],esi + db 081h,0d2h +lab2 dd 0 ; adc edx,hi + mov esi,(index*4)[edi] + db 08bh,0ch,085h +lab3 dd 0 ; mov ecx,[eax*4+table1] + ENDM + +SM2L MACRO index ; 486+ + add esi,ecx + mov (index*4-4)[edi],esi + ENDM + +;SS2 ; 386 +;mov al,[edx+source] +;add ebx,lo +;adc edx,hi +;mov ecx,[eax*4+table1] +;mov ebp,[eax*4+table2] +;add [edi],ecx +;add [edi+4],ebp +;ENDM + +;SS2M ; 486+ +;mov al,[edx+source] +;mov [edi-8+4],ebp +;add ebx,lo +;adc edx,hi +;mov esi,[edi] +;mov ecx,[eax*4+table1] +;mov ebp,[edi+4] +;add esi,ecx +;mov ecx,[eax*4+table2] +;mov [edi],esi +;add ebp,ecx +;ENDM + +;SM2M ; 386 +;add ebx,lo +;adc edx,hi +;mov ecx,[eax*4+table1] +;mov al,[edx+source] +;add [edi],ecx +;ENDM + +;SM2M ; 486+ +;add ebx,lo +;mov [edi-4],esi +;adc edx,hi +;mov esi,[edi] +;mov ecx,[eax*4+table1] +;mov al,[edx+source] ; AGI-3 +;add esi,ecx +;ENDM + + +_AsmStereoNormal: + STUBSTART + mov esi,[esp+32] ; get src + mov edi,[esp+36] ; get dst + mov ebx,[esp+40] ; get index + mov ecx,[esp+44] ; get increment + mov ebp,[esp+48] ; get todo + mov eax,ecx + mov edx,ebx + sar eax,31 + sar edx,31 + shld eax,ecx,21 ; convert to 32:32 + shl ecx,21 + shld edx,ebx,21 ; convert to 32:32 + shl ebx,21 + add edx,esi + mov shi1,eax + mov shi2,eax + mov shi3,eax + mov shi4,eax + mov shi5,eax + mov eax,_lvoltab + mov slo1,ecx + mov slo2,ecx + mov slo3,ecx + mov slo4,ecx + mov slo5,ecx + mov sltab1,eax + mov sltab2,eax + mov sltab3,eax + mov sltab4,eax + mov sltab5,eax + mov eax,_rvoltab + push ebp + mov srtab1,eax + mov srtab2,eax + mov srtab3,eax + mov srtab4,eax + mov srtab5,eax + xor eax,eax + jmp s1 ; flush code cache +s1: + shr ebp,2 + jz sskip16 + push ebp +sagain16: + SS2F 0,slo1,shi1,sltab1,srtab1 + SS2M 1,slo2,shi2,sltab2,srtab2 + SS2M 2,slo3,shi3,sltab3,srtab3 + SS2M 3,slo4,shi4,sltab4,srtab4 + SS2L 4 + add edi,(4*8) + dec dword ptr [esp] + jnz sagain16 + pop ebp +sskip16: + pop ebp + and ebp,3 + jz sskip1 + push ebp +sagain1: + SS2F 0,slo5,shi5,sltab5,srtab5 + SS2L 1 + add edi,8 + dec dword ptr [esp] + jnz sagain1 + pop ebp +sskip1: + STUBEND + ret + + +_AsmStereoSurround: + STUBSTART + mov esi,[esp+32] ; get src + mov edi,[esp+36] ; get dst + mov ebx,[esp+40] ; get index + mov ecx,[esp+44] ; get increment + mov ebp,[esp+48] ; get todo + mov eax,ecx + mov edx,ebx + sar eax,31 + sar edx,31 + shld eax,ecx,21 ; convert to 32:32 + shl ecx,21 + shld edx,ebx,21 ; convert to 32:32 + shl ebx,21 + add edx,esi + mov s2hi1,eax + mov s2hi2,eax + mov s2hi3,eax + mov s2hi4,eax + mov s2hi5,eax + mov eax,_lvoltab + mov s2lo1,ecx + mov s2lo2,ecx + mov s2lo3,ecx + mov s2lo4,ecx + mov s2lo5,ecx + mov s2ltab1,eax + mov s2ltab2,eax + mov s2ltab3,eax + mov s2ltab4,eax + mov s2ltab5,eax + ;mov eax,_rvoltab + push ebp + ;mov s2rtab1,eax + ;mov s2rtab2,eax + ;mov s2rtab3,eax + ;mov s2rtab4,eax + ;mov s2rtab5,eax + xor eax,eax + jmp s3 ; flush code cache +s3: + shr ebp,2 + jz s2skip16 + push ebp +s2again16: + SS3F 0,s2lo1,s2hi1,s2ltab1 ;,s2rtab1 + SS3M 1,s2lo2,s2hi2,s2ltab2 ;,s2rtab2 + SS3M 2,s2lo3,s2hi3,s2ltab3 ;,s2rtab3 + SS3M 3,s2lo4,s2hi4,s2ltab4 ;,s2rtab4 + SS2L 4 + add edi,(4*8) + dec dword ptr [esp] + jnz s2again16 + pop ebp +s2skip16: + pop ebp + and ebp,3 + jz s2skip1 + push ebp +s2again1: + SS3F 0,s2lo5,s2hi5,s2ltab5 ;,s2rtab5 + SS2L 1 + add edi,8 + dec dword ptr [esp] + jnz s2again1 + pop ebp +s2skip1: + STUBEND + ret + + +_AsmMonoNormal: + STUBSTART + mov esi,[esp+32] ; get src + mov edi,[esp+36] ; get dst + mov ebx,[esp+40] ; get index + mov ecx,[esp+44] ; get increment + mov ebp,[esp+48] ; get todo + mov eax,ecx + mov edx,ebx + sar eax,31 + sar edx,31 + shld eax,ecx,21 ; convert to 32:32 + shl ecx,21 + shld edx,ebx,21 ; convert to 32:32 + shl ebx,21 + add edx,esi + mov mhi1,eax + mov mhi2,eax + mov mhi3,eax + mov mhi4,eax + mov mhi5,eax + mov eax,_lvoltab + mov mlo1,ecx + mov mlo2,ecx + mov mlo3,ecx + mov mlo4,ecx + mov mlo5,ecx + mov mltab1,eax + mov mltab2,eax + mov mltab3,eax + mov mltab4,eax + mov mltab5,eax + xor eax,eax + + jmp m1 ; flush code cache +m1: + push ebp + shr ebp,2 + jz mskip16 +magain16: + SM2F 0,mlo1,mhi1,mltab1 + SM2M 1,mlo2,mhi2,mltab2 + SM2M 2,mlo3,mhi3,mltab3 + SM2M 3,mlo4,mhi4,mltab4 + SM2L 4 + add edi,(4*4) + dec ebp + jnz magain16 +mskip16: + pop ebp + and ebp,3 + jz mskip1 +magain1: + SM2F 0,mlo5,mhi5,mltab5 + SM2L 1 + add edi,4 + dec ebp + jnz magain1 +mskip1: + STUBEND + ret + + + +IFDEF __ASMSTUFF__ +_AsmMix32To16_Normal: + STUBSTART + mov edi,[esp+32] ; get dest + mov esi,[esp+36] ; get src + mov edx,[esp+40] ; get count + mov cl,[_bitshift] +again: + mov eax,[esi] + sar eax,cl + cmp eax,32767 + jg toobig + cmp eax,-32768 + jl toosmall +write: + mov [edi],ax + add esi,4 + add edi,2 + dec edx + jnz again + jmp ready +toobig: + mov eax,32767 + jmp write +toosmall: + mov eax,-32768 + jmp write +ready: + STUBEND + ret + + +_AsmMix32To8_Normal: + STUBSTART + mov edi,[esp+32] ; get dest + mov esi,[esp+36] ; get src + mov edx,[esp+40] ; get count + mov cl,[_bitshift] +cagain: + mov eax,[esi] + sar eax,cl + cmp eax,127 + jg ctoobig + cmp eax,-128 + jl ctoosmall +cwrite: + add al,080h + add esi,4 + mov [edi],al + inc edi + dec edx + jnz cagain + jmp cready +ctoobig: + mov eax,127 + jmp cwrite +ctoosmall: + mov eax,-128 + jmp cwrite +cready: + STUBEND + ret +ENDIF + + END diff --git a/mikmod/s3m_it.c b/mikmod/s3m_it.c new file mode 100644 index 0000000..f77fcfb --- /dev/null +++ b/mikmod/s3m_it.c @@ -0,0 +1,187 @@ +/* + +Name: +S3M_IT.C + +Description: +Commonfunctions between S3Ms and ITs (smaller .EXE! :) + +Portability: +All systems - all compilers (hopefully) + +*/ + +#include "mikmod.h" + +UBYTE *poslookup=NULL;/* S3M/IT fix - removing blank patterns needs a */ + /* lookup table to fix position-jump commands */ +SBYTE remap[64]; /* for removing empty channels */ +SBYTE isused[64]; /* for removing empty channels */ + + +void S3MIT_ProcessCmd(UBYTE cmd,UBYTE inf,BOOL oldeffect) +{ + UBYTE hi,lo; + + lo=inf&0xf; + hi=inf>>4; + + /* process S3M / IT specific command structure */ + + if(cmd!=255) + { switch(cmd) + { case 1: /* Axx set speed to xx */ + UniWrite(UNI_S3MEFFECTA); + UniWrite(inf); + break; + + case 2: /* Bxx position jump */ + UniPTEffect(0xb,poslookup[inf]); + break; + + case 3: /* Cxx patternbreak to row xx */ + if(oldeffect & 1) + UniPTEffect(0xd,(((inf&0xf0)>>4)*10)+(inf&0xf)); + else + UniPTEffect(0xd,inf); + break; + + case 4: /* Dxy volumeslide */ + UniWrite(UNI_S3MEFFECTD); + UniWrite(inf); + break; + + case 5: /* Exy toneslide down */ + UniWrite(UNI_S3MEFFECTE); + UniWrite(inf); + break; + + case 6: /* Fxy toneslide up */ + UniWrite(UNI_S3MEFFECTF); + UniWrite(inf); + break; + + case 7: /* Gxx Tone portamento, speed xx */ + UniWrite(UNI_ITEFFECTG); + UniWrite(inf); + break; + + case 8: /* Hxy vibrato */ + if(oldeffect & 1) + UniPTEffect(0x4,inf); + else + { UniWrite(UNI_ITEFFECTH); + UniWrite(inf); + } + break; + + case 9: /* Ixy tremor, ontime x, offtime y */ + if(oldeffect & 1) + UniWrite(UNI_S3MEFFECTI); + else + UniWrite(UNI_ITEFFECTI); + UniWrite(inf); + break; + + case 0xa: /* Jxy arpeggio */ + UniPTEffect(0x0,inf); + break; + + case 0xb: /* Kxy Dual command H00 & Dxy */ + if(oldeffect & 1) + UniPTEffect(0x4,0); + else + { UniWrite(UNI_ITEFFECTH); + UniWrite(0); + } + UniWrite(UNI_S3MEFFECTD); + UniWrite(inf); + break; + + case 0xc: /* Lxy Dual command G00 & Dxy */ + if(oldeffect & 1) + UniPTEffect(0x3,0); + else + { UniWrite(UNI_ITEFFECTG); + UniWrite(0); + } + UniWrite(UNI_S3MEFFECTD); + UniWrite(inf); + break; + + case 0xd: /* Mxx Set Channel Volume */ + UniWrite(UNI_ITEFFECTM); + UniWrite(inf); + break; + + case 0xe: /* Nxy Slide Channel Volume */ + UniWrite(UNI_ITEFFECTN); + UniWrite(inf); + break; + + case 0xf: /* Oxx set sampleoffset xx00h */ + UniPTEffect(0x9,inf); + break; + + case 0x10: /* Pxy Slide Panning Commands */ + UniWrite(UNI_ITEFFECTP); + UniWrite(inf); + break; + + case 0x11: /* Qxy Retrig (+volumeslide) */ + UniWrite(UNI_S3MEFFECTQ); + if((inf!=0) && (lo==0) && !(oldeffect & 1)) + UniWrite(1); + else + UniWrite(inf); + break; + + case 0x12: /* Rxy tremolo speed x, depth y */ + UniWrite(UNI_S3MEFFECTR); + UniWrite(inf); + break; + + case 0x13: /* Sxx special commands */ + UniWrite(UNI_ITEFFECTS0); + UniWrite(inf); + break; + + case 0x14: /* Txx tempo */ + if(inf>0x20) + { UniWrite(UNI_S3MEFFECTT); + UniWrite(inf); + } + break; + + case 0x15: /* Uxy Fine Vibrato speed x, depth y */ + if(oldeffect & 1) + UniWrite(UNI_S3MEFFECTU); + else + UniWrite(UNI_ITEFFECTU); + UniWrite(inf); + break; + + case 0x16: /* Vxx Set Global Volume */ + UniWrite(UNI_XMEFFECTG); + UniWrite(inf); + break; + + case 0x17: /* Wxy Global Volume Slide */ + UniWrite(UNI_ITEFFECTW); + UniWrite(inf); + break; + + case 0x18: /* Xxx amiga command 8xx */ + if(oldeffect & 1) + UniPTEffect(0x8,((inf<<1) == 256) ? 255 : (inf<<1)); + else + UniPTEffect(0x8,inf); + break; + + case 0x19: /* Yxy Panbrello speed x, depth y */ + UniWrite(UNI_ITEFFECTY); + UniWrite(inf); + break; + } + } +} diff --git a/mikmod/sloader.c b/mikmod/sloader.c new file mode 100644 index 0000000..557990c --- /dev/null +++ b/mikmod/sloader.c @@ -0,0 +1,407 @@ +/* + --> Sample Loaders and Sample Processing + +Name: sloader.c + +Description: +Routines for loading samples. The sample loader utilizes the routines +provided by the "registered" sample loader. See SAMPLELOADER in +MIKMOD.H for the sample loader structure. + +Portability: +All systems - all compilers + +*/ + +#include "mikmod.h" + + +static int sl_rlength; +static SWORD sl_old; +static SWORD *sl_buffer = NULL; +static SAMPLOAD *musiclist = NULL, + *sndfxlist = NULL; + + + +BOOL SL_Init(SAMPLOAD *s) /* returns 0 on error! */ +{ + if(sl_buffer==NULL) + if((sl_buffer=_mm_malloc(4100)) == NULL) return 0; + + sl_rlength = s->length; + if(s->infmt & SF_16BITS) sl_rlength>>=1; + sl_old = 0; + + return 1; +} + + +void SL_Exit(SAMPLOAD *s) +{ + if(sl_rlength > 0) _mm_fseek(s->fp,sl_rlength,SEEK_CUR); +} + + +void SL_Reset(void) +{ + sl_old = 0; +} + + +void SL_Load(void *buffer, SAMPLOAD *smp, int length) +{ + UWORD infmt = smp->infmt, outfmt = smp->outfmt; + SBYTE *bptr = (SBYTE *)buffer; + SWORD *wptr = (SWORD *)buffer; + int stodo; + int t, u; + + while(length) + { stodo = (length<2048) ? length : 2048; + + if(infmt & SF_16BITS) + { if(infmt & SF_BIG_ENDIAN) + _mm_read_M_SWORDS(sl_buffer,stodo,smp->fp); + else + _mm_read_I_SWORDS(sl_buffer,stodo,smp->fp); + } else + { SBYTE *s; + SWORD *d; + + _mm_fread(sl_buffer,sizeof(SBYTE),stodo,smp->fp); + + s = (SBYTE *)sl_buffer; + d = sl_buffer; + s += stodo; + d += stodo; + + for(t=0; tscalefactor) + { int idx = 0; + SLONG scaleval; + + /* Sample Scaling... average values for better results. */ + t = 0; + while(tscalefactor; u && tscalefactor-u); + length--; + } + sl_rlength -= stodo; + stodo = idx; + } else + { length -= stodo; + sl_rlength -= stodo; + } + + if(outfmt & SF_16BITS) + { for(t=0; t>8; + } + } +} + + +void SL_LoadStream(void *buffer, UWORD infmt, UWORD outfmt, int length, VIRTUAL_FILE *fp) + +/* This is like SL_Load, but does not perform sample scaling, and does not */ +/* require calls to SL_Init / SL_Exit. */ + +{ + SBYTE *bptr = (SBYTE *)buffer; + SWORD *wptr = (SWORD *)buffer; + int stodo; + int t; + + /* compute number of samples to load */ + + if(sl_buffer==NULL) + if((sl_buffer=_mm_malloc(4100)) == NULL) return; + + while(length) + { stodo = (length<2048) ? length : 2048; + + if(infmt & SF_16BITS) + { if(infmt & SF_BIG_ENDIAN) + _mm_read_M_SWORDS(sl_buffer,stodo,fp); + else + _mm_read_I_SWORDS(sl_buffer,stodo,fp); + } else + { SBYTE *s; + SWORD *d; + + _mm_fread(sl_buffer,sizeof(SBYTE),stodo,fp); + + s = (SBYTE *)sl_buffer; + d = sl_buffer; + s += stodo; + d += stodo; + + for(t=0; t> 1; + length-=2; + } + stodo = idx; + } + + if(outfmt & SF_16BITS) + { for(t=0; t>8; + } + } +} + + +SAMPLOAD *SL_RegisterSample(SAMPLE *s, int type, VIRTUAL_FILE *fp) /* Returns 1 on error! */ + +/* Registers a sample for loading when SL_LoadSamples() is called. */ +/* type - type of sample to be loaded .. */ +/* MD_MUSIC, MD_SNDFX */ + +{ + SAMPLOAD *news, **samplist, *cruise; + + if(type==MD_MUSIC) + { samplist = & musiclist; + cruise = musiclist; + } else + { samplist = &sndfxlist; + cruise = sndfxlist; + } + + /* Allocate and add structure to the END of the list */ + + if((news=(SAMPLOAD *)_mm_calloc(1,sizeof(SAMPLOAD))) == NULL) return NULL; + + if(cruise!=NULL) + { while(cruise->next!=NULL) cruise = cruise->next; + cruise->next = news; + } else + *samplist = news; + + news->infmt = s->flags & 31; + news->outfmt = news->infmt; + news->fp = fp; + news->sample = s; + news->length = s->length; + news->loopstart = s->loopstart; + news->loopend = s->loopend; + + return news; +} + + +static void FreeSampleList(SAMPLOAD *s) +{ + SAMPLOAD *old; + + while(s!=NULL) + { old = s; + s = s->next; + free(old); + } +} + + +static ULONG SampleTotal(SAMPLOAD *samplist, int type) +/* Returns the total amount of memory required by the samplelist queue. */ +{ + int total = 0; + + while(samplist!=NULL) + { samplist->sample->flags = (samplist->sample->flags&~31) | samplist->outfmt; + total += MD_SampleLength(type,samplist->sample); + samplist = samplist->next; + } + + return total; +} + + +static ULONG RealSpeed(SAMPLOAD *s) +{ + return(s->sample->speed / ((s->scalefactor==0) ? 1 : s->scalefactor)); +} + + +static BOOL DitherSamples(SAMPLOAD *samplist, int type) +{ + SAMPLOAD *c2smp; + ULONG maxsize, speed; + SAMPLOAD *s; + + if(samplist==NULL) return 0; + + /* make sure the samples will fit inside available RAM */ + if((maxsize = MD_SampleSpace(type)*1024) != 0) + { while(SampleTotal(samplist, type) > maxsize) + { /* First Pass - check for any 16 bit samples */ + s = samplist; + while(s!=NULL) + { if(s->outfmt & SF_16BITS) + { SL_Sample16to8(s); + break; + } + s = s->next; + } + + /* Second pass (if no 16bits found above) is to take the sample */ + /* with the highest speed and dither it by half. */ + if(s==NULL) + { s = samplist; + speed = 0; + while(s!=NULL) + { if((s->sample->length) && (RealSpeed(s) > speed)) + { speed = RealSpeed(s); + c2smp = s; + } + s = s->next; + } + SL_HalveSample(c2smp); + } + } + } + + + /* Samples dithered, now load them! */ + /* ================================ */ + + s = samplist; + while(s != NULL) + { /* sample has to be loaded ? -> increase number of */ + /* samples, allocate memory and load sample. */ + + if(s->sample->length) + { if(s->sample->seekpos) + _mm_fseek(s->fp, s->sample->seekpos, SEEK_SET); + + /* Call the sample load routine of the driver module. */ + /* It has to return a 'handle' (>=0) that identifies */ + /* the sample. */ + + s->sample->handle = MD_SampleLoad(s, type, s->fp); + s->sample->flags = (s->sample->flags & ~31) | s->outfmt; + if(s->sample->handle < 0) + { FreeSampleList(samplist); + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + return 1; + } + } + s = s->next; + } + + FreeSampleList(samplist); + return 0; +} + + +BOOL SL_LoadSamples(void) /* Returns 1 on error! */ +{ + BOOL ok; + + _mm_critical = 0; + + if((musiclist==NULL) && (sndfxlist==NULL)) return 0; +/* MikMod_Exit(); */ +/* exit(1); */ + ok = DitherSamples(musiclist,MD_MUSIC) || DitherSamples(sndfxlist,MD_SNDFX); + + musiclist = sndfxlist = NULL; + + return ok; +} + + +void SL_Sample16to8(SAMPLOAD *s) +{ + s->outfmt &= ~SF_16BITS; + s->sample->flags = (s->sample->flags&~31) | s->outfmt; +} + + +void SL_Sample8to16(SAMPLOAD *s) +{ + s->outfmt |= SF_16BITS; + s->sample->flags = (s->sample->flags&~31) | s->outfmt; +} + + +void SL_SampleSigned(SAMPLOAD *s) +{ + s->outfmt |= SF_SIGNED; + s->sample->flags = (s->sample->flags&~31) | s->outfmt; +} + + +void SL_SampleUnsigned(SAMPLOAD *s) +{ + s->outfmt &= ~SF_SIGNED; + s->sample->flags = (s->sample->flags&~31) | s->outfmt; +} + + +void SL_HalveSample(SAMPLOAD *s) +{ + if(s->scalefactor) + s->scalefactor++; + else + s->scalefactor = 2; + + s->sample->divfactor = s->scalefactor; + s->sample->length = s->length / s->scalefactor; + s->sample->loopstart = s->loopstart / s->scalefactor; + s->sample->loopend = s->loopend / s->scalefactor; +} + diff --git a/mikmod/stream.c b/mikmod/stream.c new file mode 100644 index 0000000..8a44851 --- /dev/null +++ b/mikmod/stream.c @@ -0,0 +1,134 @@ +/* + File: STREAM.C + + Description: + Streaming Audio module for MikMod. + + Portability: + All compilers - All systems + +*/ + + +#include "mikmod.h" + + +int stream_bufsize = 100; /* in 1/100th seconds */ + +static BOOL is_streaming = 0; +static MSTREAM *firststream = NULL; + +static BOOL active; + +VIRTUAL_FILE *stream_fp; +SLONG stream_seekpos; +SLONG stream_reppos; + +void MikMod_RegisterStream(MSTREAM *stream) +{ + MSTREAM *cruise = firststream; + + if(cruise!=NULL) + { while(cruise->next!=NULL) cruise = cruise->next; + cruise->next = stream; + } else + firststream = stream; +} + + +BOOL Stream_PlayFN(CHAR *filename) +{ + return 0; +} + + +BOOL Stream_PlayFP(VIRTUAL_FILE *fp) +{ + BOOL ok; + MSTREAM *l; + + stream_fp = fp; + _mm_errno = 0; + _mm_critical = 0; + + _mm_iobase_setcur(stream_fp); + + /* Try to find a loader that recognizes the stream */ + + for(l=firststream; l!=NULL; l=l->next) + { _mm_rewind(stream_fp); + if(l->Test()) break; + } + + if(l==NULL) + { _mm_errno = MMERR_NOT_A_STREAM; + if(_mm_errorhandler!=NULL) _mm_errorhandler(); + _mm_iobase_revert(); + return 1; + } + + /* init stream loader and load the header */ + if(l->Init()) + { _mm_rewind(stream_fp); + ok = l->Load(); + } + + /* free loader allocations */ + l->Cleanup(); + + if(!ok) + { _mm_iobase_revert(); + return 1; + } + + /*loadbuf = _mm_malloc(8192); */ + + _mm_iobase_revert(); + active = 1; + return 0; +} + + +BOOL Stream_Init(ULONG speed, UWORD flags) + +/* size = size of buffer in 1/100th seconds */ + +{ + if(is_streaming) md_driver->StreamExit(); + if(md_driver->StreamInit(speed,flags)) return 1; + is_streaming = 1; + + return 0; +} + + +void Stream_Exit(void) +{ + if(is_streaming) md_driver->StreamExit(); + is_streaming = 0; +} + + +static ULONG last = 0; + +void Stream_Update(void) +{ + ULONG curr; + ULONG todo; + + curr = md_driver->StreamGetPosition(); + if(curr==last) return; + + if(curr>last) + { todo = curr-last; + /*SL_LoadStream(,vstream.infmt,vstream.flags,todo,stream_fp); */ + last += todo; + /*if(last>=vstream.size) last = 0; */ + } else + { /*todo = vstream.size-last; */ + /*SL_LoadStream(&vstream.buffer[last],vstream.infmt,vstream.flags,todo,stream_fp); */ + /*SL_LoadStream(vstream.buffer,vstream.infmt,vstream.flags,curr,stream_fp); */ + last = curr; + } +} + diff --git a/mikmod/tdefs.h b/mikmod/tdefs.h new file mode 100644 index 0000000..6614873 --- /dev/null +++ b/mikmod/tdefs.h @@ -0,0 +1,105 @@ +/* + TDEFS.H : Type definitions for the more commonly used type statements. + A 'shortened' version of MTYPES.H that has only what I use most. + + This module is my hidden secret of "portability" to many compilers + and platforms. I really love C sometimes.. ;) +*/ + + +#ifndef TDEFS_H +#define TDEFS_H + + +/* + MikMod atomic types: + ==================== +*/ + +typedef char CHAR; + +#ifdef __OS2__ + +typedef signed char SBYTE; /* has to be 1 byte signed */ +typedef unsigned char UBYTE; /* has to be 1 byte unsigned */ +typedef signed short SWORD; /* has to be 2 bytes signed */ +typedef unsigned short UWORD; /* has to be 2 bytes unsigned */ +typedef signed long SLONG; /* has to be 4 bytes signed */ +/* ULONG and BOOL are already defined in OS2.H */ + +#elif defined(__alpha) + +typedef signed char SBYTE; /* has to be 1 byte signed */ +typedef unsigned char UBYTE; /* has to be 1 byte unsigned */ +typedef signed short SWORD; /* has to be 2 bytes signed */ +typedef unsigned short UWORD; /* has to be 2 bytes unsigned */ +/* long is 8 bytes on dec alpha - RCA */ +typedef signed int SLONG; /* has to be 4 bytes signed */ +typedef unsigned int ULONG; /* has to be 4 bytes unsigned */ +typedef int BOOL; /* doesn't matter.. 0=FALSE, <>0 true */ + +#else + +typedef signed char SBYTE; /* has to be 1 byte signed */ +typedef unsigned char UBYTE; /* has to be 1 byte unsigned */ +typedef signed short SWORD; /* has to be 2 bytes signed */ +typedef unsigned short UWORD; /* has to be 2 bytes unsigned */ +typedef signed long SLONG; /* has to be 4 bytes signed */ +typedef unsigned long ULONG; /* has to be 4 bytes unsigned */ +typedef int BOOL; /* doesn't matter.. 0=FALSE, <>0 true */ + +#endif + + +#ifdef __OS2__ +#define INCL_DOS +#define INCL_MCIOS2 +#define INCL_MMIOOS2 +#include +#include +#include +#endif + + +#ifdef __WATCOMC__ + +typedef __int64 SDOUBLE; +typedef unsigned __int64 UDOUBLE; + +#define inportb(x) inp(x) +#define outportb(x,y) outp(x,y) +#define inport(x) inpw(x) +#define outport(x,y) outpw(x,y) +#define disable() _disable() +#define enable() _enable() +#endif + +#ifdef __BORLANDC__ +#define inp(x) inportb(x) +#define outp(x,y) outportb(x,y) +#define inpw(x) inport(x) +#define outpw(x,y) outport(x,y) +#define _disable() disable() +#define _enable() enable() +#endif + +#ifdef __DJGPP__ +#include +#include +#include +#define inp inportw +#define outport outportw +#define inport inportw +#define interrupt +#endif + +#if defined(__OS2__) + #define delay(x) DosSleep(x); +#elif defined(__WIN32__) + #define delay(x) Sleep(x); +#elif defined(__GNUC__) + #define delay(x) ; +#endif + +#endif + diff --git a/mikmod/timer.h b/mikmod/timer.h new file mode 100644 index 0000000..6d1b075 --- /dev/null +++ b/mikmod/timer.h @@ -0,0 +1,88 @@ +/* + FILE : TIMER.H + + DOS-based Timer Interrupt functions + Includes defines for TIMER.C and VTIMER.C +*/ + +#ifndef VTIMER_H +#define VTIMER_H + +#include "tdefs.h" + +#define VT_VRSYNC 1 +#define VT_CALLOLD 2 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Defined in TIMER.C */ + +void Timer_Exit(void); +void Timer_Init(int rate, void (*handler)(void)); +void Timer_SetSpeed(UWORD rate); +void Timer_Start(void); +void Timer_Stop(void); + + +/* Defined in VTIMER.C */ +void VT_Exit(void); +void VT_Init(void); +SWORD VT_Alloc(void); +void VT_Free(SWORD handle); +void VT_SetHandler(SWORD handle,void (*handler)(void)); +void VT_SetSpeed(SWORD handle,SLONG speed); +void VT_SetBPM(SWORD handle,UBYTE bpm); +void VT_Start(SWORD handle); +void VT_Stop(SWORD handle); +void VT_Mode(UBYTE flags); +void VT_V0Handler(void (*handler)(void)); +void VT_V1Handler(void (*handler)(void)); + +#ifdef __cplusplus +} +#endif + + +extern volatile int framecount; +void framecounter(void); + +/* COUNTER.C defnitions */ +/* (ObjectGraphics Library) */ + +#define CNT_ACTIVE 16 +#define CNT_VALUE 0 +#define CNT_POINTER 1 +#define CNT_FUNCTION 2 +#define CNT_TYPE 15 + +typedef struct COUNTER +{ struct COUNTER *next, *prev; + UBYTE flags; + ULONG counter; + ULONG resetcount; + int increment; + int value; + int stopvalue; +} COUNTER; + + +/* Defined in COUNTER.C */ +/* (ObjectGraphics Library) */ + +COUNTER *RegisterCounter(ULONG initcount, ULONG resetcount, int value, int increment, int stopvalue, UBYTE flags); +void RemoveCounter(COUNTER *counter); +void StartCounter(COUNTER *counter); +void StopCounter(COUNTER *counter); + +#ifdef DJGPP +#include +typedef void (*PVI)(); +#define interrupt +#define far +void _dos_setvect(unsigned vector, PVI handler); +PVI _dos_getvect(unsigned vector); +#endif + +#endif diff --git a/mikmod/virtch.c b/mikmod/virtch.c new file mode 100644 index 0000000..ed3fbc7 --- /dev/null +++ b/mikmod/virtch.c @@ -0,0 +1,1407 @@ +/* + +Name: VIRTCH.C + +Description: + Sample mixing routines, using a 32 bits mixing buffer. + + Optional features include: + (a) 4-step reverb (for 16 bit output only) + (b) Interpolation of sample data during mixing + (c) Dolby Surround Sound + (d) Optimized assembly mixers for the Intel platform + (e) Optional high-speed or high-quality modes + +C Mixer Portability: + All Systems -- All compilers. + +Assembly Mixer Portability: + + MSDOS: BC(?) Watcom(y) DJGPP(y) + Win95: ? + Os2: ? + Linux: y + + (y) - yes + (n) - no (not possible or not useful) + (?) - may be possible, but not tested + +*/ + +#include +#include +#include +#include "mikmod.h" + + +// ** For PC-assembly mixing +// ========================= +// Uncomment both lines below for assembly mixing under WATCOM or GCC for +// Linux. Note that there is no 16 bit mixers for assembly yet (C only), so +// defining __ASSEMBLY__ when not defining __FASTMIXER__ will lead to compiler +// errors. + +#define __FASTMIXER__ +/* #define __ASSEMBLY__ */ +#define __FAST_REVERB__ + +// Various other VIRTCH.C Compiler Options +// ======================================= + +// BITSHIFT : Controls the maximum volume of the sound output. All data +// is shifted right by BITSHIFT after being mixed. Higher values +// result in quieter sound and less chance of distortion. If you +// are using the assembly mixer, you must change the bitshift const- +// ant in RESAMPLE.ASM or RESAMPLE.S as well! + +#define BITSHIFT 9 + +// REVERBERATION : Controls the duration of the reverb. Larger values +// represent a shorter reverb loop. Smaller values extend the reverb +// but can result in more of an echo-ish sound. + +#define REVERBERATION 110000l + +// BOUNDS_CHECKING : Forces VIRTCH to perform bounds checking. Commenting +// the line below will result in a slightly faster mixing process but +// could cause nasty clicks and pops on some modules. Disable this +// option on games or demos only, where speed is very important all +// songs / sndfx played can be specifically tested for pops. + +#define BOUNDS_CHECKING + + +#ifdef __GNUC__ +#define __cdecl +#endif + +#ifdef __WATCOMC__ +#define inline +#endif + +#define FRACBITS 11 +#define FRACMASK ((1l<(b))?(a):(b)) +#endif + + +typedef struct +{ UBYTE kick; // =1 -> sample has to be restarted + UBYTE active; // =1 -> sample is playing + UWORD flags; // 16/8 bits looping/one-shot + SWORD handle; // identifies the sample + ULONG start; // start index + ULONG size; // samplesize + ULONG reppos; // loop start + ULONG repend; // loop end + ULONG frq; // current frequency + int vol; // current volume + int pan; // current panning position + SLONG current; // current index in the sample + SLONG increment; // fixed-point increment value +} VINFO; + +#ifdef __FASTMIXER__ +static SBYTE **Samples; +SLONG *lvoltab, *rvoltab; // Volume Table values for use by 8 bit mixers +#else +static SWORD **Samples; +static SLONG lvolsel, rvolsel; // Volume Selectors for 16 bit mixers. +#endif + +// Volume table for 8 bit sample mixing +#ifdef __FASTMIXER__ +static SLONG **voltab; +#endif + +static VINFO *vinf = NULL, *vnf; +static long TICKLEFT, samplesthatfit, vc_memory = 0; +static int vc_softchn; +static SLONG idxsize, idxlpos, idxlend; +static SLONG *VC_TICKBUF = NULL; +static UWORD vc_mode; + + +// Reverb control variables +// ======================== + +static int RVc1, RVc2, RVc3, RVc4; +#ifndef __FAST_REVERB__ +static int RVc5, RVc6, RVc7, RVc8; +#endif +static ULONG RVRindex; + + +// For Mono or Left Channel + +static SLONG *RVbuf1 = NULL, *RVbuf2 = NULL, *RVbuf3 = NULL, *RVbuf4 = NULL; +#ifndef __FAST_REVERB__ +static SLONG *RVbuf5 = NULL, *RVbuf6 = NULL, *RVbuf7 = NULL, *RVbuf8 = NULL; +#endif + +// For Stereo only (Right Channel) +// Values start at 9 to leave room for expanding this to 8-step +// reverb in the future. + +static SLONG *RVbuf9 = NULL, *RVbuf10 = NULL, *RVbuf11 = NULL, *RVbuf12 = NULL; +#ifndef __FAST_REVERB__ +static SLONG *RVbuf13 = NULL, *RVbuf14 = NULL, *RVbuf15 = NULL, *RVbuf16 = NULL; +#endif + + +// Define external Assembly Language Prototypes +// ============================================ + +#ifdef __ASSEMBLY__ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __GNUC__ +#define __cdecl +#endif + +void __cdecl AsmStereoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,SLONG todo); +void __cdecl AsmStereoInterp(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,SLONG todo); +void __cdecl AsmSurroundNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,SLONG todo); +void __cdecl AsmSurroundInterp(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,SLONG todo); +void __cdecl AsmMonoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,SLONG todo); +void __cdecl AsmMonoInterp(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,SLONG todo); + +#ifdef __cplusplus +}; +#endif + +#else + +#ifdef __FASTMIXER__ + +// ============================================================== +// 8 bit sample mixers! + +static SLONG MixStereoNormal(SBYTE *srce, SLONG *dest, SLONG index, SLONG increment, SLONG todo) +{ + UBYTE sample1, sample2, sample3, sample4; + int remain; + + remain = todo & 3; + + for(todo>>=2; todo; todo--) + { + sample1 = srce[index >> FRACBITS]; + index += increment; + sample2 = srce[index >> FRACBITS]; + index += increment; + sample3 = srce[index >> FRACBITS]; + index += increment; + sample4 = srce[index >> FRACBITS]; + index += increment; + + *dest++ += lvoltab[sample1]; + *dest++ += rvoltab[sample1]; + *dest++ += lvoltab[sample2]; + *dest++ += rvoltab[sample2]; + *dest++ += lvoltab[sample3]; + *dest++ += rvoltab[sample3]; + *dest++ += lvoltab[sample4]; + *dest++ += rvoltab[sample4]; + } + + for(; remain--; ) + { + sample1 = srce[index >> FRACBITS]; + index += increment; + *dest++ += lvoltab[sample1]; + *dest++ += rvoltab[sample1]; + } + + return index; +} + + +static SLONG MixStereoInterp(SBYTE *srce, SLONG *dest, SLONG index, SLONG increment, SLONG todo) +{ + UBYTE sample; + + for(; todo; todo--) + { sample = (UBYTE)((srce[index >> FRACBITS] * ((FRACMASK+1l) - (index & FRACMASK))) + + (srce[(index >> FRACBITS) + 1] * (index & FRACMASK)) >> FRACBITS); + index += increment; + + *dest++ += lvoltab[sample]; + *dest++ += rvoltab[sample]; + } + + return index; +} + + +static SLONG MixSurroundNormal(SBYTE *srce, SLONG *dest, SLONG index, SLONG increment, SLONG todo) +{ + SLONG sample1, sample2, sample3, sample4; + int remain; + + remain = todo & 3; + + for(todo>>=2; todo; todo--) + { + sample1 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; + index += increment; + sample2 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; + index += increment; + sample3 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; + index += increment; + sample4 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; + index += increment; + + *dest++ += sample1; + *dest++ -= sample1; + *dest++ += sample2; + *dest++ -= sample2; + *dest++ += sample3; + *dest++ -= sample3; + *dest++ += sample4; + *dest++ -= sample4; + } + + for(; remain--; ) + { sample1 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; + index += increment; + *dest++ += sample1; + *dest++ -= sample1; + } + + return index; +} + + +static SLONG MixSurroundInterp(SBYTE *srce, SLONG *dest, SLONG index, SLONG increment, SLONG todo) +{ + SLONG sample; + + for(; todo; todo--) + { sample = lvoltab[(UBYTE)((srce[index >> FRACBITS] * ((FRACMASK+1l) - (index & FRACMASK))) + + (srce[(index >> FRACBITS) + 1] * (index & FRACMASK)) >> FRACBITS)]; + index += increment; + + *dest++ += sample; + *dest++ -= sample; + } + + return index; +} + + +static SLONG MixMonoNormal(SBYTE *srce, SLONG *dest, SLONG index, SLONG increment, SLONG todo) +{ + SLONG sample1, sample2, sample3, sample4; + int remain; + + remain = todo & 3; + + for(todo>>=2; todo; todo--) + { + sample1 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; + index += increment; + sample2 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; + index += increment; + sample3 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; + index += increment; + sample4 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; + index += increment; + + *dest++ += sample1; + *dest++ += sample2; + *dest++ += sample3; + *dest++ += sample4; + } + + for(; remain--;) + { sample1 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; + index += increment; + *dest++ += sample1; + } + + return index; +} + + +static SLONG MixMonoInterp(SBYTE *srce, SLONG *dest, SLONG index, SLONG increment, SLONG todo) +{ + SLONG sample; + + for(; todo; todo--) + { sample = lvoltab[(UBYTE)(((srce[index >> FRACBITS] * ((FRACMASK+1l) - (index & FRACMASK))) + + (srce[(index >> FRACBITS) + 1] * (index & FRACMASK))) >> FRACBITS)]; + index += increment; + + *dest++ += sample; + } + + return index; +} + + +#else // not __FASTMIXER__ + +// ============================================================== +// 16 bit sample mixers! + +static SLONG MixStereoNormal(SWORD *srce, SLONG *dest, SLONG index, SLONG increment, ULONG todo) +{ + SWORD sample; + + for(; todo; todo--) + { + sample = srce[index >> FRACBITS]; + index += increment; + + *dest++ += lvolsel * sample; + *dest++ += rvolsel * sample; + } + + return index; +} + + +static SLONG MixStereoInterp(SWORD *srce, SLONG *dest, SLONG index, SLONG increment, ULONG todo) +{ + SWORD sample; + + for(; todo; todo--) + { + sample = (srce[index >> FRACBITS] * ((FRACMASK+1l) - (index & FRACMASK))) + + (srce[(index >> FRACBITS)+1] * (index & FRACMASK)) >> FRACBITS; + index += increment; + + *dest++ += lvolsel * sample; + *dest++ += rvolsel * sample; + } + + return index; +} + + +static SLONG MixSurroundNormal(SWORD *srce, SLONG *dest, SLONG index, SLONG increment, ULONG todo) +{ + SWORD sample; + + for (; todo; todo--) + { + sample = srce[index >> FRACBITS]; + index += increment; + + *dest++ += lvolsel * sample; + *dest++ -= lvolsel * sample; + } + + return index; +} + + +static SLONG MixSurroundInterp(SWORD *srce, SLONG *dest, SLONG index, SLONG increment, ULONG todo) +{ + SWORD sample; + + for (; todo; todo--) + { + sample = (srce[index >> FRACBITS] * ((FRACMASK+1l) - (index & FRACMASK))) + + (srce[(index >> FRACBITS)+1] * (index & FRACMASK)) >> FRACBITS; + index += increment; + + *dest++ += lvolsel * sample; + *dest++ -= lvolsel * sample; + } + + return index; +} + + +static SLONG MixMonoNormal(SWORD *srce, SLONG *dest, SLONG index, SLONG increment, SLONG todo) +{ + SWORD sample; + + for(; todo; todo--) + { + sample = srce[index >> FRACBITS]; + index += increment; + + *dest++ += lvolsel * sample; + } + + return index; +} + + +static SLONG MixMonoInterp(SWORD *srce, SLONG *dest, SLONG index, SLONG increment, SLONG todo) +{ + SWORD sample; + + for(; todo; todo--) + { + sample = (srce[index >> FRACBITS] * ((FRACMASK+1l) - (index & FRACMASK))) + + (srce[(index >> FRACBITS)+1] * (index & FRACMASK)) >> FRACBITS; + index += increment; + + *dest++ += lvolsel * sample; + } + + return index; +} + + +#endif // __FASTMIXER__ +#endif // __ASSEMBLY__ + +static void (*MixReverb)(SLONG *srce, SLONG count); + +static void MixReverb_Normal(SLONG *srce, SLONG count) +{ + unsigned int speedup; + int ReverbPct; + unsigned int loc1, loc2, loc3, loc4; +#ifndef __FAST_REVERB__ + unsigned int loc5, loc6, loc7, loc8; + + ReverbPct = 58 + (md_reverb*4); +#else + ReverbPct = 89 + (md_reverb*2); +#endif + + loc1 = RVRindex % RVc1; + loc2 = RVRindex % RVc2; + loc3 = RVRindex % RVc3; + loc4 = RVRindex % RVc4; +#ifndef __FAST_REVERB__ + loc5 = RVRindex % RVc5; + loc6 = RVRindex % RVc6; + loc7 = RVRindex % RVc7; + loc8 = RVRindex % RVc8; +#endif + + for(; count; count--) + { + // Compute the LEFT CHANNEL echo buffers! + + speedup = *srce >> 3; + + RVbuf1[loc1] = speedup + ((ReverbPct * RVbuf1[loc1]) / 128); + RVbuf2[loc2] = speedup + ((ReverbPct * RVbuf2[loc2]) / 128); + RVbuf3[loc3] = speedup + ((ReverbPct * RVbuf3[loc3]) / 128); + RVbuf4[loc4] = speedup + ((ReverbPct * RVbuf4[loc4]) / 128); +#ifndef __FAST_REVERB__ + RVbuf5[loc5] = speedup + ((ReverbPct * RVbuf5[loc5]) / 128); + RVbuf6[loc6] = speedup + ((ReverbPct * RVbuf6[loc6]) / 128); + RVbuf7[loc7] = speedup + ((ReverbPct * RVbuf7[loc7]) / 128); + RVbuf8[loc8] = speedup + ((ReverbPct * RVbuf8[loc8]) / 128); +#endif + + // Prepare to compute actual finalized data! + + RVRindex++; + loc1 = RVRindex % RVc1; + loc2 = RVRindex % RVc2; + loc3 = RVRindex % RVc3; + loc4 = RVRindex % RVc4; +#ifndef __FAST_REVERB__ + loc5 = RVRindex % RVc5; + loc6 = RVRindex % RVc6; + loc7 = RVRindex % RVc7; + loc8 = RVRindex % RVc8; +#endif + // Left Channel! + +#ifdef __FAST_REVERB__ + *srce++ += RVbuf1[loc1] - RVbuf2[loc2] + RVbuf3[loc3] - RVbuf4[loc4]; +#else + *srce++ += RVbuf1[loc1] - RVbuf2[loc2] + RVbuf3[loc3] - RVbuf4[loc4] + + RVbuf5[loc5] - RVbuf6[loc6] + RVbuf7[loc7] - RVbuf8[loc8]; +#endif + } +} + + +static void MixReverb_Stereo(SLONG *srce, SLONG count) +{ + unsigned int speedup; + int ReverbPct; + unsigned int loc1, loc2, loc3, loc4; +#ifndef __FAST_REVERB__ + unsigned int loc5, loc6, loc7, loc8; + + ReverbPct = 63 + (md_reverb*4); +#else + ReverbPct = 92 + (md_reverb*2); +#endif + + loc1 = RVRindex % RVc1; + loc2 = RVRindex % RVc2; + loc3 = RVRindex % RVc3; + loc4 = RVRindex % RVc4; +#ifndef __FAST_REVERB__ + loc5 = RVRindex % RVc5; + loc6 = RVRindex % RVc6; + loc7 = RVRindex % RVc7; + loc8 = RVRindex % RVc8; +#endif + + for(; count; count--) + { + // Compute the LEFT CHANNEL echo buffers! + + speedup = *srce >> 3; + + RVbuf1[loc1] = speedup + ((ReverbPct * RVbuf1[loc1]) / 128); + RVbuf2[loc2] = speedup + ((ReverbPct * RVbuf2[loc2]) / 128); + RVbuf3[loc3] = speedup + ((ReverbPct * RVbuf3[loc3]) / 128); + RVbuf4[loc4] = speedup + ((ReverbPct * RVbuf4[loc4]) / 128); +#ifndef __FAST_REVERB__ + RVbuf5[loc5] = speedup + ((ReverbPct * RVbuf5[loc5]) / 128); + RVbuf6[loc6] = speedup + ((ReverbPct * RVbuf6[loc6]) / 128); + RVbuf7[loc7] = speedup + ((ReverbPct * RVbuf7[loc7]) / 128); + RVbuf8[loc8] = speedup + ((ReverbPct * RVbuf8[loc8]) / 128); +#endif + + // Compute the RIGHT CHANNEL echo buffers! + + speedup = srce[1] >> 3; + + RVbuf9[loc1] = speedup + ((ReverbPct * RVbuf9[loc1]) / 128); + RVbuf10[loc2] = speedup + ((ReverbPct * RVbuf11[loc2]) / 128); + RVbuf11[loc3] = speedup + ((ReverbPct * RVbuf12[loc3]) / 128); + RVbuf12[loc4] = speedup + ((ReverbPct * RVbuf12[loc4]) / 128); +#ifndef __FAST_REVERB__ + RVbuf13[loc5] = speedup + ((ReverbPct * RVbuf13[loc5]) / 128); + RVbuf14[loc6] = speedup + ((ReverbPct * RVbuf14[loc6]) / 128); + RVbuf15[loc7] = speedup + ((ReverbPct * RVbuf15[loc7]) / 128); + RVbuf16[loc8] = speedup + ((ReverbPct * RVbuf16[loc8]) / 128); +#endif + + // Prepare to compute actual finalized data! + + RVRindex++; + loc1 = RVRindex % RVc1; + loc2 = RVRindex % RVc2; + loc3 = RVRindex % RVc3; + loc4 = RVRindex % RVc4; +#ifndef __FAST_REVERB__ + loc5 = RVRindex % RVc5; + loc6 = RVRindex % RVc6; + loc7 = RVRindex % RVc7; + loc8 = RVRindex % RVc8; +#endif + +#ifdef __FAST_REVERB__ + // Left Channel then right channel! + *srce++ += RVbuf1[loc1] - RVbuf2[loc2] + RVbuf3[loc3] - RVbuf4[loc4]; + *srce++ += RVbuf9[loc1] - RVbuf10[loc2] + RVbuf11[loc3] - RVbuf12[loc4]; +#else + // Left Channel then right channel! + *srce++ += RVbuf1[loc1] - RVbuf2[loc2] + RVbuf3[loc3] - RVbuf4[loc4] + + RVbuf5[loc5] - RVbuf6[loc6] + RVbuf7[loc7] - RVbuf8[loc8]; + + *srce++ += RVbuf9[loc1] - RVbuf10[loc2] + RVbuf11[loc3] - RVbuf12[loc4] + + RVbuf13[loc5] - RVbuf14[loc6] + RVbuf15[loc7] - RVbuf16[loc8]; +#endif + } +} + + +static void Mix32To16(SWORD *dste, SLONG *srce, SLONG count) +{ + SLONG x1, x2, x3, x4; + int remain; + + remain = count & 3; + + if (md_mixshift == 0) { + for(count>>=2; count; count--) + { x1 = *srce++ >> BITSHIFT; + x2 = *srce++ >> BITSHIFT; + x3 = *srce++ >> BITSHIFT; + x4 = *srce++ >> BITSHIFT; + + #ifdef BOUNDS_CHECKING + x1 = (x1 > 32767) ? 32767 : (x1 < -32768) ? -32768 : x1; + x2 = (x2 > 32767) ? 32767 : (x2 < -32768) ? -32768 : x2; + x3 = (x3 > 32767) ? 32767 : (x3 < -32768) ? -32768 : x3; + x4 = (x4 > 32767) ? 32767 : (x4 < -32768) ? -32768 : x4; + #endif + + *dste++ = x1; + *dste++ = x2; + *dste++ = x3; + *dste++ = x4; + } + } + else if (md_mixshift == 1) { + for(count>>=2; count; count--) + { x1 = *srce++ >> BITSHIFT; + x2 = *srce++ >> BITSHIFT; + x3 = *srce++ >> BITSHIFT; + x4 = *srce++ >> BITSHIFT; + + #ifdef BOUNDS_CHECKING + x1 = (x1 > 32767) ? 32767 : (x1 < -32768) ? -32768 : x1; + x2 = (x2 > 32767) ? 32767 : (x2 < -32768) ? -32768 : x2; + x3 = (x3 > 32767) ? 32767 : (x3 < -32768) ? -32768 : x3; + x4 = (x4 > 32767) ? 32767 : (x4 < -32768) ? -32768 : x4; + #endif + + *dste++ = x1; + *dste++ = x2; + *dste++ = x1; + *dste++ = x2; + *dste++ = x3; + *dste++ = x4; + *dste++ = x3; + *dste++ = x4; + } + } + else if (md_mixshift == 2) { + for(count>>=2; count; count--) + { x1 = *srce++ >> BITSHIFT; + x2 = *srce++ >> BITSHIFT; + x3 = *srce++ >> BITSHIFT; + x4 = *srce++ >> BITSHIFT; + + #ifdef BOUNDS_CHECKING + x1 = (x1 > 32767) ? 32767 : (x1 < -32768) ? -32768 : x1; + x2 = (x2 > 32767) ? 32767 : (x2 < -32768) ? -32768 : x2; + x3 = (x3 > 32767) ? 32767 : (x3 < -32768) ? -32768 : x3; + x4 = (x4 > 32767) ? 32767 : (x4 < -32768) ? -32768 : x4; + #endif + + *dste++ = x1; + *dste++ = x2; + *dste++ = x1; + *dste++ = x2; + *dste++ = x1; + *dste++ = x2; + *dste++ = x1; + *dste++ = x2; + + *dste++ = x3; + *dste++ = x4; + *dste++ = x3; + *dste++ = x4; + *dste++ = x3; + *dste++ = x4; + *dste++ = x3; + *dste++ = x4; + } + } + + for(; remain; remain--) + { x1 = *srce++ >> BITSHIFT; + #ifdef BOUNDS_CHECKING + x1 = (x1 > 32767) ? 32767 : (x1 < -32768) ? -32768 : x1; + #endif + *dste = x1; + if (md_mixshift == 1) + *(dste + 2) = x1; + if (md_mixshift == 2) { + *(dste + 4) = x1; + *(dste + 6) = x1; + } + dste++; + } +} + +// A faire pour supporter md_mixshift +static void Mix32To8(SBYTE *dste, SLONG *srce, SLONG count) +{ + int x1, x2, x3, x4; + int remain; + + remain = count & 3; + + for(count>>=2; count; count--) + { x1 = *srce++ >> (BITSHIFT + 8); + x2 = *srce++ >> (BITSHIFT + 8); + x3 = *srce++ >> (BITSHIFT + 8); + x4 = *srce++ >> (BITSHIFT + 8); + + #ifdef BOUNDS_CHECKING + x1 = (x1 > 127) ? 127 : (x1 < -128) ? -128 : x1; + x2 = (x2 > 127) ? 127 : (x2 < -128) ? -128 : x2; + x3 = (x3 > 127) ? 127 : (x3 < -128) ? -128 : x3; + x4 = (x4 > 127) ? 127 : (x4 < -128) ? -128 : x4; + #endif + + *dste++ = x1 + 128; + *dste++ = x2 + 128; + *dste++ = x3 + 128; + *dste++ = x4 + 128; + } + + for(; remain; remain--) + { x1 = *srce++ >> (BITSHIFT + 8); + #ifdef BOUNDS_CHECKING + x1 = (x1 > 127) ? 127 : (x1 < -128) ? -128 : x1; + #endif + *dste++ = x1 + 128; + } +} + + +static ULONG samples2bytes(ULONG samples) +{ + if(vc_mode & DMODE_16BITS) samples <<= 1; + if(vc_mode & DMODE_STEREO) samples <<= 1; + return samples; +} + + +static ULONG bytes2samples(ULONG bytes) +{ + if(vc_mode & DMODE_16BITS) bytes >>= 1; + if(vc_mode & DMODE_STEREO) bytes >>= 1; + return bytes; +} + + +static void AddChannel(SLONG *ptr, SLONG todo) +{ + SLONG end, done; +#ifdef __FASTMIXER__ + SBYTE *s; +#else + SWORD *s; +#endif + + if((s=Samples[vnf->handle]) == NULL) + { vnf->current = 0; + vnf->active = 0; + return; + } + + while(todo > 0) + { // update the 'current' index so the sample loops, or + // stops playing if it reached the end of the sample + + if(vnf->flags & SF_REVERSE) + { + // The sample is playing in reverse + + if((vnf->flags & SF_LOOP) && (vnf->current < idxlpos)) + { + // the sample is looping, and it has + // reached the loopstart index + + if(vnf->flags & SF_BIDI) + { + // sample is doing bidirectional loops, so 'bounce' + // the current index against the idxlpos + + vnf->current = idxlpos + (idxlpos - vnf->current); + vnf->flags &= ~SF_REVERSE; + vnf->increment = -vnf->increment; + } else + // normal backwards looping, so set the + // current position to loopend index + + vnf->current = idxlend - (idxlpos-vnf->current); + } else + { + // the sample is not looping, so check + // if it reached index 0 + + if(vnf->current < 0) + { + // playing index reached 0, so stop + // playing this sample + + vnf->current = 0; + vnf->active = 0; + break; + } + } + } else + { + // The sample is playing forward + + if((vnf->flags & SF_LOOP) && (vnf->current > idxlend)) + { + // the sample is looping, so check if + // it reached the loopend index + + if(vnf->flags & SF_BIDI) + { + // sample is doing bidirectional loops, so 'bounce' + // the current index against the idxlend + + vnf->flags |= SF_REVERSE; + vnf->increment = -vnf->increment; + vnf->current = idxlend - (vnf->current-idxlend); + } else + // normal backwards looping, so set the + // current position to loopend index + + vnf->current = idxlpos + (vnf->current-idxlend); + } else + { + // sample is not looping, so check + // if it reached the last position + + if(vnf->current > idxsize) + { + // yes, so stop playing this sample + + vnf->current = 0; + vnf->active = 0; + break; + } + } + } + + end = (vnf->flags & SF_REVERSE) ? + (vnf->flags & SF_LOOP) ? idxlpos : 0 : + (vnf->flags & SF_LOOP) ? idxlend : idxsize; + + done = MIN((end - vnf->current) / vnf->increment + 1, todo); + + if(!done) + { vnf->active = 0; + break; + } + + if(vnf->vol) + { +#ifdef __ASSEMBLY__ + if(md_mode & DMODE_INTERP) //&& ((vnf->increment >> (FRACBITS+1)) == 0)) + { if(vc_mode & DMODE_STEREO) + if((vnf->pan == PAN_SURROUND) && (vc_mode & DMODE_SURROUND)) + AsmSurroundInterp(s,ptr,vnf->current,vnf->increment,done); + else + AsmStereoInterp(s,ptr,vnf->current,vnf->increment,done); + else + AsmMonoInterp(s,ptr,vnf->current,vnf->increment,done); + } else if(vc_mode & DMODE_STEREO) + if((vnf->pan == PAN_SURROUND) && (vc_mode & DMODE_SURROUND)) + AsmSurroundNormal(s,ptr,vnf->current,vnf->increment,done); + else + AsmStereoNormal(s,ptr,vnf->current,vnf->increment,done); + else + AsmMonoNormal(s,ptr,vnf->current,vnf->increment,done); + + vnf->current += (vnf->increment*done); +#else + if((md_mode & DMODE_INTERP)) // && ((vnf->increment & ((1ul<<30)-1)) < (FRACMASK<<1))) + { if(vc_mode & DMODE_STEREO) + if((vnf->pan == PAN_SURROUND) && (vc_mode & DMODE_SURROUND)) + vnf->current = MixSurroundInterp(s,ptr,vnf->current,vnf->increment,done); + else + vnf->current = MixStereoInterp(s,ptr,vnf->current,vnf->increment,done); + else + vnf->current = MixMonoInterp(s,ptr,vnf->current,vnf->increment,done); + } else if(vc_mode & DMODE_STEREO) + if((vnf->pan == PAN_SURROUND) && (vc_mode & DMODE_SURROUND)) + vnf->current = MixSurroundNormal(s,ptr,vnf->current,vnf->increment,done); + else + vnf->current = MixStereoNormal(s,ptr,vnf->current,vnf->increment,done); + else + vnf->current = MixMonoNormal(s,ptr,vnf->current,vnf->increment,done); +#endif + } + + todo -= done; + ptr += (vc_mode & DMODE_STEREO) ? (done<<1) : done; + } + +} + + +void VC_WriteSamples(SBYTE *buf, ULONG todo) +{ + int left, portion = 0, count; + SBYTE *buffer; + int t; + int pan, vol; + + while(todo) + { if(TICKLEFT==0) + { if(vc_mode & DMODE_SOFT_MUSIC) md_player(); + TICKLEFT = (md_mixfreq * 125l) / (md_bpm * 50L); + } + + left = MIN(TICKLEFT, todo); + + buffer = buf; + TICKLEFT -= left; + todo -= left; + + buf += samples2bytes(left) << md_mixshift; + + while(left) + { portion = MIN(left, samplesthatfit); + count = (vc_mode & DMODE_STEREO) ? (portion<<1) : portion; + + memset(VC_TICKBUF, 0, count<<2); + + for(t=0; tkick) + { vnf->current = vnf->start << FRACBITS; + vnf->kick = 0; + vnf->active = 1; + } + + if((vnf->frq == 0) || (vnf->size == 0)) vnf->active = 0; + + if(vnf->active) + { vnf->increment = (vnf->frq << FRACBITS) / md_mixfreq; + if(vnf->flags & SF_REVERSE) vnf->increment =- vnf->increment; + vol = vnf->vol; pan = vnf->pan; + + if(vc_mode & DMODE_STEREO) + { if(pan != PAN_SURROUND) + { + #ifdef __FASTMIXER__ + lvoltab = voltab[(vol * (255-pan)) / 1024]; + rvoltab = voltab[(vol * pan) / 1024]; + #else + lvolsel = (vol * (255-pan)) >> 8; + rvolsel = (vol * pan) >> 8; + #endif + } else + { + #ifdef __FASTMIXER__ + lvoltab = voltab[(vol+1)>>3]; + #else + lvolsel = vol/2; + #endif + } + } else + { + #ifdef __FASTMIXER__ + lvoltab = voltab[vol>>2]; + #else + lvolsel = vol; + #endif + } + + idxsize = (vnf->size) ? (vnf->size << FRACBITS)-1 : 0; + idxlend = (vnf->repend) ? (vnf->repend << FRACBITS)-1 : 0; + idxlpos = vnf->reppos << FRACBITS; + AddChannel(VC_TICKBUF, portion); + } + } + + if(md_reverb) MixReverb(VC_TICKBUF, portion); + + if(vc_mode & DMODE_16BITS) + Mix32To16((SWORD *) buffer, VC_TICKBUF, count); + else + Mix32To8((SBYTE *) buffer, VC_TICKBUF, count); + + buffer += samples2bytes(portion) << md_mixshift; + left -= portion; + } + } +} + + +void VC_SilenceBytes(SBYTE *buf, ULONG todo) + +// Fill the buffer with 'todo' bytes of silence (it depends on the mixing +// mode how the buffer is filled) + +{ + // clear the buffer to zero (16 bits + // signed ) or 0x80 (8 bits unsigned) + + todo <<= md_mixshift; + + if(vc_mode & DMODE_16BITS) + memset(buf,0,todo); + else + memset(buf,0x80,todo); +} + + +ULONG VC_WriteBytes(SBYTE *buf, ULONG todo) + +// Writes 'todo' mixed SBYTES (!!) to 'buf'. It returns the number of +// SBYTES actually written to 'buf' (which is rounded to number of samples +// that fit into 'todo' bytes). + +{ + todo >>= md_mixshift; + + if(vc_softchn == 0) + { VC_SilenceBytes(buf,todo); + return todo; + } + + todo = bytes2samples(todo); + VC_WriteSamples(buf,todo); + + return samples2bytes(todo); +} + + +BOOL VC_Init(void) +{ + +#ifdef __FASTMIXER__ + int t; + + _mm_errno = MMERR_INITIALIZING_MIXER; + if((voltab = (SLONG **)calloc(65,sizeof(SLONG *))) == NULL) return 1; + for(t=0; t<65; t++) + if((voltab[t] = (SLONG *)calloc(256,sizeof(SLONG))) == NULL) return 1; + + if((Samples = (SBYTE **)calloc(MAXSAMPLEHANDLES, sizeof(SBYTE *))) == NULL) return 1; +#else + _mm_errno = MMERR_INITIALIZING_MIXER; + if((Samples = (SWORD **)calloc(MAXSAMPLEHANDLES, sizeof(SWORD *))) == NULL) return 1; +#endif + + if(VC_TICKBUF==NULL) if((VC_TICKBUF=(SLONG *)malloc((TICKLSIZE+32) * sizeof(SLONG))) == NULL) return 1; + + MixReverb = (md_mode & DMODE_STEREO) ? MixReverb_Stereo : MixReverb_Normal; + + //if(md_mode & DMODE_INTERP) md_mode &= ~DMODE_INTERP; + vc_mode = md_mode; + + _mm_errno = 0; + return 0; +} + + +void VC_Exit(void) +{ +#ifdef __FASTMIXER__ + int t; + if(voltab!=NULL) + { for(t=0; t<65; t++) if(voltab[t]!=NULL) free(voltab[t]); + free(voltab); voltab = NULL; + } +#endif + + //if(VC_TICKBUF!=NULL) free(VC_TICKBUF); + if(vinf!=NULL) free(vinf); + if(Samples!=NULL) free(Samples); + + //VC_TICKBUF = NULL; + vinf = NULL; + Samples = NULL; +} + + +BOOL VC_PlayStart(void) +{ + int numchn; + + numchn = md_softchn; +#ifdef __FASTMIXER__ + if(numchn > 0) + { + int c, t; + SLONG volmul; + + for(t=0; t<65; t++) + { volmul = (65536l*t) / 64; + for(c=-128; c<128; c++) + voltab[t][(UBYTE)c] = (SLONG)c*volmul; + } + } +#endif + + samplesthatfit = TICKLSIZE; + if(vc_mode & DMODE_STEREO) samplesthatfit >>= 1; + TICKLEFT = 0; + +#ifdef __FAST_REVERB__ + RVc1 = (5000L * md_mixfreq) / (REVERBERATION * 2); + RVc2 = (5946L * md_mixfreq) / (REVERBERATION * 2); + RVc3 = (7071L * md_mixfreq) / (REVERBERATION * 2); + RVc4 = (8409L * md_mixfreq) / (REVERBERATION * 2); +#else + RVc1 = (5000L * md_mixfreq) / REVERBERATION; + RVc2 = (5078L * md_mixfreq) / REVERBERATION; + RVc3 = (5313L * md_mixfreq) / REVERBERATION; + RVc4 = (5703L * md_mixfreq) / REVERBERATION; + RVc5 = (6250L * md_mixfreq) / REVERBERATION; + RVc6 = (6953L * md_mixfreq) / REVERBERATION; + RVc7 = (7813L * md_mixfreq) / REVERBERATION; + RVc8 = (8828L * md_mixfreq) / REVERBERATION; +#endif + + if((RVbuf1 = (SLONG *)_mm_calloc((RVc1+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf2 = (SLONG *)_mm_calloc((RVc2+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf3 = (SLONG *)_mm_calloc((RVc3+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf4 = (SLONG *)_mm_calloc((RVc4+1),sizeof(SLONG))) == NULL) return 1; +#ifndef __FAST_REVERB__ + if((RVbuf5 = (SLONG *)_mm_calloc((RVc5+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf6 = (SLONG *)_mm_calloc((RVc6+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf7 = (SLONG *)_mm_calloc((RVc7+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf8 = (SLONG *)_mm_calloc((RVc8+1),sizeof(SLONG))) == NULL) return 1; +#endif + + if((RVbuf9 = (SLONG *)_mm_calloc((RVc1+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf10 = (SLONG *)_mm_calloc((RVc2+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf11 = (SLONG *)_mm_calloc((RVc3+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf12 = (SLONG *)_mm_calloc((RVc4+1),sizeof(SLONG))) == NULL) return 1; +#ifndef __FAST_REVERB__ + if((RVbuf13 = (SLONG *)_mm_calloc((RVc5+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf14 = (SLONG *)_mm_calloc((RVc6+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf15 = (SLONG *)_mm_calloc((RVc7+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf16 = (SLONG *)_mm_calloc((RVc8+1),sizeof(SLONG))) == NULL) return 1; +#endif + + RVRindex = 0; + + return 0; +} + + +void VC_PlayStop(void) +{ + if(RVbuf1 != NULL) free(RVbuf1); + if(RVbuf2 != NULL) free(RVbuf2); + if(RVbuf3 != NULL) free(RVbuf3); + if(RVbuf4 != NULL) free(RVbuf4); + if(RVbuf9 != NULL) free(RVbuf9); + if(RVbuf10 != NULL) free(RVbuf10); + if(RVbuf11 != NULL) free(RVbuf11); + if(RVbuf12 != NULL) free(RVbuf12); + + RVbuf1 = RVbuf2 = RVbuf3 = RVbuf4 = NULL; + RVbuf9 = RVbuf10 = RVbuf11 = RVbuf12 = NULL; + +#ifndef __FAST_REVERB__ + if(RVbuf5 != NULL) free(RVbuf5); + if(RVbuf6 != NULL) free(RVbuf6); + if(RVbuf7 != NULL) free(RVbuf7); + if(RVbuf8 != NULL) free(RVbuf8); + if(RVbuf13 != NULL) free(RVbuf13); + if(RVbuf14 != NULL) free(RVbuf14); + if(RVbuf15 != NULL) free(RVbuf15); + if(RVbuf16 != NULL) free(RVbuf16); + + RVbuf13 = RVbuf14 = RVbuf15 = RVbuf16 = NULL; + RVbuf5 = RVbuf6 = RVbuf7 = RVbuf8 = NULL; +#endif + +} + + +BOOL VC_SetNumVoices(void) +{ + int t; + + if((vc_softchn = md_softchn) == 0) return 0; + + if(vinf!=NULL) free(vinf); + if((vinf = _mm_calloc(sizeof(VINFO),vc_softchn)) == NULL) return 1; + + for(t=0; t> FRACBITS); +} + + +/************************************************** +*************************************************** +*************************************************** +**************************************************/ + + +void VC_SampleUnload(SWORD handle) +{ + free(Samples[handle]); + Samples[handle] = NULL; +} + + +SWORD VC_SampleLoad(SAMPLOAD *sload, int type) +{ + SAMPLE *s = sload->sample; + int handle; + ULONG t, length,loopstart,loopend; + + if(type==MD_HARDWARE) return -1; + + // Find empty slot to put sample address in + + for(handle=0; handlelength; + loopstart = s->loopstart; + loopend = s->loopend; + + SL_SampleSigned(sload); + +#ifdef __FASTMIXER__ + SL_Sample16to8(sload); + if((Samples[handle]=(SBYTE *)malloc(length+20))==NULL) + { _mm_errno = MMERR_SAMPLE_TOO_BIG; + return -1; + } + + // read sample into buffer. + SL_Load(Samples[handle],sload,length); +#else + SL_Sample8to16(sload); + if((Samples[handle]=(SWORD *)malloc((length+20)<<1))==NULL) + { _mm_errno = MMERR_SAMPLE_TOO_BIG; + return -1; + } + + // read sample into buffer. + SL_Load(Samples[handle],sload,length); +#endif + + + // Unclick samples: + + if(s->flags & SF_LOOP) + { if(s->flags & SF_BIDI) + for(t=0; t<16; t++) Samples[handle][loopend+t] = Samples[handle][(loopend-t)-1]; + else + for(t=0; t<16; t++) Samples[handle][loopend+t] = Samples[handle][t+loopstart]; + } else + for(t=0; t<16; t++) Samples[handle][t+length] = 0; + + return handle; +} + + +ULONG VC_SampleSpace(int type) +{ + return vc_memory; +} + + +ULONG VC_SampleLength(int type, SAMPLE *s) +{ +#ifdef __FASTMIXER__ + return s->length + 16; +#else + return (s->length * ((s->flags&SF_16BITS) ? 2 : 1)) + 16; +#endif +} + + +/************************************************** +*************************************************** +*************************************************** +**************************************************/ + + +ULONG VC_VoiceRealVolume(UBYTE voice) +{ + ULONG i,s,size; + int k,j; +#ifdef __FASTMIXER__ + SBYTE *smp; +#else + SWORD *smp; +#endif + SLONG t; + + t = vinf[voice].current>>FRACBITS; + if(vinf[voice].active==0) return 0; + + s = vinf[voice].handle; + size = vinf[voice].size; + + i=64; t-=64; k=0; j=0; + if(i>size) i = size; + if(t<0) t = 0; + if(t+i > size) t = size-i; + + i &= ~1; // make sure it's EVEN. + + smp = &Samples[s][t]; + for(; i; i--, smp++) + { if(k<*smp) k = *smp; + if(j>*smp) j = *smp; + } + +#ifdef __FASTMIXER__ + k = abs(k-j)<<8; +#else + k = abs(k-j); +#endif + + return k; +} + diff --git a/mikmod/virtch2.c b/mikmod/virtch2.c new file mode 100644 index 0000000..e2f833b --- /dev/null +++ b/mikmod/virtch2.c @@ -0,0 +1,1168 @@ +/* + +Name: VIRTCH2.C + +Description: + All-c sample mixing routines, using a 32 bits mixing buffer, interpolation, + and sample smoothing [improves sound quality and removes clicks]. + + Future Additions: + Low-Pass filter to remove annoying staticy buzz. + + +C Mixer Portability: + All Systems -- All compilers. + +Assembly Mixer Portability: + + MSDOS: BC(?) Watcom(y) DJGPP(y) + Win95: ? + Os2: ? + Linux: y + + (y) - yes + (n) - no (not possible or not useful) + (?) - may be possible, but not tested + +*/ + +#include +#include +#include "mikmod.h" + +// USE_64BIT_INTS : Uncomment this line only if you have a compiler / +// platform that supports 64 bit integers, and have the SLONGLONG +// and ULONGLONG typedefs proper in TDEFS.H. Otherwise, floating +// point math will be used. + +#define USE_64BIT_INTS + + +// Constant Definitions +// ====================================================================== + +// MAXVOL_FACTOR : Controls the maximum volume of the output data. +// All mixed data is divided by this number after mixing, so +// larger numbers result in quieter mixing. Smaller numbers +// will increase the likliness of distortion on loud modules. + +// REVERBERATION : Larger numbers result in shorter reverb duration. +// Longer reverb durations can cause unwanted static and make the +// reverb sound more like a crappy echo. + +// SAMPLING_SHIFT : Specified the shift multiplier which controls by how +// much the mixing rate is multiplied while mixing. Higher values +// can improve quality by smoothing the sound and reducing pops and +// clicks. Note, this is a shift value, so a value of 2 becomes a +// mixing-rate multiplier of 4, and a value of 3 = 8, etc. + +// FRACBITS : the number of bits per integer devoted to the fractional +// part of the number. Generally, this number should not be changed +// for any reason. + + +// IMPORTANT: All values below MUST ALWAYS be greater than 0! + +const unsigned int REVERBERATION = 11000; +const int MAXVOL_FACTOR = 512; +const unsigned int SAMPLING_SHIFT = 2; +const unsigned int FRACBITS = 28; +const unsigned int TICKLSIZE = 8192; +const unsigned int CLICK_SHIFT_BASE = 6; + +// Do not modify the following macros / constants + +#define SAMPLING_FACTOR (1l << SAMPLING_SHIFT) +#define FRACMASK ((1UL << FRACBITS) - 1UL) +#define TICKWSIZE (TICKLSIZE * 2) +#define TICKBSIZE (TICKWSIZE * 2) +#define CLICK_SHIFT (CLICK_SHIFT_BASE * SAMPLING_SHIFT) +#define CLICK_BUFFER (1L << CLICK_SHIFT) + + +#ifndef MIN +#define MIN(a,b) (((a)<(b)) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a,b) (((a)>(b))?(a):(b)) +#endif + +#ifdef USE_64BIT_INTS +typedef SLONGLONG FRACTYPE; +#else +#include +typedef double FRACTYPE; +#endif + + + +typedef struct +{ UBYTE kick; // =1 -> sample has to be restarted + UBYTE active; // =1 -> sample is playing + UWORD flags; // 16/8 bits looping/one-shot + SWORD handle; // identifies the sample + ULONG start; // start index + ULONG size; // samplesize + ULONG reppos; // loop start + ULONG repend; // loop end + ULONG frq; // current frequency + int vol; // current volume + int pan; // current panning position + + int click, rampvol; + SLONG lastvalL, lastvalR; + int lvolsel, rvolsel, // Volume factor .. range 0-255 + oldlvol, oldrvol; + + FRACTYPE current; // current index in the sample + FRACTYPE increment; // increment value +} VINFO; + + +static SWORD **Samples; + +static VINFO *vinf = NULL; +static VINFO *vnf; +static long samplesthatfit, TICKLEFT; +static long vc_memory = 0; +static int vc_softchn; +static FRACTYPE idxsize,idxlpos,idxlend; +static SLONG *VC2_TICKBUF = NULL; +static UWORD vc_mode; + + +// Reverb control variables +// ======================== + +static int RVc1, RVc2, RVc3, RVc4, RVc5, RVc6, RVc7, RVc8; +static ULONG RVRindex; + +// For Mono or Left Channel +static SLONG *RVbuf1 = NULL, *RVbuf2 = NULL, *RVbuf3 = NULL, + *RVbuf4 = NULL, *RVbuf5 = NULL, *RVbuf6 = NULL, + *RVbuf7 = NULL, *RVbuf8 = NULL; + +// For Stereo only (Right Channel) +static SLONG *RVbuf9 = NULL, *RVbuf10 = NULL, *RVbuf11 = NULL, + *RVbuf12 = NULL, *RVbuf13 = NULL, *RVbuf14 = NULL, + *RVbuf15 = NULL, *RVbuf16 = NULL; + + +#ifndef USE_64BIT_INTS + +// ============================================================== +// Floating point versions!! + +static double MixStereoNormal(SWORD *srce, SLONG *dest, double index, double increment, ULONG todo) +{ + SWORD sample; + double i, f; + + for(; todo; todo--) + { f = modf(index,&i); + sample = (srce[(SLONG)i] * (1.0-f)) + (srce[(SLONG)i+1] * f); + index += increment; + + if(vnf->rampvol) + { *dest++ += (long)(((((double)vnf->oldlvol * vnf->rampvol) + (vnf->lvolsel * (CLICK_BUFFER-vnf->rampvol))) * (double)sample) / (1<oldrvol * vnf->rampvol) + (vnf->rvolsel * (CLICK_BUFFER-vnf->rampvol))) * (double)sample) / (1<rampvol--; + } else if(vnf->click) + { *dest++ += (long)((((double)(vnf->lvolsel * (CLICK_BUFFER-vnf->click)) * (double)sample) + (vnf->lastvalL * vnf->click)) / (1<rvolsel * (CLICK_BUFFER-vnf->click)) * (double)sample) + (vnf->lastvalR * vnf->click)) / (1<click--; + } else + { *dest++ += vnf->lvolsel * sample; + *dest++ += vnf->rvolsel * sample; + } + } + + vnf->lastvalL = vnf->lvolsel * sample; + vnf->lastvalR = vnf->rvolsel * sample; + + return index; +} + + +static double MixStereoSurround(SWORD *srce, SLONG *dest, double index, double increment, ULONG todo) +{ + SWORD sample; + long whoop; + double i, f; + + for(dest--; todo; todo--) + { f = modf(index,&i); + sample = (srce[(SLONG)i] * (1.0-f)) + (srce[(SLONG)i+1] * f); + index += increment; + + if(vnf->rampvol) + { whoop = (long)((((double)(vnf->oldlvol * vnf->rampvol) + (vnf->lvolsel * (CLICK_BUFFER-vnf->rampvol))) * (double)sample) / (1<rampvol--; + } else if(vnf->click) + { whoop = (long)(((((double)vnf->lvolsel * (CLICK_BUFFER-vnf->click)) * (double)sample) + (vnf->lastvalL * vnf->click)) / (1<click--; + } else + { *dest++ += vnf->lvolsel * sample; + *dest++ -= vnf->rvolsel * sample; + } + } + + vnf->lastvalL = vnf->lvolsel * sample; + vnf->lastvalR = vnf->rvolsel * sample; + + return index; +} + + +static double MixMonoNormal(SWORD *srce, SLONG *dest, double index, double increment, SLONG todo) +{ + SWORD sample; + double i, f; + + for(; todo; todo--) + { f = modf(index,&i); + sample = (srce[(SLONG)i] * (1.0-f)) + (srce[(SLONG)i+1] * f); + index += increment; + + if(vnf->rampvol) + { *dest++ += (long)((((double)(vnf->oldlvol * vnf->rampvol) + (vnf->lvolsel * (CLICK_BUFFER-vnf->rampvol))) * (double)sample) / (1<rampvol--; + } else if(vnf->click) + { *dest++ += (long)(((((double)vnf->lvolsel * (CLICK_BUFFER-vnf->click)) * (double)sample) + (vnf->lastvalL * vnf->click)) / (1<click--; + } else + *dest++ += vnf->lvolsel * sample; + } + + vnf->lastvalL = vnf->lvolsel * sample; + + return index; +} + +#else + +// ============================= +// 64 bit integer versions! + +static SLONGLONG MixStereoNormal(SWORD *srce, SLONG *dest, SLONGLONG index, SLONGLONG increment, ULONG todo) +{ + SWORD sample; + + for(; todo; todo--) + { + sample = (SWORD)(((SLONGLONG)srce[index >> FRACBITS] * ((FRACMASK+1L) - (index & FRACMASK))) + + ((SLONGLONG)srce[(index >> FRACBITS)+1] * (index & FRACMASK)) >> FRACBITS); + index += increment; + + if(vnf->rampvol) + { *dest++ += (((SLONGLONG)(vnf->oldlvol * vnf->rampvol) + (vnf->lvolsel * (CLICK_BUFFER-vnf->rampvol))) * (SLONGLONG)sample) >> CLICK_SHIFT; + *dest++ += (((SLONGLONG)(vnf->oldrvol * vnf->rampvol) + (vnf->rvolsel * (CLICK_BUFFER-vnf->rampvol))) * (SLONGLONG)sample) >> CLICK_SHIFT; + vnf->rampvol--; + } else if(vnf->click) + { *dest++ += ((((SLONGLONG)vnf->lvolsel * (CLICK_BUFFER-vnf->click)) * (SLONGLONG)sample) + ((SLONGLONG)vnf->lastvalL * vnf->click)) >> CLICK_SHIFT; + *dest++ += ((((SLONGLONG)vnf->rvolsel * (CLICK_BUFFER-vnf->click)) * (SLONGLONG)sample) + ((SLONGLONG)vnf->lastvalR * vnf->click)) >> CLICK_SHIFT; + vnf->click--; + } else + { *dest++ += vnf->lvolsel * sample; + *dest++ += vnf->rvolsel * sample; + } + } + + vnf->lastvalL = vnf->lvolsel * sample; + vnf->lastvalR = vnf->rvolsel * sample; + + return index; +} + + +static SLONGLONG MixStereoSurround(SWORD *srce, SLONG *dest, SLONGLONG index, SLONGLONG increment, ULONG todo) +{ + SWORD sample; + long whoop; + + for(; todo; todo--) + { sample = (SWORD)(((SLONGLONG)srce[index >> FRACBITS] * ((FRACMASK+1L) - (index & FRACMASK))) + + ((SLONGLONG)srce[(index >> FRACBITS)+1] * (index & FRACMASK)) >> FRACBITS); + index += increment; + + if(vnf->rampvol) + { whoop = (((SLONGLONG)(vnf->oldlvol * vnf->rampvol) + (vnf->lvolsel * (CLICK_BUFFER-vnf->rampvol))) * (SLONGLONG)sample) >> CLICK_SHIFT; + *dest++ += whoop; + *dest++ -= whoop; + vnf->rampvol--; + } else if(vnf->click) + { whoop = ((((SLONGLONG)vnf->lvolsel * (CLICK_BUFFER-vnf->click)) * (SLONGLONG)sample) + ((SLONGLONG)vnf->lastvalL * vnf->click)) >> CLICK_SHIFT; + *dest++ += whoop; + *dest++ -= whoop; + vnf->click--; + } else + { *dest++ += vnf->lvolsel * sample; + *dest++ -= vnf->lvolsel * sample; + } + } + + vnf->lastvalL = vnf->lvolsel * sample; + vnf->lastvalR = vnf->lvolsel * sample; + + return index; +} + + +static SLONGLONG MixMonoNormal(SWORD *srce, SLONG *dest, SLONGLONG index, SLONGLONG increment, SLONG todo) +{ + SWORD sample; + + for(; todo; todo--) + { sample = (SWORD)((SLONGLONG)(srce[index >> FRACBITS] * ((FRACMASK+1L) - (index & FRACMASK))) + + ((SLONGLONG)srce[(index >> FRACBITS)+1] * (index & FRACMASK)) >> FRACBITS); + index += increment; + + if(vnf->rampvol) + { *dest++ += (((SLONGLONG)(vnf->oldlvol * vnf->rampvol) + (vnf->lvolsel * (CLICK_BUFFER-vnf->rampvol))) * (SLONGLONG)sample) >> CLICK_SHIFT; + vnf->rampvol--; + } else if(vnf->click) + { *dest++ += ((((SLONGLONG)vnf->lvolsel * (CLICK_BUFFER-vnf->click)) * (SLONGLONG)sample) + ((SLONGLONG)vnf->lastvalL * vnf->click)) >> CLICK_SHIFT; + vnf->click--; + } else + *dest++ += vnf->lvolsel * sample; + } + + vnf->lastvalL = vnf->lvolsel * sample; + + return index; +} + +#endif + +static void (*Mix32to16)(SWORD *dste, SLONG *srce, SLONG count); +static void (*Mix32to8)(SBYTE *dste, SLONG *srce, SLONG count); +static void (*MixReverb)(SLONG *srce, SLONG count); + + +static void MixReverb_Normal(SLONG *srce, SLONG count) +{ + SLONG speedup; + int ReverbPct; + unsigned int loc1, loc2, loc3, loc4, + loc5, loc6, loc7, loc8; + + ReverbPct = 58 + (md_reverb*4); + + loc1 = RVRindex % RVc1; + loc2 = RVRindex % RVc2; + loc3 = RVRindex % RVc3; + loc4 = RVRindex % RVc4; + loc5 = RVRindex % RVc5; + loc6 = RVRindex % RVc6; + loc7 = RVRindex % RVc7; + loc8 = RVRindex % RVc8; + + for(; count; count--) + { + // Compute the LEFT CHANNEL echo buffers! + + speedup = *srce >> 3; + + RVbuf1[loc1] = speedup + ((ReverbPct * RVbuf1[loc1]) / 128); + RVbuf2[loc2] = speedup + ((ReverbPct * RVbuf2[loc2]) / 128); + RVbuf3[loc3] = speedup + ((ReverbPct * RVbuf3[loc3]) / 128); + RVbuf4[loc4] = speedup + ((ReverbPct * RVbuf4[loc4]) / 128); + RVbuf5[loc5] = speedup + ((ReverbPct * RVbuf5[loc5]) / 128); + RVbuf6[loc6] = speedup + ((ReverbPct * RVbuf6[loc6]) / 128); + RVbuf7[loc7] = speedup + ((ReverbPct * RVbuf7[loc7]) / 128); + RVbuf8[loc8] = speedup + ((ReverbPct * RVbuf8[loc8]) / 128); + + // Prepare to compute actual finalized data! + + RVRindex++; + loc1 = RVRindex % RVc1; + loc2 = RVRindex % RVc2; + loc3 = RVRindex % RVc3; + loc4 = RVRindex % RVc4; + loc5 = RVRindex % RVc5; + loc6 = RVRindex % RVc6; + loc7 = RVRindex % RVc7; + loc8 = RVRindex % RVc8; + + // Left Channel! + + *srce++ += (RVbuf1[loc1] - RVbuf2[loc2] + RVbuf3[loc3] - RVbuf4[loc4] + + RVbuf5[loc5] - RVbuf6[loc6] + RVbuf7[loc7] - RVbuf8[loc8]); + } +} + + +static void MixReverb_Stereo(SLONG *srce, SLONG count) +{ + SLONG speedup; + int ReverbPct; + unsigned int loc1, loc2, loc3, loc4, + loc5, loc6, loc7, loc8; + + ReverbPct = 58 + (md_reverb*4); + + loc1 = RVRindex % RVc1; + loc2 = RVRindex % RVc2; + loc3 = RVRindex % RVc3; + loc4 = RVRindex % RVc4; + loc5 = RVRindex % RVc5; + loc6 = RVRindex % RVc6; + loc7 = RVRindex % RVc7; + loc8 = RVRindex % RVc8; + + for(; count; count--) + { + // Compute the LEFT CHANNEL echo buffers! + + speedup = *srce >> 3; + + RVbuf1[loc1] = speedup + ((ReverbPct * RVbuf1[loc1]) / 128); + RVbuf2[loc2] = speedup + ((ReverbPct * RVbuf2[loc2]) / 128); + RVbuf3[loc3] = speedup + ((ReverbPct * RVbuf3[loc3]) / 128); + RVbuf4[loc4] = speedup + ((ReverbPct * RVbuf4[loc4]) / 128); + RVbuf5[loc5] = speedup + ((ReverbPct * RVbuf5[loc5]) / 128); + RVbuf6[loc6] = speedup + ((ReverbPct * RVbuf6[loc6]) / 128); + RVbuf7[loc7] = speedup + ((ReverbPct * RVbuf7[loc7]) / 128); + RVbuf8[loc8] = speedup + ((ReverbPct * RVbuf8[loc8]) / 128); + + // Compute the RIGHT CHANNEL echo buffers! + + speedup = srce[1] >> 3; + + RVbuf9[loc1] = speedup + ((ReverbPct * RVbuf9[loc1]) / 128); + RVbuf10[loc2] = speedup + ((ReverbPct * RVbuf11[loc2]) / 128); + RVbuf11[loc3] = speedup + ((ReverbPct * RVbuf12[loc3]) / 128); + RVbuf12[loc4] = speedup + ((ReverbPct * RVbuf12[loc4]) / 128); + RVbuf13[loc5] = speedup + ((ReverbPct * RVbuf13[loc5]) / 128); + RVbuf14[loc6] = speedup + ((ReverbPct * RVbuf14[loc6]) / 128); + RVbuf15[loc7] = speedup + ((ReverbPct * RVbuf15[loc7]) / 128); + RVbuf16[loc8] = speedup + ((ReverbPct * RVbuf16[loc8]) / 128); + + // Prepare to compute actual finalized data! + + RVRindex++; + loc1 = RVRindex % RVc1; + loc2 = RVRindex % RVc2; + loc3 = RVRindex % RVc3; + loc4 = RVRindex % RVc4; + loc5 = RVRindex % RVc5; + loc6 = RVRindex % RVc6; + loc7 = RVRindex % RVc7; + loc8 = RVRindex % RVc8; + + // Left Channel! + + *srce++ += RVbuf1[loc1] - RVbuf2[loc2] + RVbuf3[loc3] - RVbuf4[loc4] + + RVbuf5[loc5] - RVbuf6[loc6] + RVbuf7[loc7] - RVbuf8[loc8]; + + // Right Channel! + + *srce++ += RVbuf9[loc1] - RVbuf10[loc2] + RVbuf11[loc3] - RVbuf12[loc4] + + RVbuf13[loc5] - RVbuf14[loc6] + RVbuf15[loc7] - RVbuf16[loc8]; + } +} + + +static void Mix32To16_Normal(SWORD *dste, SLONG *srce, SLONG count) +{ + SLONG x1, x2, tmpx; + int i; + SWORD tmp; + + for(count/=SAMPLING_FACTOR; count; count--) + { tmpx = 0; + + for(i=SAMPLING_FACTOR/2; i; i--) + { x1 = *srce++ / MAXVOL_FACTOR; + x2 = *srce++ / MAXVOL_FACTOR; + + x1 = (x1 > 32767) ? 32767 : (x1 < -32768) ? -32768 : x1; + x2 = (x2 > 32767) ? 32767 : (x2 < -32768) ? -32768 : x2; + + tmpx += x1 + x2; + } + + tmp = tmpx / SAMPLING_FACTOR; + *dste++ = tmp; + if (md_mixshift == 1) + *dste++ = tmp; + if (md_mixshift == 2) { + *dste++ = tmp; + *dste++ = tmp; + } + } +} + + +static void Mix32To16_Stereo(SWORD *dste, SLONG *srce, SLONG count) +{ + SLONG x1, x2, x3, x4, tmpx, tmpy; + int i; + SWORD tmp1, tmp2; + + for(count/=SAMPLING_FACTOR; count; count--) + { tmpx = tmpy = 0; + + for(i=SAMPLING_FACTOR/2; i; i--) + { x1 = *srce++ / MAXVOL_FACTOR; + x2 = *srce++ / MAXVOL_FACTOR; + x3 = *srce++ / MAXVOL_FACTOR; + x4 = *srce++ / MAXVOL_FACTOR; + + x1 = (x1 > 32767) ? 32767 : (x1 < -32768) ? -32768 : x1; + x2 = (x2 > 32767) ? 32767 : (x2 < -32768) ? -32768 : x2; + x3 = (x3 > 32767) ? 32767 : (x3 < -32768) ? -32768 : x3; + x4 = (x4 > 32767) ? 32767 : (x4 < -32768) ? -32768 : x4; + + tmpx += x1 + x3; + tmpy += x2 + x4; + } + + tmp1 = tmpx / SAMPLING_FACTOR; + tmp2 = tmpy / SAMPLING_FACTOR; + *dste++ = tmp1; + *dste++ = tmp2; + if (md_mixshift == 1) { + *dste++ = tmp1; + *dste++ = tmp2; + } + if (md_mixshift == 2) { + *dste++ = tmp1; + *dste++ = tmp2; + *dste++ = tmp1; + *dste++ = tmp2; + } + } +} + + +static void Mix32To8_Normal(SBYTE *dste, SLONG *srce, SLONG count) +{ + int x1, x2; + int i, tmpx; + SBYTE tmp; + + for(count/=SAMPLING_FACTOR; count; count--) + { tmpx = 0; + + for(i=SAMPLING_FACTOR/2; i; i--) + { x1 = *srce++ / (MAXVOL_FACTOR * 256); + x2 = *srce++ / (MAXVOL_FACTOR * 256); + + x1 = (x1 > 127) ? 127 : (x1 < -128) ? -128 : x1; + x2 = (x2 > 127) ? 127 : (x2 < -128) ? -128 : x2; + + tmpx += x1 + x2; + } + + tmp = (tmpx / SAMPLING_FACTOR) + 128; + *dste++ = tmp; + if (md_mixshift == 1) + *dste++ = tmp; + else if (md_mixshift == 2) { + *dste++ = tmp; + *dste++ = tmp; + } + } +} + + +static void Mix32To8_Stereo(SBYTE *dste, SLONG *srce, SLONG count) +{ + int x1, x2, x3, x4; + int i, tmpx, tmpy; + SBYTE tmp1, tmp2; + + for(count/=SAMPLING_FACTOR; count; count--) + { tmpx = tmpy = 0; + + for(i=SAMPLING_FACTOR/2; i; i--) + { x1 = *srce++ / (MAXVOL_FACTOR * 256); + x2 = *srce++ / (MAXVOL_FACTOR * 256); + x3 = *srce++ / (MAXVOL_FACTOR * 256); + x4 = *srce++ / (MAXVOL_FACTOR * 256); + + x1 = (x1 > 127) ? 127 : (x1 < -128) ? -128 : x1; + x2 = (x2 > 127) ? 127 : (x2 < -128) ? -128 : x2; + x3 = (x3 > 127) ? 127 : (x3 < -128) ? -128 : x3; + x4 = (x4 > 127) ? 127 : (x4 < -128) ? -128 : x4; + + tmpx += x1 + x3; + tmpy += x2 + x4; + } + + tmp1 = (tmpx / SAMPLING_FACTOR) + 128; + tmp2 = (tmpy / SAMPLING_FACTOR) + 128; + *dste++ = tmp1; + *dste++ = tmp2; + if (md_mixshift == 1) { + *dste++ = tmp1; + *dste++ = tmp2; + } + else if (md_mixshift == 2) { + *dste++ = tmp1; + *dste++ = tmp2; + *dste++ = tmp1; + *dste++ = tmp2; + } + } +} + + +static ULONG samples2bytes(ULONG samples) +{ + if(vc_mode & DMODE_16BITS) samples <<= 1; + if(vc_mode & DMODE_STEREO) samples <<= 1; + + return samples; +} + + +static ULONG bytes2samples(ULONG bytes) +{ + if(vc_mode & DMODE_16BITS) bytes >>= 1; + if(vc_mode & DMODE_STEREO) bytes >>= 1; + + return bytes; +} + + +static void AddChannel(SLONG *ptr, SLONG todo) +{ + FRACTYPE end; + SLONG done; + SWORD *s; + + if(!(s=Samples[vnf->handle])) + { vnf->current = 0; + vnf->active = 0; + + vnf->lastvalL = 0; + vnf->lastvalR = 0; + + return; + } + + while(todo > 0) + { // update the 'current' index so the sample loops, or + // stops playing if it reached the end of the sample + + if(vnf->flags & SF_REVERSE) + { + // The sample is playing in reverse + + if((vnf->flags & SF_LOOP) && (vnf->current < idxlpos)) + { + // the sample is looping, and it has + // reached the loopstart index + + if(vnf->flags & SF_BIDI) + { + // sample is doing bidirectional loops, so 'bounce' + // the current index against the idxlpos + + vnf->current = idxlpos + (idxlpos - vnf->current); + vnf->flags &= ~SF_REVERSE; + vnf->increment = -vnf->increment; + } else + // normal backwards looping, so set the + // current position to loopend index + + vnf->current = idxlend - (idxlpos-vnf->current); + } else + { + // the sample is not looping, so check + // if it reached index 0 + + if(vnf->current < 0) + { + // playing index reached 0, so stop + // playing this sample + + vnf->current = 0; + vnf->active = 0; + break; + } + } + } else + { + // The sample is playing forward + + if((vnf->flags & SF_LOOP) && (vnf->current > idxlend)) + { + // the sample is looping, so check if + // it reached the loopend index + + if(vnf->flags & SF_BIDI) + { + // sample is doing bidirectional loops, so 'bounce' + // the current index against the idxlend + + vnf->flags |= SF_REVERSE; + vnf->increment = -vnf->increment; + vnf->current = idxlend - (vnf->current-idxlend); + } else + // normal backwards looping, so set the + // current position to loopend index + + vnf->current = idxlpos + (vnf->current-idxlend); + } else + { + // sample is not looping, so check + // if it reached the last position + + if(vnf->current > idxsize) + { + // yes, so stop playing this sample + + vnf->current = 0; + vnf->active = 0; + break; + } + } + } + + end = (FRACTYPE)(vnf->flags & SF_REVERSE) ? + (vnf->flags & SF_LOOP) ? idxlpos : 0 : + (vnf->flags & SF_LOOP) ? idxlend : idxsize; + + done = MIN((end - vnf->current) / vnf->increment + 1, todo); + + if(!done) + { vnf->active = 0; + break; + } + + if(vnf->vol || vnf->rampvol) + { if(vc_mode & DMODE_STEREO) + if((vnf->pan == PAN_SURROUND) && (vc_mode & DMODE_SURROUND)) + vnf->current = MixStereoSurround(s,ptr,vnf->current,vnf->increment,done); + else + vnf->current = MixStereoNormal(s,ptr,vnf->current,vnf->increment,done); + else + vnf->current = MixMonoNormal(s,ptr,vnf->current,vnf->increment,done); + } else + { vnf->lastvalL = 0; + vnf->lastvalR = 0; + } + + todo -= done; + ptr += (vc_mode & DMODE_STEREO) ? (done<<1) : done; + } +} + + +void VC2_WriteSamples(SBYTE *buf, long todo) +{ + int left, portion = 0; + SBYTE *buffer; + int t; + int pan, vol; + + todo *= SAMPLING_FACTOR; + + while(todo) + { if(TICKLEFT==0) + { if(vc_mode & DMODE_SOFT_MUSIC) md_player(); + TICKLEFT = (md_mixfreq * 125l * SAMPLING_FACTOR) / (md_bpm * 50l); + TICKLEFT &= ~(SAMPLING_FACTOR-1); + } + + left = MIN(TICKLEFT, todo); + + buffer = buf; + TICKLEFT -= left; + todo -= left; + + buf += (samples2bytes(left) / SAMPLING_FACTOR) << md_mixshift; + + while(left) + { portion = MIN(left, samplesthatfit); + memset(VC2_TICKBUF, 0, portion << ((vc_mode & DMODE_STEREO) ? 3 : 2)); + + for(t=0; tkick) + { + #ifdef USE_64BIT_INTS + vnf->current = (SLONGLONG)(vnf->start) << FRACBITS; + #else + vnf->current = (double)vnf->start; + #endif + + vnf->kick = 0; + vnf->active = 1; + vnf->click = CLICK_BUFFER; + vnf->rampvol = 0; + } + + if(vnf->frq == 0) vnf->active = 0; + + if(vnf->active) + { + #ifdef USE_64BIT_INTS + vnf->increment = ((SLONGLONG)(vnf->frq) << (FRACBITS-SAMPLING_SHIFT)) / (SLONGLONG)md_mixfreq; + #else + vnf->increment = ((double)(vnf->frq) / (1<flags & SF_REVERSE) vnf->increment = -vnf->increment; + + vol = vnf->vol; pan = vnf->pan; + + if(vc_mode & DMODE_STEREO) + { if(pan!=PAN_SURROUND) + { vnf->oldlvol = vnf->lvolsel; vnf->oldrvol = vnf->rvolsel; + vnf->lvolsel = (vol * (255-pan)) >> 8; + vnf->rvolsel = (vol * pan) >> 8; + } else + { vnf->oldlvol = vnf->lvolsel; + vnf->lvolsel = (vol * 256l) / 480; + } + } else + { vnf->oldlvol = vnf->lvolsel; + vnf->lvolsel = vol; + } + + #ifdef USE_64BIT_INTS + idxsize = (vnf->size) ? ((SLONGLONG)(vnf->size) << FRACBITS)-1 : 0; + idxlend = (vnf->repend) ? ((SLONGLONG)(vnf->repend) << FRACBITS)-1 : 0; + idxlpos = (SLONGLONG)(vnf->reppos) << FRACBITS; + #else + idxsize = (double)(vnf->size); // ? vnf->size : 0); + idxlend = (double)(vnf->repend); // ? vnf->repend : 0); + idxlpos = (double)(vnf->reppos); + #endif + AddChannel(VC2_TICKBUF, portion); + } + } + + if(md_reverb) MixReverb(VC2_TICKBUF, portion); + + if(vc_mode & DMODE_16BITS) + Mix32to16((SWORD *) buffer, VC2_TICKBUF, portion); + else + Mix32to8((SBYTE *) buffer, VC2_TICKBUF, portion); + + buffer += (samples2bytes(portion) / SAMPLING_FACTOR) << md_mixshift; + left -= portion; + } + } +} + + +void VC2_SilenceBytes(SBYTE *buf, long todo) + +// Fill the buffer with 'todo' bytes of silence (it depends on the mixing +// mode how the buffer is filled) + +{ + // clear the buffer to zero (16 bits + // signed ) or 0x80 (8 bits unsigned) + + todo <<= md_mixshift; + if(vc_mode & DMODE_16BITS) + memset(buf,0,todo); + else + memset(buf,0x80,todo); +} + + +ULONG VC2_WriteBytes(SBYTE *buf, long todo) + +// Writes 'todo' mixed SBYTES (!!) to 'buf'. It returns the number of +// SBYTES actually written to 'buf' (which is rounded to number of samples +// that fit into 'todo' bytes). + +{ + todo >>= md_mixshift; + + if(vc_softchn == 0) + { VC2_SilenceBytes(buf,todo); + return todo; + } + + todo = bytes2samples(todo); + VC2_WriteSamples(buf,todo); + + return samples2bytes(todo); +} + + +BOOL VC2_PlayStart(void) +{ + md_mode |= DMODE_INTERP; + + samplesthatfit = TICKLSIZE; + if(vc_mode & DMODE_STEREO) samplesthatfit >>= 1; + TICKLEFT = 0; + +#ifndef USE_64BIT_INTS + RVc1 = (SLONG)(500.0 * md_mixfreq) / REVERBERATION; + RVc2 = (SLONG)(507.8125 * md_mixfreq) / REVERBERATION; + RVc3 = (SLONG)(531.25 * md_mixfreq) / REVERBERATION; + RVc4 = (SLONG)(570.3125 * md_mixfreq) / REVERBERATION; + RVc5 = (SLONG)(625.0 * md_mixfreq) / REVERBERATION; + RVc6 = (SLONG)(695.3125 * md_mixfreq) / REVERBERATION; + RVc7 = (SLONG)(781.25 * md_mixfreq) / REVERBERATION; + RVc8 = (SLONG)(882.8125 * md_mixfreq) / REVERBERATION; +#else + RVc1 = (5000L * md_mixfreq) / (REVERBERATION * 10); + RVc2 = (5078L * md_mixfreq) / (REVERBERATION * 10); + RVc3 = (5313L * md_mixfreq) / (REVERBERATION * 10); + RVc4 = (5703L * md_mixfreq) / (REVERBERATION * 10); + RVc5 = (6250L * md_mixfreq) / (REVERBERATION * 10); + RVc6 = (6953L * md_mixfreq) / (REVERBERATION * 10); + RVc7 = (7813L * md_mixfreq) / (REVERBERATION * 10); + RVc8 = (8828L * md_mixfreq) / (REVERBERATION * 10); +#endif + + if((RVbuf1 = (SLONG *)_mm_calloc((RVc1+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf2 = (SLONG *)_mm_calloc((RVc2+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf3 = (SLONG *)_mm_calloc((RVc3+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf4 = (SLONG *)_mm_calloc((RVc4+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf5 = (SLONG *)_mm_calloc((RVc5+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf6 = (SLONG *)_mm_calloc((RVc6+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf7 = (SLONG *)_mm_calloc((RVc7+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf8 = (SLONG *)_mm_calloc((RVc8+1),sizeof(SLONG))) == NULL) return 1; + + if((RVbuf9 = (SLONG *)_mm_calloc((RVc1+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf10 = (SLONG *)_mm_calloc((RVc2+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf11 = (SLONG *)_mm_calloc((RVc3+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf12 = (SLONG *)_mm_calloc((RVc4+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf13 = (SLONG *)_mm_calloc((RVc5+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf14 = (SLONG *)_mm_calloc((RVc6+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf15 = (SLONG *)_mm_calloc((RVc7+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf16 = (SLONG *)_mm_calloc((RVc8+1),sizeof(SLONG))) == NULL) return 1; + + RVRindex = 0; + return 0; +} + + +void VC2_PlayStop(void) +{ + if(RVbuf1 != NULL) free(RVbuf1); + if(RVbuf2 != NULL) free(RVbuf2); + if(RVbuf3 != NULL) free(RVbuf3); + if(RVbuf4 != NULL) free(RVbuf4); + if(RVbuf5 != NULL) free(RVbuf5); + if(RVbuf6 != NULL) free(RVbuf6); + if(RVbuf7 != NULL) free(RVbuf7); + if(RVbuf8 != NULL) free(RVbuf8); + if(RVbuf9 != NULL) free(RVbuf9); + if(RVbuf10 != NULL) free(RVbuf10); + if(RVbuf11 != NULL) free(RVbuf11); + if(RVbuf12 != NULL) free(RVbuf12); + if(RVbuf13 != NULL) free(RVbuf13); + if(RVbuf14 != NULL) free(RVbuf14); + if(RVbuf15 != NULL) free(RVbuf15); + if(RVbuf16 != NULL) free(RVbuf16); + + RVbuf1 = RVbuf2 = RVbuf3 = RVbuf4 = RVbuf5 = RVbuf6 = RVbuf7 = RVbuf8 = NULL; + RVbuf9 = RVbuf10 = RVbuf11 = RVbuf12 = RVbuf13 = RVbuf14 = RVbuf15 = RVbuf16 = NULL; +} + + +BOOL VC2_Init(void) +{ + _mm_errno = MMERR_INITIALIZING_MIXER; + if((Samples = (SWORD **)calloc(MAXSAMPLEHANDLES, sizeof(SWORD *))) == NULL) return 1; + if(VC2_TICKBUF==NULL) if((VC2_TICKBUF=(SLONG *)malloc((TICKLSIZE+32) * sizeof(SLONG))) == NULL) return 1; + + if(md_mode & DMODE_STEREO) + { Mix32to16 = Mix32To16_Stereo; + Mix32to8 = Mix32To8_Stereo; + MixReverb = MixReverb_Stereo; + } else + { Mix32to16 = Mix32To16_Normal; + Mix32to8 = Mix32To8_Normal; + MixReverb = MixReverb_Normal; + } + + md_mode |= DMODE_INTERP; + vc_mode = md_mode; + + _mm_errno = 0; + return 0; +} + + +void VC2_Exit(void) + +// Yay, the joys and fruits of C and C++ - +// Deallocation of arrays! + +{ + //if(VC2_TICKBUF!=NULL) free(VC2_TICKBUF); + if(vinf!=NULL) free(vinf); + if(Samples!=NULL) free(Samples); + +// VC2_TICKBUF = NULL; + vinf = NULL; + Samples = NULL; +} + + +BOOL VC2_SetNumVoices(void) +{ + int t; + + md_mode |= DMODE_INTERP; + + if((vc_softchn = md_softchn) == 0) return 0; + + if(vinf!=NULL) free(vinf); + if((vinf = _mm_calloc(sizeof(VINFO),vc_softchn)) == NULL) return 1; + + for(t=0; t 32) vinf[voice].rampvol = CLICK_BUFFER; + vinf[voice].vol = vol; +} + + +void VC2_VoiceSetFrequency(UBYTE voice, ULONG frq) +{ + vinf[voice].frq = frq; +} + + +void VC2_VoiceSetPanning(UBYTE voice, ULONG pan) +{ + if(abs((int)vinf[voice].pan - (int)pan) > 48) vinf[voice].rampvol = CLICK_BUFFER; + vinf[voice].pan = pan; +} + + +void VC2_VoicePlay(UBYTE voice, SWORD handle, ULONG start, ULONG size, ULONG reppos, ULONG repend, UWORD flags) +{ + vinf[voice].flags = flags; + vinf[voice].handle = handle; + vinf[voice].start = start; + vinf[voice].size = size; + vinf[voice].reppos = reppos; + vinf[voice].repend = repend; + vinf[voice].kick = 1; +} + + +void VC2_VoiceStop(UBYTE voice) +{ + vinf[voice].active = 0; +} + + +BOOL VC2_VoiceStopped(UBYTE voice) +{ + return(vinf[voice].active == 0); +} + + +void VC2_VoiceReleaseSustain(UBYTE voice) +{ + +} + + +SLONG VC2_VoiceGetPosition(UBYTE voice) +{ + #ifdef USE_64BIT_INTS + return(vinf[voice].current >> FRACBITS); + #else + return((SLONG)vinf[voice].current); + #endif +} + + +/************************************************** +*************************************************** +*************************************************** +**************************************************/ + + +void VC2_SampleUnload(SWORD handle) +{ + free(Samples[handle]); + Samples[handle] = NULL; +} + + +SWORD VC2_SampleLoad(SAMPLOAD *sload, int type) +{ + SAMPLE *s = sload->sample; + int handle; + ULONG t, length,loopstart,loopend; + + if(type==MD_HARDWARE) return -1; + + // Find empty slot to put sample address in + + for(handle=0; handlelength; + loopstart = s->loopstart; + loopend = s->loopend; + + SL_SampleSigned(sload); + SL_Sample8to16(sload); + + if((Samples[handle]=(SWORD *)malloc((length+20)<<1))==NULL) + { _mm_errno = MMERR_SAMPLE_TOO_BIG; + return -1; + } + + SL_Load(Samples[handle],sload,length); // read sample into buffer. + + // Unclick samples: + + if(s->flags & SF_LOOP) + { if(s->flags & SF_BIDI) + for(t=0; t<16; t++) Samples[handle][loopend+t] = Samples[handle][(loopend-t)-1]; + else + for(t=0; t<16; t++) Samples[handle][loopend+t] = Samples[handle][t+loopstart]; + } else + for(t=0; t<16; t++) Samples[handle][t+length] = 0; + + return handle; +} + + +ULONG VC2_SampleSpace(int type) +{ + return vc_memory; +} + + +ULONG VC2_SampleLength(int type, SAMPLE *s) +{ + return (s->length * ((s->flags & SF_16BITS) ? 2 : 1)) + 16; +} + + +/************************************************** +*************************************************** +*************************************************** +**************************************************/ + diff --git a/net.c b/net.c index f098d18..5ede1f9 100755 --- a/net.c +++ b/net.c @@ -1,582 +1,610 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "oslib.h" -#include "net.h" - -int oslLoadNetModules() -{ - sceUtilityLoadNetModule(PSP_NET_MODULE_COMMON); - sceUtilityLoadNetModule(PSP_NET_MODULE_INET); - sceUtilityLoadNetModule(PSP_NET_MODULE_PARSEURI); - sceUtilityLoadNetModule(PSP_NET_MODULE_PARSEHTTP); - sceUtilityLoadNetModule(PSP_NET_MODULE_HTTP); - sceUtilityLoadNetModule(PSP_NET_MODULE_SSL); - return 0; -} - - -int oslUnloadNetModules() -{ - sceUtilityUnloadNetModule(PSP_NET_MODULE_SSL); - sceUtilityUnloadNetModule(PSP_NET_MODULE_HTTP); - sceUtilityUnloadNetModule(PSP_NET_MODULE_PARSEHTTP); - sceUtilityUnloadNetModule(PSP_NET_MODULE_PARSEURI); - sceUtilityUnloadNetModule(PSP_NET_MODULE_INET); - sceUtilityUnloadNetModule(PSP_NET_MODULE_COMMON); - return 0; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -//Public API -/////////////////////////////////////////////////////////////////////////////////////////////////// -int oslIsWlanPowerOn(){ - return sceWlanDevIsPowerOn(); -} - - -int oslIsWlanConnected(){ - union SceNetApctlInfo apctlInfo; - - if(sceNetApctlGetInfo(PSP_NET_APCTL_INFO_IP, &apctlInfo) == 0) - return 1; - else - return 0; -} - -int oslGetNetConfigs(struct oslNetConfig *result){ - int index = 0; - netData name, ip; - - for (index=1; index= timeout){ - if (apctlCallback != NULL) - (*apctlCallback)(OSL_ERR_APCTL_TIMEOUT); - oslDisconnectFromAP(); - err = OSL_ERR_APCTL_TIMEOUT; - break; - } - int state; - err = sceNetApctlGetState(&state); - if (err){ - if (apctlCallback != NULL) - (*apctlCallback)(OSL_ERR_APCTL_GETSTATE); - oslDisconnectFromAP(); - err = OSL_ERR_APCTL_GETSTATE; - break; - } - if (state > stateLast){ - stateLast = state; - if (apctlCallback != NULL){ - if ((*apctlCallback)(state)){ - err = OSL_USER_ABORTED; - break; - } - } - } - if (state == PSP_NET_APCTL_STATE_GOT_IP) - break; // connected with static IP - sceKernelDelayThread(50*1000); - } - - return err; -} - -int oslDisconnectFromAP(){ - sceNetApctlDisconnect(); - return 0; -} - -int oslGetAPState(){ - int state; - int err = sceNetApctlGetState(&state); - if (err) - return OSL_ERR_APCTL_GETSTATE; - return state; -} - - -//The following functions are copied from PGE LUA source code: -//http://svn.luaplayer.org/pge/pgeNet.c -int oslResolveAddress(char *address, char *resolvedIP){ - struct hostent *host; - - if(!(host = gethostbyname(address))) - return OSL_ERR_RESOLVER_RESOLVING; - - sprintf(resolvedIP, inet_ntoa(*((struct in_addr *)host->h_addr))); - return 0; -} - - -int oslNetGetFile(const char *url, const char *filepath) -{ - int template, connection, request, ret, status, dataend, fd, byteswritten; - SceULong64 contentsize; - unsigned char readbuffer[8192]; - - ret = sceHttpInit(20000); - - if(ret < 0) - return OSL_ERR_HTTP_INIT; - - template = sceHttpCreateTemplate("OSL-agent/0.0.1 libhttp/1.0.0", 1, 1); - if(template < 0) - return OSL_ERR_HTTP_TEMPLATE; - - ret = sceHttpSetResolveTimeOut(template, 3000000); - if(ret < 0) - return OSL_ERR_HTTP_TIMEOUT; - - ret = sceHttpSetRecvTimeOut(template, 60000000); - if(ret < 0) - return OSL_ERR_HTTP_TIMEOUT; - - ret = sceHttpSetSendTimeOut(template, 60000000); - if(ret < 0) - return OSL_ERR_HTTP_TIMEOUT; - - connection = sceHttpCreateConnectionWithURL(template, url, 0); - if(connection < 0) - return OSL_ERR_HTTP_CONNECT; - - request = sceHttpCreateRequestWithURL(connection, PSP_HTTP_METHOD_GET, (char*)url, 0); - if(request < 0) - return OSL_ERR_HTTP_REQUEST; - - ret = sceHttpSendRequest(request, 0, 0); - if(ret < 0) - return OSL_ERR_HTTP_REQUEST; - - ret = sceHttpGetStatusCode(request, &status); - if(ret < 0) - return OSL_ERR_HTTP_GENERIC; - - if(status != 200) - return 0; - - ret = sceHttpGetContentLength(request, &contentsize); - if(ret < 0) - return OSL_ERR_HTTP_GENERIC; - - dataend = 0; - byteswritten = 0; - - fd = sceIoOpen(filepath, PSP_O_WRONLY | PSP_O_CREAT, 0777); - - while(dataend == 0) - { - ret = sceHttpReadData(request, readbuffer, 8192); - if(ret < 0) - { - sceIoWrite(fd, filepath, 4); - sceIoClose(fd); - return OSL_ERR_HTTP_GENERIC; - } - - if(ret == 0) - dataend = 1; - - if(ret > 0) - { - byteswritten += ret; - sceIoWrite(fd, readbuffer, ret); - } - } - - sceIoClose(fd); - sceHttpDeleteRequest(request); - sceHttpDeleteConnection(connection); - sceHttpDeleteTemplate(template); - sceHttpEnd(); - - return 0; -} - -int oslNetPostForm(const char *url, char *data, char *response, unsigned int responsesize) -{ - int template, connection, request, ret, status; - ret = sceHttpInit(20000); - if(ret < 0) - return OSL_ERR_HTTP_INIT; - - template = sceHttpCreateTemplate("OSL-agent/0.0.1 libhttp/1.0.0", 1, 1); - if(template < 0) - { - sceHttpEnd(); - return OSL_ERR_HTTP_TEMPLATE; - } - - ret = sceHttpSetResolveTimeOut(template, 3000000); - if(ret < 0) - { - sceHttpDeleteTemplate(template); - sceHttpEnd(); - return OSL_ERR_HTTP_TIMEOUT; - } - - ret = sceHttpSetRecvTimeOut(template, 60000000); - - if(ret < 0) - { - sceHttpDeleteTemplate(template); - sceHttpEnd(); - return OSL_ERR_HTTP_TIMEOUT; - } - - ret = sceHttpSetSendTimeOut(template, 60000000); - - if(ret < 0) - { - sceHttpDeleteTemplate(template); - sceHttpEnd(); - return OSL_ERR_HTTP_TIMEOUT; - } - - connection = sceHttpCreateConnectionWithURL(template, url, 0); - - if(connection < 0) - { - sceHttpDeleteTemplate(template); - sceHttpEnd(); - return OSL_ERR_HTTP_TIMEOUT; - } - - sceHttpEnableKeepAlive(connection); - request = sceHttpCreateRequestWithURL(connection, PSP_HTTP_METHOD_POST, (char*)url, strlen(data)); - if(request < 0) - { - sceHttpDeleteConnection(connection); - sceHttpDeleteTemplate(template); - sceHttpEnd(); - return OSL_ERR_HTTP_REQUEST; - } - - sceHttpAddExtraHeader(request, "Content-Type", "application/x-www-form-urlencoded", 0); - - ret = sceHttpSendRequest(request, data, strlen(data)); - if(ret < 0) - { - sceHttpDeleteRequest(request); - sceHttpDeleteConnection(connection); - sceHttpDeleteTemplate(template); - sceHttpEnd(); - return OSL_ERR_HTTP_REQUEST; - } - - ret = sceHttpGetStatusCode(request, &status); - if(ret < 0) - { - sceHttpDeleteRequest(request); - sceHttpDeleteConnection(connection); - sceHttpDeleteTemplate(template); - sceHttpEnd(); - return OSL_ERR_HTTP_GENERIC; - } - - if(status != 200) - { - sceHttpDeleteRequest(request); - sceHttpDeleteConnection(connection); - sceHttpDeleteTemplate(template); - sceHttpEnd(); - return OSL_ERR_HTTP_GENERIC; - } - - if(response != NULL && responsesize > 0) - { - ret = sceHttpReadData(request, response, responsesize); - if(ret < 0) - { - sceHttpDeleteRequest(request); - sceHttpDeleteConnection(connection); - sceHttpDeleteTemplate(template); - sceHttpEnd(); - return OSL_ERR_HTTP_GENERIC; - } - } - - sceHttpDeleteRequest(request); - sceHttpDeleteConnection(connection); - - sceHttpDeleteTemplate(template); - sceHttpEnd(); - - return 1; -} - -int oslNetSocketCreate(void) -{ - int sock; - - sock = socket(PF_INET, SOCK_STREAM, 0); - - if(sock < 0) - return -1; - - return sock; -} - -int oslNetSocketAccept(int socket) -{ - int sock; - - struct sockaddr_in client; - - socklen_t size; - - sock = accept(socket, (struct sockaddr *) &client, &size); - - if(sock < 0) - return -1; - - return sock; -} - -int oslNetSocketBind(int socket, unsigned short port) -{ - struct sockaddr_in addr; - - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_ANY); - - int error; - - error = bind(socket, (struct sockaddr *)&addr, sizeof(struct sockaddr)); - - if(error < 0) - return 0; - - return 1; -} - -int oslNetSocketListen(int socket, unsigned int maxconn) -{ - int error; - - error = listen(socket, maxconn); - - if(error < 0) - return 0; - - return 1; -} - -int oslNetSocketConnect(int socket, char *ip, unsigned short port) -{ - struct sockaddr_in addr; - - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - inet_aton(ip, &(addr.sin_addr)); - memset(&(addr.sin_zero), '\0', 8); - - if(connect(socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) - return 0; - - return 1; -} - -int oslNetSocketSend(int socket, const void *data, int length) -{ - int bytessent = send(socket, data, length, 0); - - return bytessent; -} - -int oslNetSocketReceive(int socket, void *data, int length) -{ - int bytesrecv = recv(socket, data, length, 0); - - return bytesrecv; -} - -void oslNetSocketClose(int socket) -{ - close(socket); -} - -void oslNetSocketSetClear(fd_set *set) -{ - FD_ZERO(set); -} - -void oslNetSocketSetAdd(int socket, fd_set *set) -{ - FD_SET(socket, set); -} - -void oslNetSocketSetRemove(int socket, fd_set *set) -{ - FD_CLR(socket, set); -} - -int oslNetSocketSetIsMember(int socket, fd_set *set) -{ - if(FD_ISSET(socket, set)) - return 1; - - return 0 ; -} - -int oslNetSocketSetSelect(unsigned int maxsockets, fd_set *set) -{ - // TODO: Add argument manipulation of timeout etc. - int numsockets; - struct timeval tv; - - tv.tv_sec = 0; - tv.tv_usec = 1000; - - numsockets = select(maxsockets, set, NULL, NULL, &tv); - - if(numsockets < 0) - return -1; - - return numsockets; -} +#include +#include +#include +#include +#include +#include +#include +#include +//#include //<-- STAS: included in net.h +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "oslib.h" +#include "net.h" + +static int networkIsActive = 0; //<-- STAS: network initialization flag + +int oslLoadNetModules() +{ + sceUtilityLoadNetModule(PSP_NET_MODULE_COMMON); + sceUtilityLoadNetModule(PSP_NET_MODULE_INET); + sceUtilityLoadNetModule(PSP_NET_MODULE_PARSEURI); + sceUtilityLoadNetModule(PSP_NET_MODULE_PARSEHTTP); + sceUtilityLoadNetModule(PSP_NET_MODULE_HTTP); + sceUtilityLoadNetModule(PSP_NET_MODULE_SSL); + return 0; +} + + +int oslUnloadNetModules() +{ + sceUtilityUnloadNetModule(PSP_NET_MODULE_SSL); + sceUtilityUnloadNetModule(PSP_NET_MODULE_HTTP); + sceUtilityUnloadNetModule(PSP_NET_MODULE_PARSEHTTP); + sceUtilityUnloadNetModule(PSP_NET_MODULE_PARSEURI); + sceUtilityUnloadNetModule(PSP_NET_MODULE_INET); + sceUtilityUnloadNetModule(PSP_NET_MODULE_COMMON); + return 0; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +//Public API +/////////////////////////////////////////////////////////////////////////////////////////////////// +int oslIsWlanPowerOn(){ + return sceWlanDevIsPowerOn(); +} + + +int oslIsWlanConnected(){ + union SceNetApctlInfo apctlInfo; + + if(sceNetApctlGetInfo(PSP_NET_APCTL_INFO_IP, &apctlInfo) == 0) + return 1; + else + return 0; +} + +int oslGetNetConfigs(struct oslNetConfig *result){ + int index = 0; + netData name, ip; + + for (index=1; index + +int oslNetInit() +{ + int res; + + oslLoadNetModules(); + res = sceNetInit(128*1024, 42, 4*1024, 42, 4*1024); + if (res < 0) + return OSL_NET_ERROR_NET; + + res = sceNetInetInit(); + if (res < 0) { + oslNetTermEx(1); + return OSL_NET_ERROR_INET; + } + + res = sceNetResolverInit(); + if (res < 0) + { + oslNetTermEx(2); + return OSL_NET_ERROR_RESOLVER; + } + + res = sceNetApctlInit(0x10000, 48); + if (res < 0) + { + oslNetTermEx(3); + return OSL_NET_ERROR_APCTL; + } + + res = sceSslInit(0x28000); + if (res < 0) + { + oslNetTermEx(4); + return OSL_NET_ERROR_SSL; + } + + res = sceHttpInit(0x25800); + if (res < 0) + { + oslNetTermEx(5); + return OSL_NET_ERROR_HTTP; + } + + res = sceHttpsInit(0, 0, 0, 0); + if (res < 0) + { + oslNetTermEx(6); + return OSL_NET_ERROR_HTTPS; + } + + res = sceHttpsLoadDefaultCert(0, 0); + if (res < 0) + { + oslNetTermEx(7); + return OSL_NET_ERROR_CERT; + } + + res = sceHttpLoadSystemCookie(); + if (res < 0) + { + oslNetTermEx(7); + return OSL_NET_ERROR_COOKIE; + } + networkIsActive = 1; //<-- STAS: network is initialized marker + return 0; +} + + +int oslNetTerm() +{ + return oslNetTermEx(0); //<-- STAS: full deinitialization +} + +int oslGetIPaddress(char *IPaddress){ + union SceNetApctlInfo apctlInfo; + strcpy(IPaddress, ""); + if (sceNetApctlGetInfo(PSP_NET_APCTL_INFO_IP, &apctlInfo)) + return OSL_ERR_APCTL_GETINFO; + strcpy(IPaddress, apctlInfo.ip); + return 0; +} + + +int oslConnectToAP(int config, int timeout, + int (*apctlCallback)(int state)){ + int err = 0; + int stateLast = -1; + + if (!oslIsWlanPowerOn()) + return OSL_ERR_WLAN_OFF; + + err = sceNetApctlConnect(config); + if (err) + return OSL_ERR_APCTL_CONNECT; + + time_t startTime; + time_t currTime; + time(&startTime); + while (!osl_quit){ + //Check timeout: + time(&currTime); + if (currTime - startTime >= timeout){ + if (apctlCallback != NULL) + (*apctlCallback)(OSL_ERR_APCTL_TIMEOUT); + oslDisconnectFromAP(); + err = OSL_ERR_APCTL_TIMEOUT; + break; + } + int state; + err = sceNetApctlGetState(&state); + if (err){ + if (apctlCallback != NULL) + (*apctlCallback)(OSL_ERR_APCTL_GETSTATE); + oslDisconnectFromAP(); + err = OSL_ERR_APCTL_GETSTATE; + break; + } + if (state > stateLast){ + stateLast = state; + if (apctlCallback != NULL){ + if ((*apctlCallback)(state)){ + err = OSL_USER_ABORTED; + break; + } + } + } + if (state == PSP_NET_APCTL_STATE_GOT_IP) + break; // connected with static IP + sceKernelDelayThread(50*1000); + } + + return err; +} + +int oslDisconnectFromAP(){ + sceNetApctlDisconnect(); + return 0; +} + +int oslGetAPState(){ + int state; + int err = sceNetApctlGetState(&state); + if (err) + return OSL_ERR_APCTL_GETSTATE; + return state; +} + + +//The following functions are copied from PGE LUA source code: +//http://svn.luaplayer.org/pge/pgeNet.c +int oslResolveAddress(char *address, char *resolvedIP){ + struct hostent *host; + + if(!(host = gethostbyname(address))) + return OSL_ERR_RESOLVER_RESOLVING; + + sprintf(resolvedIP, inet_ntoa(*((struct in_addr *)host->h_addr))); + return 0; +} + + +int oslNetGetFile(const char *url, const char *filepath) +{ + int template, connection, request, ret, status, dataend, fd, byteswritten; + SceULong64 contentsize; + unsigned char readbuffer[8192]; +/* //<-- STAS: HTTP library was already initialized (see oslNetInit()) ! + ret = sceHttpInit(20000); + + if(ret < 0) + return OSL_ERR_HTTP_INIT; +*/ //<-- STAS END --> + template = sceHttpCreateTemplate("OSL-agent/0.0.1 libhttp/1.0.0", 1, 1); + if(template < 0) + return OSL_ERR_HTTP_TEMPLATE; + + ret = sceHttpSetResolveTimeOut(template, 3000000); + if(ret < 0) + return OSL_ERR_HTTP_TIMEOUT; + + ret = sceHttpSetRecvTimeOut(template, 60000000); + if(ret < 0) + return OSL_ERR_HTTP_TIMEOUT; + + ret = sceHttpSetSendTimeOut(template, 60000000); + if(ret < 0) + return OSL_ERR_HTTP_TIMEOUT; + + connection = sceHttpCreateConnectionWithURL(template, url, 0); + if(connection < 0) + return OSL_ERR_HTTP_CONNECT; + + request = sceHttpCreateRequestWithURL(connection, PSP_HTTP_METHOD_GET, (char*)url, 0); + if(request < 0) + return OSL_ERR_HTTP_REQUEST; + + ret = sceHttpSendRequest(request, 0, 0); + if(ret < 0) + return OSL_ERR_HTTP_REQUEST; + + ret = sceHttpGetStatusCode(request, &status); + if(ret < 0) + return OSL_ERR_HTTP_GENERIC; + + if(status != 200) + return 0; + + ret = sceHttpGetContentLength(request, &contentsize); + if(ret < 0) + return OSL_ERR_HTTP_GENERIC; + + dataend = 0; + byteswritten = 0; + + fd = sceIoOpen(filepath, PSP_O_WRONLY | PSP_O_CREAT, 0777); + + while(dataend == 0) + { + ret = sceHttpReadData(request, readbuffer, 8192); + if(ret < 0) + { + sceIoWrite(fd, filepath, 4); + sceIoClose(fd); + return OSL_ERR_HTTP_GENERIC; + } + + if(ret == 0) + dataend = 1; + + if(ret > 0) + { + byteswritten += ret; + sceIoWrite(fd, readbuffer, ret); + } + } + + sceIoClose(fd); + sceHttpDeleteRequest(request); + sceHttpDeleteConnection(connection); + sceHttpDeleteTemplate(template); +// sceHttpEnd(); //<-- STAS: This should be done in oslNetTerm() only ! + + return 0; +} + +int oslNetPostForm(const char *url, char *data, char *response, unsigned int responsesize) +{ + int template, connection, request, ret, status; +/* //<-- STAS: HTTP library was already initialized (see oslNetInit()) ! + ret = sceHttpInit(20000); + if(ret < 0) + return OSL_ERR_HTTP_INIT; +*/ //<-- STAS END --> + template = sceHttpCreateTemplate("OSL-agent/0.0.1 libhttp/1.0.0", 1, 1); + if(template < 0) + { + sceHttpEnd(); + return OSL_ERR_HTTP_TEMPLATE; + } + + ret = sceHttpSetResolveTimeOut(template, 3000000); + if(ret < 0) + { + sceHttpDeleteTemplate(template); + sceHttpEnd(); + return OSL_ERR_HTTP_TIMEOUT; + } + + ret = sceHttpSetRecvTimeOut(template, 60000000); + + if(ret < 0) + { + sceHttpDeleteTemplate(template); + sceHttpEnd(); + return OSL_ERR_HTTP_TIMEOUT; + } + + ret = sceHttpSetSendTimeOut(template, 60000000); + + if(ret < 0) + { + sceHttpDeleteTemplate(template); + sceHttpEnd(); + return OSL_ERR_HTTP_TIMEOUT; + } + + connection = sceHttpCreateConnectionWithURL(template, url, 0); + + if(connection < 0) + { + sceHttpDeleteTemplate(template); + sceHttpEnd(); + return OSL_ERR_HTTP_TIMEOUT; + } + + sceHttpEnableKeepAlive(connection); + request = sceHttpCreateRequestWithURL(connection, PSP_HTTP_METHOD_POST, (char*)url, strlen(data)); + if(request < 0) + { + sceHttpDeleteConnection(connection); + sceHttpDeleteTemplate(template); + sceHttpEnd(); + return OSL_ERR_HTTP_REQUEST; + } + + sceHttpAddExtraHeader(request, "Content-Type", "application/x-www-form-urlencoded", 0); + + ret = sceHttpSendRequest(request, data, strlen(data)); + if(ret < 0) + { + sceHttpDeleteRequest(request); + sceHttpDeleteConnection(connection); + sceHttpDeleteTemplate(template); + sceHttpEnd(); + return OSL_ERR_HTTP_REQUEST; + } + + ret = sceHttpGetStatusCode(request, &status); + if(ret < 0) + { + sceHttpDeleteRequest(request); + sceHttpDeleteConnection(connection); + sceHttpDeleteTemplate(template); + sceHttpEnd(); + return OSL_ERR_HTTP_GENERIC; + } + + if(status != 200) + { + sceHttpDeleteRequest(request); + sceHttpDeleteConnection(connection); + sceHttpDeleteTemplate(template); + sceHttpEnd(); + return OSL_ERR_HTTP_GENERIC; + } + + if(response != NULL && responsesize > 0) + { + ret = sceHttpReadData(request, response, responsesize); + if(ret < 0) + { + sceHttpDeleteRequest(request); + sceHttpDeleteConnection(connection); + sceHttpDeleteTemplate(template); + sceHttpEnd(); + return OSL_ERR_HTTP_GENERIC; + } + } + + sceHttpDeleteRequest(request); + sceHttpDeleteConnection(connection); + + sceHttpDeleteTemplate(template); +// sceHttpEnd(); //<-- STAS: This should be done in oslNetTerm() only ! + + return 1; +} + +int oslNetSocketCreate(void) +{ + int sock; + + sock = socket(PF_INET, SOCK_STREAM, 0); + + if(sock < 0) + return -1; + + return sock; +} + +int oslNetSocketAccept(int socket) +{ + int sock; + + struct sockaddr_in client; + + socklen_t size; + + sock = accept(socket, (struct sockaddr *) &client, &size); + + if(sock < 0) + return -1; + + return sock; +} + +int oslNetSocketBind(int socket, unsigned short port) +{ + struct sockaddr_in addr; + + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + int error; + + error = bind(socket, (struct sockaddr *)&addr, sizeof(struct sockaddr)); + + if(error < 0) + return 0; + + return 1; +} + +int oslNetSocketListen(int socket, unsigned int maxconn) +{ + int error; + + error = listen(socket, maxconn); + + if(error < 0) + return 0; + + return 1; +} + +int oslNetSocketConnect(int socket, char *ip, unsigned short port) +{ + struct sockaddr_in addr; + + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + inet_aton(ip, &(addr.sin_addr)); + memset(&(addr.sin_zero), '\0', 8); + + if(connect(socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) + return 0; + + return 1; +} + +int oslNetSocketSend(int socket, const void *data, int length) +{ + int bytessent = send(socket, data, length, 0); + + return bytessent; +} + +int oslNetSocketReceive(int socket, void *data, int length) +{ + int bytesrecv = recv(socket, data, length, 0); + + return bytesrecv; +} + +void oslNetSocketClose(int socket) +{ + close(socket); +} + +void oslNetSocketSetClear(fd_set *set) +{ + FD_ZERO(set); +} + +void oslNetSocketSetAdd(int socket, fd_set *set) +{ + FD_SET(socket, set); +} + +void oslNetSocketSetRemove(int socket, fd_set *set) +{ + FD_CLR(socket, set); +} + +int oslNetSocketSetIsMember(int socket, fd_set *set) +{ + if(FD_ISSET(socket, set)) + return 1; + + return 0 ; +} + +int oslNetSocketSetSelect(unsigned int maxsockets, fd_set *set) +{ + // TODO: Add argument manipulation of timeout etc. + int numsockets; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 1000; + + numsockets = select(maxsockets, set, NULL, NULL, &tv); + + if(numsockets < 0) + return -1; + + return numsockets; +} diff --git a/net.h b/net.h index 110fe31..65236c8 100755 --- a/net.h +++ b/net.h @@ -1,125 +1,141 @@ -#ifndef NET_H -#define NET_H - -#include - -/** @defgroup Network - - Network functions - @{ -*/ - -#define OSL_NET_ERROR_NET -1 -#define OSL_NET_ERROR_INET -2 -#define OSL_NET_ERROR_RESOLVER -3 -#define OSL_NET_ERROR_APCTL -4 -#define OSL_NET_ERROR_SSL -5 -#define OSL_NET_ERROR_HTTP -6 -#define OSL_NET_ERROR_HTTPS -7 -#define OSL_NET_ERROR_CERT -8 -#define OSL_NET_ERROR_COOKIE -9 - -#define OSL_ERR_APCTL_GETINFO -10 -#define OSL_ERR_APCTL_CONNECT -11 -#define OSL_ERR_APCTL_TIMEOUT -12 -#define OSL_ERR_APCTL_GETSTATE -13 - -#define OSL_ERR_RESOLVER_CREATE -14 -#define OSL_ERR_RESOLVER_RESOLVING -15 - -#define OSL_ERR_WLAN_OFF -16 -#define OSL_USER_ABORTED -17 - -#define OSL_ERR_HTTP_INIT -18 -#define OSL_ERR_HTTP_TEMPLATE -19 -#define OSL_ERR_HTTP_TIMEOUT -20 -#define OSL_ERR_HTTP_CONNECT -21 -#define OSL_ERR_HTTP_REQUEST -22 -#define OSL_ERR_HTTP_GENERIC -23 - - -#define OSL_MAX_NET_CONFIGS 20 - -/**Structure for network configuration*/ -struct oslNetConfig{ - char name[128]; - char IP[128]; -}; - -#define OSL_RESOLVER_RETRY 4 - -/**Checks if the WLAN switch is powered on (returns 1, else 0). -*/ -int oslIsWlanPowerOn(); - -/**Checks if the WLAN is connected to an Access Point (returns 1, else 0). -*/ -int oslIsWlanConnected(); - -/**Gets the network configs. -\code -struct oslNetConfig configs[OSL_MAX_NET_CONFIGS]; -int numconfigs = oslGetNetConfigs(configs); -\endcode -*/ -int oslGetNetConfigs(struct oslNetConfig *result); - -/**Inits network -*/ -int oslNetInit(); - -/**Terminates network -*/ -int oslNetTerm(); - -/**Gets the current IP address (when connected to an Access Point) -*/ -int oslGetIPaddress(char *IPaddress); - -/**Tries to connect to an Access Point using the given configuration - \param int config - Index of the configuration to use - \param int timeout - Timeout (in seconds) for the connection - \param int (*apctlCallback)(int state) - Pointer to a callback function. It will be called with the current state -*/ -int oslConnectToAP(int config, int timeout, int (*apctlCallback)(int state)); - -/**Disconnectes from the Access Point -*/ -int oslDisconnectFromAP(); - -/**Gets the current Access Point state -*/ -int oslGetAPState(); - -/**Resolves an address to its IP address -*/ -int oslResolveAddress(char *address, char *resolvedIP); - -/**Get a file from the web and save it -*/ -int oslNetGetFile(const char *url, const char *filepath); - -/**Posts a web form -*/ -int oslNetPostForm(const char *url, char *data, char *response, unsigned int responsesize); - - -int oslNetSocketCreate(void); -int oslNetSocketAccept(int socket); -int oslNetSocketBind(int socket, unsigned short port); -int oslNetSocketListen(int socket, unsigned int maxconn); -int oslNetSocketConnect(int socket, char *ip, unsigned short port); -int oslNetSocketSend(int socket, const void *data, int length); -int oslNetSocketReceive(int socket, void *data, int length); -void oslNetSocketClose(int socket); -void oslNetSocketSetClear(fd_set *set); -void oslNetSocketSetAdd(int socket, fd_set *set); -void oslNetSocketSetRemove(int socket, fd_set *set); -int oslNetSocketSetIsMember(int socket, fd_set *set); -int oslNetSocketSetSelect(unsigned int maxsockets, fd_set *set); - -/** @} */ // end of net -#endif +#ifndef NET_H +#define NET_H + +#include + +/** @defgroup Network + + Network functions + @{ +*/ +//<-- STAS: APCTL states returned by oslGetAPState() --> +#include + +#define OSL_APCTL_STATE_DISCONNECTED PSP_NET_APCTL_STATE_DISCONNECTED +#define OSL_APCTL_STATE_SCANNING PSP_NET_APCTL_STATE_SCANNING +#define OSL_APCTL_STATE_JOINING PSP_NET_APCTL_STATE_JOINING +#define OSL_APCTL_STATE_GETTING_IP PSP_NET_APCTL_STATE_GETTING_IP +#define OSL_APCTL_STATE_GOT_IP PSP_NET_APCTL_STATE_GOT_IP +#define OSL_APCTL_STATE_EAP_AUTH PSP_NET_APCTL_STATE_EAP_AUTH +#define OSL_APCTL_STATE_KEY_EXCHANGE PSP_NET_APCTL_STATE_KEY_EXCHANGE +//<-- STAS END --> +#define OSL_NET_ERROR_NET -1 +#define OSL_NET_ERROR_INET -2 +#define OSL_NET_ERROR_RESOLVER -3 +#define OSL_NET_ERROR_APCTL -4 +#define OSL_NET_ERROR_SSL -5 +#define OSL_NET_ERROR_HTTP -6 +#define OSL_NET_ERROR_HTTPS -7 +#define OSL_NET_ERROR_CERT -8 +#define OSL_NET_ERROR_COOKIE -9 + +#define OSL_ERR_APCTL_GETINFO -10 +#define OSL_ERR_APCTL_CONNECT -11 +#define OSL_ERR_APCTL_TIMEOUT -12 +#define OSL_ERR_APCTL_GETSTATE -13 + +#define OSL_ERR_RESOLVER_CREATE -14 +#define OSL_ERR_RESOLVER_RESOLVING -15 + +#define OSL_ERR_WLAN_OFF -16 +#define OSL_USER_ABORTED -17 + +#define OSL_ERR_HTTP_INIT -18 +#define OSL_ERR_HTTP_TEMPLATE -19 +#define OSL_ERR_HTTP_TIMEOUT -20 +#define OSL_ERR_HTTP_CONNECT -21 +#define OSL_ERR_HTTP_REQUEST -22 +#define OSL_ERR_HTTP_GENERIC -23 + + +#define OSL_MAX_NET_CONFIGS 20 + +/**Structure for network configuration*/ +struct oslNetConfig{ + char name[128]; + char IP[128]; +}; + +#define OSL_RESOLVER_RETRY 4 + +/**Checks if the WLAN switch is powered on (returns 1, else 0). +*/ +int oslIsWlanPowerOn(); + +/**Checks if the WLAN is connected to an Access Point (returns 1, else 0). +*/ +int oslIsWlanConnected(); + +/**Gets the network configs. +\code +struct oslNetConfig configs[OSL_MAX_NET_CONFIGS]; +int numconfigs = oslGetNetConfigs(configs); +\endcode +*/ +int oslGetNetConfigs(struct oslNetConfig *result); + +//<-- STAS: +/**Returns 1 or 0 indicating whether the network is initialized or not +*/ +int oslIsNetActive(); +//<-- STAS END --> + +/**Inits network +*/ +int oslNetInit(); + +/**Terminates network +*/ +int oslNetTerm(); + +/**Gets the current IP address (when connected to an Access Point) +*/ +int oslGetIPaddress(char *IPaddress); + +/**Tries to connect to an Access Point using the given configuration + \param int config + Index of the configuration to use + \param int timeout + Timeout (in seconds) for the connection + \param int (*apctlCallback)(int state) + Pointer to a callback function. It will be called with the current state +*/ +int oslConnectToAP(int config, int timeout, int (*apctlCallback)(int state)); + +/**Disconnectes from the Access Point +*/ +int oslDisconnectFromAP(); + +/**Gets the current Access Point state +*/ +int oslGetAPState(); + +/**Resolves an address to its IP address +*/ +int oslResolveAddress(char *address, char *resolvedIP); + +/**Get a file from the web and save it +*/ +int oslNetGetFile(const char *url, const char *filepath); + +/**Posts a web form +*/ +int oslNetPostForm(const char *url, char *data, char *response, unsigned int responsesize); + + +int oslNetSocketCreate(void); +int oslNetSocketAccept(int socket); +int oslNetSocketBind(int socket, unsigned short port); +int oslNetSocketListen(int socket, unsigned int maxconn); +int oslNetSocketConnect(int socket, char *ip, unsigned short port); +int oslNetSocketSend(int socket, const void *data, int length); +int oslNetSocketReceive(int socket, void *data, int length); +void oslNetSocketClose(int socket); +void oslNetSocketSetClear(fd_set *set); +void oslNetSocketSetAdd(int socket, fd_set *set); +void oslNetSocketSetRemove(int socket, fd_set *set); +int oslNetSocketSetIsMember(int socket, fd_set *set); +int oslNetSocketSetSelect(unsigned int maxsockets, fd_set *set); + +/** @} */ // end of net +#endif diff --git a/osk.c b/osk.c index e592175..8f51e0a 100644 --- a/osk.c +++ b/osk.c @@ -8,70 +8,165 @@ #include "oslib.h" #include "osk.h" -SceUtilityOskData OskData; -SceUtilityOskParams oskParams; -unsigned short *intext; -unsigned short *outtext; -unsigned short desc[128] = { 0 }; +//SceUtilityOskData OskData; //<-- STAS: this is not necessary now +//SceUtilityOskParams OskParams; //<-- STAS: this is not necessary now +unsigned short *intext = NULL; +//unsigned short *outtext; //<-- STAS: this is not necessary now +//unsigned short desc[128] = { 0 }; //<-- STAS: this is not necessary now +unsigned short *desc = NULL; + +//int OskActive = 0; //<-- STAS: this is not necessary now +OSL_KEYBOARD* osl_osk = NULL; //<-- STAS: static ptr to the currently active OSL_KEYBOARD + + +OSL_KEYBOARD* oslInitOskEx(int nData, int language) +{ + OSL_KEYBOARD* kbd; + + kbd = (OSL_KEYBOARD*) malloc(sizeof(OSL_KEYBOARD)); + if (!kbd) return NULL; + memset(kbd, 0, sizeof(OSL_KEYBOARD)); + + kbd->oskParams.base.size = sizeof(SceUtilityOskParams); + if (language >= 0) + kbd->oskParams.base.language = language; + else + sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_LANGUAGE, &kbd->oskParams.base.language); + sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_UNKNOWN, &kbd->oskParams.base.buttonSwap); + kbd->oskParams.base.graphicsThread = 17; + kbd->oskParams.base.accessThread = 19; + kbd->oskParams.base.fontThread = 18; + kbd->oskParams.base.soundThread = 16; + kbd->oskParams.datacount = oslMax(1,nData); + kbd->oskParams.data = (SceUtilityOskData*) malloc(kbd->oskParams.datacount * sizeof(SceUtilityOskData)); + if (!kbd->oskParams.data) { + free(kbd); + return NULL; + } + + memset(kbd->oskParams.data, 0, kbd->oskParams.datacount * sizeof(SceUtilityOskData)); + return kbd; +} + +int oslInitOskDataEx(OSL_KEYBOARD *kbd, int idx, + unsigned short *desc, unsigned short *intext, int textLimit, int linesNumber) +{ + if (!kbd || idx < 0 || idx >= kbd->oskParams.datacount) + return 0; + + unsigned short *outtext = (unsigned short *) malloc((textLimit + 1)*sizeof(unsigned short)); + if (!outtext) + return 0; + + memset(&kbd->oskParams.data[idx], 0, sizeof(SceUtilityOskData)); + kbd->oskParams.data[idx].language = PSP_UTILITY_OSK_LANGUAGE_DEFAULT; + kbd->oskParams.data[idx].lines = linesNumber; + kbd->oskParams.data[idx].unk_24 = 1; // set to 1 + kbd->oskParams.data[idx].desc = desc; + kbd->oskParams.data[idx].intext = intext; + kbd->oskParams.data[idx].outtextlength = textLimit; + kbd->oskParams.data[idx].outtextlimit = textLimit; + kbd->oskParams.data[idx].outtext = outtext; + + return 1; +} + +int oslActivateOskEx(OSL_KEYBOARD *kbd, int waitcycle) +{ + if (!kbd) return -1; + + if (!osl_osk) { // There is no active OSK - activate the given one + osl_osk = kbd; + int ret = sceUtilityOskInitStart(&kbd->oskParams); + if (ret < 0) osl_osk = NULL; + return ret; + } + else if (osl_osk == kbd) + return 0; // The given OSK is currently active... + else if (!waitcycle) + return -2; // Other OSK is currently active... + else { // Wait for other OSK to finish and try again to activate the given one + while (osl_osk) sceDisplayWaitVblankStart(); + return oslActivateOskEx(kbd, waitcycle); + } +} + +int oslOskIsActiveEx(OSL_KEYBOARD *kbd) +{ + return (kbd && (kbd == osl_osk)); +} + +void oslDeActivateOskEx(OSL_KEYBOARD *kbd) +{ + if (oslOskIsActiveEx(kbd)) + osl_osk = NULL; +} + +int oslOskGetResultEx(OSL_KEYBOARD *kbd, int idx) +{ + if (!kbd) return 0; + else if (idx < 0 || idx >= kbd->oskParams.datacount) + return kbd->oskParams.base.result; + else + return kbd->oskParams.data[idx].result; +} + +unsigned short* oslOskOutTextEx(OSL_KEYBOARD *kbd, int idx) +{ + if (!kbd || idx < 0 || idx >= kbd->oskParams.datacount) + return NULL; + else + return kbd->oskParams.data[idx].outtext; +} + + +void oslEndOskEx(OSL_KEYBOARD *kbd) +{ + if (!kbd || !oslOskIsActiveEx(kbd)) return; + + oslDeActivateOskEx(kbd); + int i; + for (i = 0; i < kbd->oskParams.datacount; i++) { + free(kbd->oskParams.data[i].outtext); + } + free(kbd->oskParams.data); + free(kbd); +} -int OskActive = 0; void oslInitOsk(char *descStr, char *initialStr, int textLimit, int linesNumber, int language){ int i = 0; - intext = (unsigned short *) malloc((textLimit + 1)*sizeof(unsigned short)); + if (intext || desc) return; //<-- STAS: Is the static OSK already initialized? + +// intext = (unsigned short *) malloc((textLimit + 1)*sizeof(unsigned short)); //<-- STAS: textLimit ISN'T right! + intext = (unsigned short *) malloc((strlen(initialStr) + 1)*sizeof(unsigned short)); if (!intext) return; - outtext = (unsigned short *) malloc((textLimit + 1)*sizeof(unsigned short)); - if (!outtext) + + desc = (unsigned short *) malloc((strlen(descStr) + 1)*sizeof(unsigned short)); + if (!desc) { + oslEndOsk(); return; + } for (i=0; i<=strlen(initialStr); i++) intext[i] = (unsigned short)initialStr[i]; for (i=0; i<=strlen(descStr); i++){ desc[i] = (unsigned short)descStr[i]; - if (i >= 128) - break; } - memset(&OskData, 0, sizeof(OskData)); - /*if (language >= 0) - OskData.language = language; - else - sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_LANGUAGE, &OskData.language);*/ - OskData.language = PSP_UTILITY_OSK_LANGUAGE_DEFAULT; - - OskData.lines = linesNumber; - OskData.unk_24 = 1; // set to 1 - OskData.desc = desc; - OskData.intext = intext; - OskData.outtextlength = textLimit; - OskData.outtextlimit = textLimit; - OskData.outtext = outtext; - - memset(&oskParams, 0, sizeof(oskParams)); - oskParams.base.size = sizeof(oskParams); - if (language >= 0) - oskParams.base.language = language; - else - sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_LANGUAGE, &oskParams.base.language); - sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_UNKNOWN, &oskParams.base.buttonSwap); - oskParams.base.graphicsThread = 17; - oskParams.base.accessThread = 19; - oskParams.base.fontThread = 18; - oskParams.base.soundThread = 16; - oskParams.datacount = 1; - oskParams.data = &OskData; - - sceUtilityOskInitStart(&oskParams); - OskActive = 1; + OSL_KEYBOARD *kbd = oslInitOskEx(1, language); + if (!kbd || !oslInitOskDataEx(kbd, 0, desc, intext, textLimit, linesNumber) || (oslActivateOskEx(kbd,0)<0)) { + oslEndOsk(); + } } void oslDrawOsk() { switch(sceUtilityOskGetStatus()){ - case PSP_UTILITY_DIALOG_INIT: +// case PSP_UTILITY_DIALOG_INIT: //<-- STAS: sceUtilityOskUpdate should be called only in VISIBLE state! case PSP_UTILITY_DIALOG_VISIBLE : sceDisplayWaitVblankStart(); sceDisplayWaitVblankStart(); @@ -84,14 +179,15 @@ void oslDrawOsk() case PSP_UTILITY_DIALOG_QUIT: sceUtilityOskShutdownStart(); break; - case PSP_UTILITY_DIALOG_FINISHED: - case PSP_UTILITY_DIALOG_NONE: - break; +// case PSP_UTILITY_DIALOG_FINISHED: //<-- STAS: nothing to do for the other states +// case PSP_UTILITY_DIALOG_NONE: + default: + break; //<-- STAS END --> } } int oslOskIsActive(){ - return OskActive; + return oslOskIsActiveEx(osl_osk); } int oslGetOskStatus(){ @@ -100,35 +196,37 @@ int oslGetOskStatus(){ int oslOskGetResult(){ - return oskParams.base.result; + return oslOskGetResultEx(osl_osk, -1); } void oslOskGetText(char *text){ int i, j; j = 0; - for(i = 0; OskData.outtext[i]; i++) - if (OskData.outtext[i]!='\0' && OskData.outtext[i]!='\n' && OskData.outtext[i]!='\r'){ - text[j] = OskData.outtext[i]; + if (osl_osk) for(i = 0; osl_osk->oskParams.data[0].outtext[i]; i++) { + if (osl_osk->oskParams.data[0].outtext[i]!='\n' && osl_osk->oskParams.data[0].outtext[i]!='\r'){ + text[j] = osl_osk->oskParams.data[0].outtext[i]; j++; } + } text[j] = 0; } void oslOskGetTextUCS2(unsigned short *text){ int i, j; j = 0; - for(i = 0; OskData.outtext[i]; i++) - if (OskData.outtext[i]!='\0' && OskData.outtext[i]!='\n' && OskData.outtext[i]!='\r'){ - text[j] = OskData.outtext[i]; + if (osl_osk) for(i = 0; osl_osk->oskParams.data[0].outtext[i]; i++) { + if (osl_osk->oskParams.data[0].outtext[i]!='\n' && osl_osk->oskParams.data[0].outtext[i]!='\r'){ + text[j] = osl_osk->oskParams.data[0].outtext[i]; j++; } + } text[j] = 0; } void oslEndOsk(){ - free(intext); - free(outtext); - memset(&OskData, 0, sizeof(OskData)); - memset(&oskParams, 0, sizeof(oskParams)); - OskActive = 0; + if (intext) free(intext); + if (desc) free(desc); + intext = NULL; + desc = NULL; + oslEndOskEx(osl_osk); } diff --git a/osk.h b/osk.h index be65704..f8c60a2 100644 --- a/osk.h +++ b/osk.h @@ -6,11 +6,41 @@ Functions to display Sony's On Screen Keyboard @{ */ +//<-- STAS: define the OSL_KEYBOARD structure and its methods for multithreaded environment +typedef struct { + SceUtilityOskParams oskParams; +// SceUtilityOskData *oskData; +} OSL_KEYBOARD; + +extern OSL_KEYBOARD* osl_osk; + +extern OSL_KEYBOARD* oslInitOskEx(int nData, int language); + +extern int oslInitOskDataEx(OSL_KEYBOARD *kbd, int idx, unsigned short *desc, + unsigned short *intext, int textLimit, int linesNumber); + +extern int oslActivateOskEx(OSL_KEYBOARD *kbd, int waitcycle); + +extern int oslOskIsActiveEx(OSL_KEYBOARD *kbd); + +extern void oslDeActivateOskEx(OSL_KEYBOARD *kbd); + +extern int oslOskGetResultEx(OSL_KEYBOARD *kbd, int idx); + +extern unsigned short* oslOskOutTextEx(OSL_KEYBOARD *kbd, int idx); + +extern void oslEndOskEx(OSL_KEYBOARD *kbd); + + +#define OSL_OSK_RESULT_UNCHANGED PSP_UTILITY_OSK_RESULT_UNCHANGED +#define OSL_OSK_RESULT_CANCELLED PSP_UTILITY_OSK_RESULT_CANCELLED +#define OSL_OSK_RESULT_CHANGED PSP_UTILITY_OSK_RESULT_CHANGED +//<-- STAS END --> /**OSK cancel*/ -#define OSL_OSK_CANCEL 1 +#define OSL_OSK_CANCEL PSP_UTILITY_OSK_RESULT_CANCELLED /**<-- STAS: for backward compatibility */ /**OSK OK*/ -#define OSL_OSK_OK 0 +// #define OSL_OSK_OK 0 //<-- STAS: This isn't right !!! - see SceUtilityOskResult enumeration /** Initializes the OSK \param *descStr diff --git a/oslib.c b/oslib.c index 30cf6a5..03bb8db 100644 --- a/oslib.c +++ b/oslib.c @@ -1,716 +1,734 @@ -#include "oslib.h" -#ifndef PSP - #include "../PC_Main/GL/glext.h" -#endif - -/* - GRAPHICS -*/ - -int osl_intraInit = 0; -int osl_quit=0; -int osl_vblInterruptNumber=0; -int (*osl_powerCallback)(int, int, void*)=NULL; -int (*osl_exitCallback)(int, int, void*)=NULL; -OSL_CONTROLLER *osl_keys; -OSL_REMOTECONTROLLER *osl_remotekeys; - -int osl_noFail = 0; - -//float osl_fsinus[361]; -//float osl_fcosinus[361]; -int osl_isinus[361]; -int osl_icosinus[361]; - -void oslSetupFTrigo() { - int i; - - //Precalculate values for integer sine and cosine tables - for (i=0;i<361;i++) { -// osl_fsinus[i] = sin(i * 3.1415926535898f / 180.f); -// osl_fcosinus[i] = cos(i * 3.1415926535898f / 180.f); - osl_isinus[i] = (int)oslSin(i, 16384.0f); - osl_icosinus[i] = (int)oslCos(i, 16384.0f); - } -} - -//Moved to VFPU.C -/*float oslCos(float angle, float dist) { - //Degree => Radian - angle = angle * 0.0174532925f; - return vfpu_cosf(angle, dist); -} - -float oslSin(float angle, float dist) { - //Degree => Radian - angle = angle * 0.0174532925f; - return vfpu_sinf(angle, dist); -}*/ - -int oslCosi(int angle, int dist) { - angle = angle % 360; - if (angle < 0) - angle += 360; - //Integer values are multiplicated by 16384 - return (osl_icosinus[angle] * dist) >> 14; -} - -int oslSini(int angle, int dist) { - angle = angle % 360; - if (angle < 0) - angle += 360; - return (osl_isinus[angle] * dist) >> 14; -} - - -int oslGetNextPower2(int val) { - int i; - for (i=15;i>=0;i--) { - if (val & (1<>6; - u8 *dst2, *src2; - while (len--) { - *dst++ = *src; - *dst++ = *src; - *dst++ = *src; - *dst++ = *src; - *dst++ = *src; - *dst++ = *src; - *dst++ = *src; - *dst++ = *src; - } - len = (length & 63) >> 3; - while (len--) - *dst++ = *src; - dst2 = (u8*)dst; - src2 = (u8*)src; - len = (length & 7); - while (len--) - *dst2++ = *src2++; -} - -void oslWaitVSync() -{ -// osl_vblCount++; - sceDisplayWaitVblankStart(); -} - -inline void oslFlushDataCache() { - sceKernelDcacheWritebackInvalidateAll(); -} - -int oslMeanBenchmarkTestEx(int startend, int slot) { - static int val[OSL_BENCH_SLOTS]; - static struct timeval start[OSL_BENCH_SLOTS]; - struct timeval end; - static int curr_ms[OSL_BENCH_SLOTS], time[OSL_BENCH_SLOTS]; - - if (startend == OSL_BENCH_INIT) { - val[slot]=0; - time[slot]=0; - curr_ms[slot]=0; - gettimeofday(&start[slot],0); - } - else if (startend == OSL_BENCH_START) - gettimeofday(&start[slot],0); - else if (startend == OSL_BENCH_END) { - gettimeofday(&end,0); - time[slot] += (end.tv_sec - start[slot].tv_sec) * 1000000; - time[slot] += end.tv_usec - start[slot].tv_usec; - val[slot]++; - if (val[slot] >= OSL_BENCH_SAMPLES) - { - val[slot] = 0; - curr_ms[slot] = time[slot] / OSL_BENCH_SAMPLES; - time[slot] = 0; - } - } - //Returns the last measure - else if (startend == OSL_BENCH_GET_LAST) { - if (val[slot] != 0) - return time[slot] / val[slot]; - } - -/* else if (startend == OSL_BENCH_DISPLAY) { - pspDebugScreenSetXY(0,0); - pspDebugScreenPrintf("%i.%03i", curr_ms[slot]/1000, curr_ms[slot]%1000); - }*/ - return curr_ms[slot]; -} - -int oslBenchmarkTestEx(int startend, int slot) { - static struct timeval start[OSL_BENCH_SLOTS]; - struct timeval end; - static int time[OSL_BENCH_SLOTS]; - - if (startend == OSL_BENCH_START) - gettimeofday(&start[slot],0); - else if (startend == OSL_BENCH_END) { - gettimeofday(&end,0); - time[slot] = (end.tv_sec - start[slot].tv_sec) * 1000000; - time[slot] += end.tv_usec - start[slot].tv_usec; - } - return time[slot]; -} - -void oslQuit() -{ - sceKernelExitGame(); -} - -#ifdef PSP - /* Exit callback */ - int oslStandardExitCallback(int arg1, int arg2, void *common) - { - osl_quit = 1; - if (osl_exitCallback) - osl_exitCallback(arg1, arg2, common); - // sceKernelExitGame(); - return 0; - } - - int oslStandardPowerCallback(int unknown, int pwrflags,void *common){ -// int cbid = sceKernelCreateCallback("powerCallback", oslStandardPowerCallback, NULL); -// scePowerRegisterCallback(0, cbid); - if (osl_powerCallback) - return osl_powerCallback(unknown, pwrflags, common); - else - return 0; - } - - /* Callback thread */ - int oslCallbackThread(SceSize args, void *argp) - { - int cbid; - - cbid = sceKernelCreateCallback("exitCallback", oslStandardExitCallback, NULL); - sceKernelRegisterExitCallback(cbid); - cbid = sceKernelCreateCallback("powerCallback", oslStandardPowerCallback,NULL ); - scePowerRegisterCallback(0, cbid ); - - sceKernelSleepThreadCB(); - - return 0; - } - - /* Sets up the callback thread and returns its thread id */ - int oslSetupCallbacks() - { - int thid = 0; - - thid = sceKernelCreateThread("update_thread", oslCallbackThread, 0x11, 0xFA0, 0, 0); - if(thid >= 0) - { - sceKernelStartThread(thid, 0, 0); - } - - return thid; - } -#endif - -//osl_currentFrameRate CANNOT be > 60! -volatile int osl_vblCount=0, osl_vblCountMultiple=0, osl_currentFrameRate, osl_vblCallCount=0, osl_skip=0, osl_nbSkippedFrames=0, osl_vblankCounterActive=1; -volatile int osl_vblShouldSwap = 0; - -void oslVblankNextFrame() { - osl_vblCountMultiple += osl_currentFrameRate; - //osl_currentFrameRate CANNOT be > 60! (else a while or a better method would be needed here) - if (osl_vblCountMultiple >= 60) { - osl_vblCountMultiple -= 60; - osl_vblCount++; - } -} - -void oslVblankInterrupt(int sub, void *parg) -{ - if (osl_vblankCounterActive) - oslVblankNextFrame(); - - //This is done so to avoid screen tearing when sound takes too long - if (osl_vblShouldSwap) { - oslSwapBuffers(); - osl_vblShouldSwap = 0; - } -} - -int osl_maxFrameskip=0, osl_vsyncEnabled=0, osl_frameskip=0; - -void oslInit(int flags) -{ - void *arg = 0; - int i; - - osl_keys = &osl_pad; - osl_remotekeys = &osl_remote; - - osl_quit = 0; - osl_vblCount = 0; - osl_vblCallCount = 0; - osl_skip = 0; - osl_nbSkippedFrames = 0; - osl_maxFrameskip=5; - osl_vsyncEnabled=4; - osl_frameskip=0; - osl_currentFrameRate = 60; - - //Configure l'autorepeat (il n'y en a pas au début) - oslSetKeyAutorepeat(OSL_KEYMASK_UP|OSL_KEYMASK_RIGHT|OSL_KEYMASK_DOWN|OSL_KEYMASK_LEFT|OSL_KEYMASK_R|OSL_KEYMASK_L,0,0); - -#ifdef PSP - if (!(flags & OSL_IF_USEOWNCALLBACKS)) - oslSetupCallbacks(); - - //No interrupt handler... - if (!(flags & OSL_IF_NOVBLANKIRQ)) { - sceKernelRegisterSubIntrHandler(PSP_VBLANK_INT,osl_vblInterruptNumber,oslVblankInterrupt,arg); - sceKernelEnableSubIntr(PSP_VBLANK_INT,osl_vblInterruptNumber); - } -#endif - for (i=0;i1: dépend de vsync, saute 1 frame sur X - - Max frameskip: - >=1: Frameskip maximum autorisé - VSync: - 0: pas de VSync - 1: vsync activée - +4: si on rajoute 4, avec un frameskip >1, synchronise au framerate souhaité, par ex. 2 -> 30 fps - +0: sinon, fixe le frameskip minimum (ex. avec 2, le jeu tournera à 60 fps, 30 images par seconde) - +8: synchro maximale (impression de triple buffering), sans vsync - +16: pas de swapbuffers - Exemples: - //30 fps (pas de frameskip) - oslSyncFrameEx(2,0,0); - //30 fps, jeu à 60, frameskip max de 2, c'est-à-dire pas plus d'une frame skippée pour une affichée - oslSyncFrameEx(2,2,4); - //synchronise à 60 fps - oslSyncFrameEx(0,0,0); -*/ - -#if 0 -int oslSyncFrameEx(int frameskip, int max_frameskip, int vsync) -{ - #ifdef OSL_SYSTEM_BENCHMARK_ENABLED - int lastOslSkip; - #endif - int i, wasDrawing=0; - if (osl_isDrawingStarted) - oslEndDrawing(), wasDrawing=1; - if (frameskip==0) { - #ifdef OSL_SYSTEM_BENCHMARK_ENABLED - oslMeanBenchmarkTestEx(OSL_BENCH_END, 4); - oslMeanBenchmarkTestEx(OSL_BENCH_END, 6); - #endif - //Dans les temps -> vsync -/* i = osl_vblCount; - if (vsync || osl_vblCallCount+1 > i) { - oslWaitVSync(); - i++; - } - osl_vblCallCount = i;*/ - - //We need to do this outside of the handler to be more precise - osl_vblankCounterActive = 0; - if (vsync || osl_vblCallCount+1 > osl_vblCount) { - while (osl_vblCallCount+1 > osl_vblCount) { - oslWaitVSync(); - oslVblankNextFrame(); - } - } - osl_vblCallCount = osl_vblCount; - - osl_skip = 0; - #ifdef OSL_SYSTEM_BENCHMARK_ENABLED - oslMeanBenchmarkTestEx(OSL_BENCH_START, 4); - oslMeanBenchmarkTestEx(OSL_BENCH_START, 6); - #endif - if (!(vsync & 16)) - oslSwapBuffers(); - } - else { - if (vsync&4) - osl_vblCallCount++; - else - osl_vblCallCount+=frameskip; - #ifdef OSL_SYSTEM_BENCHMARK_ENABLED - lastOslSkip = osl_skip; - if (osl_skip) - oslMeanBenchmarkTestEx(OSL_BENCH_END, 5); - else { - oslMeanBenchmarkTestEx(OSL_BENCH_END, 4); - } - #endif - //La référence quand vsync = 0 - i=((vsync&1) && !osl_skip && !(vsync&8))?1:0; - //On est en retard? - if ((osl_vblCount+i > osl_vblCallCount || (vsync&4 && osl_vblCallCount%frameskip)) && osl_nbSkippedFrames < max_frameskip-1) { - if (!osl_skip) { //La frame a été dessinée -> on l'affiche - #ifdef OSL_SYSTEM_BENCHMARK_ENABLED - oslMeanBenchmarkTestEx(OSL_BENCH_END, 6); - #endif - if (vsync&1) //Activer pour avoir vraiment la VSync - oslWaitVSync(); - if (!(vsync & 16)) - oslSwapBuffers(); - #ifdef OSL_SYSTEM_BENCHMARK_ENABLED - oslMeanBenchmarkTestEx(OSL_BENCH_START, 6); - #endif - } - osl_nbSkippedFrames++; - //Dernière fois -> la prochaine c'est en-dessous - if (frameskip > 1 && osl_vblCallCount%frameskip == frameskip - 1) - osl_skip = 0; - else - osl_skip = 1; - } - else { - #ifdef OSL_SYSTEM_BENCHMARK_ENABLED - if (!osl_skip) - oslMeanBenchmarkTestEx(OSL_BENCH_END, 6); - #endif - if (vsync&1 && !osl_skip) //Activer pour avoir vraiment la VSync - oslWaitVSync(); - //Dans les temps -/* i = osl_vblCount; - while (i < osl_vblCallCount + ((vsync & 8) ? (1 - osl_skip) : (0))) { - oslWaitVSync(); - i++; - }*/ - //We need to do this outside of the handler to be more precise - osl_vblankCounterActive = 0; - while (osl_vblCount < osl_vblCallCount + ((vsync & 8) ? (1 - osl_skip) : (0))) { - oslWaitVSync(); - oslVblankNextFrame(); - } - osl_vblankCounterActive = 1; - - //La référence (meilleur frameskip), mais bidouillage -/* if (osl_vblCount < osl_vblCallCount) { - do { - oslWaitVSync(); - } while (osl_vblCount+1 <=osl_vblCallCount); - }*/ - if (!osl_skip) { - if (!(vsync & 16)) - oslSwapBuffers(); - } - #ifdef OSL_SYSTEM_BENCHMARK_ENABLED - if (!osl_skip) - oslMeanBenchmarkTestEx(OSL_BENCH_START, 6); - #endif - //Trop de frameskip tue le frameskip - if (osl_nbSkippedFrames >= max_frameskip-1) - osl_vblCallCount = osl_vblCount; - osl_nbSkippedFrames=0; - osl_skip = 0; - //Bidouille pour le frameskip fixé -> on repasse en-dessus - if (vsync&4 && frameskip > 1 && osl_vblCallCount%frameskip == 0) - osl_skip = 1; - } - #ifdef OSL_SYSTEM_BENCHMARK_ENABLED - if (osl_skip) - oslMeanBenchmarkTestEx(OSL_BENCH_START, 5); - else - oslMeanBenchmarkTestEx(OSL_BENCH_START, 4); - #endif - } - if (wasDrawing) - oslStartDrawing(); - return osl_skip; -} -#else - -//Routine originale, écrite entre deux. La nouvelle est dégueulasse mais elle permet d'éviter le cisaillement du haut de l'écran quand un son demande trop de puissance. -#if 0 -static void waitNextFrame() { - osl_vblankCounterActive = 0; -// while (osl_vblCallCount >= osl_vblCount) { - oslWaitVSync(); - oslVblankNextFrame(); -// } - osl_vblankCounterActive = 1; -} - -int oslSyncFrameEx(int frameskip, int max_frameskip, int vsync) -{ -// int lastOslSkip = osl_skip; - int wasDrawing=0; - - if (osl_isDrawingStarted) - oslEndDrawing(), wasDrawing=1; - - //We need to do this outside of the handler to be more precise -// osl_vblankCounterActive = 0; - osl_vblCallCount++; - - #ifdef OSL_SYSTEM_BENCHMARK_ENABLED - if (!osl_skip) - oslMeanBenchmarkTestEx(OSL_BENCH_END, 4); - else - oslMeanBenchmarkTestEx(OSL_BENCH_END, 5); - #endif - - //Soit on est en retard, soit on a un frameskip fixé. oslMax => éviter une division par zéro ;) - if (osl_vblCallCount < osl_vblCount - || (osl_vblCallCount % oslMax(frameskip, 1))) { - //Do not skip more frames than indicated - osl_nbSkippedFrames++; - if (osl_nbSkippedFrames >= max_frameskip) { - osl_vblCallCount = osl_vblCount; - goto noskip; - } - osl_skip = 1; - #ifdef OSL_SYSTEM_BENCHMARK_ENABLED - oslMeanBenchmarkTestEx(OSL_BENCH_START, 5); - #endif - } - else { - /* - En mettant le label noskip ici au lieu d'en bas, on évite le problème qui fait que lorsqu'on dépasse le frameskip max la VSync n'est plus prise en compte. Dans ce cas la VSync est toujours - attendue, même si le frameskip max a été dépassé, alors que pour l'instant ce n'est pas le cas: si le frameskip max a été dépassé, la VSync n'est pas attendue, quel que soit le paramètre - Vsync actuel. - */ -noskip: - - #ifdef OSL_SYSTEM_BENCHMARK_ENABLED - //To measure the total time of a frame (until it has been swapped) - oslMeanBenchmarkTestEx(OSL_BENCH_END, 6); - #endif - - //Pour attendre la prochaine frame - toujours en mode VSync, si on a assez d'avance en mode Auto - /* - Note: Le fait qu'on le fasse lorsque le skip passe à zéro fait que le framerate se remet de lui même au max. possible, alors qu'en le mettant dans le cas où lastOslSkip est 0 "fixe" le framerate - à 30 fps, il est difficile de remonter, ça évite un peu les saccades aléatoires, à voir. - Attention: Pareil pour swapbuffers! - */ - if (vsync & 1) { - while (osl_vblCallCount >= osl_vblCount) - waitNextFrame(); - } - else { - while (osl_vblCallCount > osl_vblCount) - waitNextFrame(); - } - -//noskip: - osl_skip = 0; - osl_nbSkippedFrames = 0; - } - - //Pas de support pour le frameskip? On n'active jamais le skip. - if (!frameskip) - osl_skip = 0; - - #ifdef OSL_SYSTEM_BENCHMARK_ENABLED - if (!osl_skip) { - oslMeanBenchmarkTestEx(OSL_BENCH_START, 4); - oslMeanBenchmarkTestEx(OSL_BENCH_START, 6); - } - else { - oslMeanBenchmarkTestEx(OSL_BENCH_START, 5); - } - #endif - - //Flag 16 pour ne pas swapper les buffers - if (!(vsync & 16) && !osl_skip) { - oslSwapBuffers(); - } - - return osl_skip; -} - -#else - -#ifdef PSP -#define swap() ({ if (!(vsync & 16) && !swapped) osl_vblShouldSwap = 1; swapped = 1; }) -#else -#define swap() -#endif - -static void waitNextFrame() { - osl_vblankCounterActive = 0; -// while (osl_vblCallCount >= osl_vblCount) { - oslWaitVSync(); - oslVblankNextFrame(); -// } - osl_vblankCounterActive = 1; -} - -int oslSyncFrameEx(int frameskip, int max_frameskip, int vsync) -{ -// int lastOslSkip = osl_skip; - int wasDrawing=0, swapped = 0; - - if (osl_isDrawingStarted) - oslEndDrawing(), wasDrawing=1; - - //We need to do this outside of the handler to be more precise -// osl_vblankCounterActive = 0; - osl_vblCallCount++; - - #ifdef OSL_SYSTEM_BENCHMARK_ENABLED - if (!osl_skip) - oslMeanBenchmarkTestEx(OSL_BENCH_END, 4); - else - oslMeanBenchmarkTestEx(OSL_BENCH_END, 5); - #endif - - //Soit on est en retard, soit on a un frameskip fixé. oslMax => éviter une division par zéro ;) - if (osl_vblCallCount < osl_vblCount - || (osl_vblCallCount % oslMax(frameskip, 1))) { - //Do not skip more frames than indicated - osl_nbSkippedFrames++; - if (osl_nbSkippedFrames >= max_frameskip) { - osl_vblCallCount = osl_vblCount; - goto noskip; - } - osl_skip = 1; - #ifdef OSL_SYSTEM_BENCHMARK_ENABLED - oslMeanBenchmarkTestEx(OSL_BENCH_START, 5); - #endif - } - else { - /* - En mettant le label noskip ici au lieu d'en bas, on évite le problème qui fait que lorsqu'on dépasse le frameskip max la VSync n'est plus prise en compte. Dans ce cas la VSync est toujours - attendue, même si le frameskip max a été dépassé, alors que pour l'instant ce n'est pas le cas: si le frameskip max a été dépassé, la VSync n'est pas attendue, quel que soit le paramètre - Vsync actuel. - */ -noskip: - - #ifdef OSL_SYSTEM_BENCHMARK_ENABLED - //To measure the total time of a frame (until it has been swapped) - oslMeanBenchmarkTestEx(OSL_BENCH_END, 6); - #endif - - //Pour attendre la prochaine frame - toujours en mode VSync, si on a assez d'avance en mode Auto - /* - Note: Le fait qu'on le fasse lorsque le skip passe à zéro fait que le framerate se remet de lui même au max. possible, alors qu'en le mettant dans le cas où lastOslSkip est 0 "fixe" le framerate - à 30 fps, il est difficile de remonter, ça évite un peu les saccades aléatoires, à voir. - Attention: Pareil pour swapbuffers! - */ - if (vsync & 1) { - if (osl_vblCallCount >= osl_vblCount) { - swap(); - } - while (osl_vblCallCount >= osl_vblCount) - waitNextFrame(); - } - else { - if (osl_vblCallCount > osl_vblCount) { - swap(); - } - while (osl_vblCallCount > osl_vblCount) - waitNextFrame(); - } - -//noskip: - osl_skip = 0; - osl_nbSkippedFrames = 0; - } - - //Pas de support pour le frameskip? On n'active jamais le skip. - if (!frameskip) - osl_skip = 0; - - #ifdef OSL_SYSTEM_BENCHMARK_ENABLED - if (!osl_skip) { - oslMeanBenchmarkTestEx(OSL_BENCH_START, 4); - oslMeanBenchmarkTestEx(OSL_BENCH_START, 6); - } - else { - oslMeanBenchmarkTestEx(OSL_BENCH_START, 5); - } - #endif - - //Flag 16 pour ne pas swapper les buffers - if (!swapped && !(vsync & 16) && !osl_skip) { - oslSwapBuffers(); - } - - return osl_skip; -} -#endif -#endif - -/*int oslSyncFrameEx(int frameskip, int max_frameskip, int vsync) -{ - osl_vblCallCount++; - if (osl_vblCount > osl_vblCallCount) { - if (!osl_skip) { -// if (vsync) -// oslWaitVSync(); - oslSwapBuffers(); - } - osl_skip = 1; - } - else { - if (osl_vblCount <= osl_vblCallCount) { - do { - oslWaitVSync(); - } while (osl_vblCount+1 <=osl_vblCallCount); - } - if (!osl_skip) { - oslSwapBuffers(); - } - osl_nbSkippedFrames=0; - osl_skip = 0; - } - - return osl_skip; -}*/ - -void oslEndFrame() { - oslAudioVSync(); -} - +#include "oslib.h" +#ifndef PSP + #include "../PC_Main/GL/glext.h" +#endif + +/* + GRAPHICS +*/ + +int osl_intraInit = 0; +int osl_quit=0; +int osl_vblInterruptNumber=0; +int (*osl_powerCallback)(int, int, void*)=NULL; +int (*osl_exitCallback)(int, int, void*)=NULL; +OSL_CONTROLLER *osl_keys; +OSL_REMOTECONTROLLER *osl_remotekeys; + +int osl_noFail = 0; + +//float osl_fsinus[361]; +//float osl_fcosinus[361]; +int osl_isinus[361]; +int osl_icosinus[361]; + +void oslSetupFTrigo() { + int i; + + //Precalculate values for integer sine and cosine tables + for (i=0;i<361;i++) { +// osl_fsinus[i] = sin(i * 3.1415926535898f / 180.f); +// osl_fcosinus[i] = cos(i * 3.1415926535898f / 180.f); + osl_isinus[i] = (int)oslSin(i, 16384.0f); + osl_icosinus[i] = (int)oslCos(i, 16384.0f); + } +} + +//Moved to VFPU.C +/*float oslCos(float angle, float dist) { + //Degree => Radian + angle = angle * 0.0174532925f; + return vfpu_cosf(angle, dist); +} + +float oslSin(float angle, float dist) { + //Degree => Radian + angle = angle * 0.0174532925f; + return vfpu_sinf(angle, dist); +}*/ + +int oslCosi(int angle, int dist) { + angle = angle % 360; + if (angle < 0) + angle += 360; + //Integer values are multiplicated by 16384 + return (osl_icosinus[angle] * dist) >> 14; +} + +int oslSini(int angle, int dist) { + angle = angle % 360; + if (angle < 0) + angle += 360; + return (osl_isinus[angle] * dist) >> 14; +} + + +int oslGetNextPower2(int val) { + int i; + for (i=15;i>=0;i--) { + if (val & (1<>6; + u8 *dst2, *src2; + while (len--) { + *dst++ = *src; + *dst++ = *src; + *dst++ = *src; + *dst++ = *src; + *dst++ = *src; + *dst++ = *src; + *dst++ = *src; + *dst++ = *src; + } + len = (length & 63) >> 3; + while (len--) + *dst++ = *src; + dst2 = (u8*)dst; + src2 = (u8*)src; + len = (length & 7); + while (len--) + *dst2++ = *src2++; +} + +void oslWaitVSync() +{ +// osl_vblCount++; + sceDisplayWaitVblankStart(); +} + +inline void oslFlushDataCache() { + sceKernelDcacheWritebackInvalidateAll(); +} + +int oslMeanBenchmarkTestEx(int startend, int slot) { + static int val[OSL_BENCH_SLOTS]; + static struct timeval start[OSL_BENCH_SLOTS]; + struct timeval end; + static int curr_ms[OSL_BENCH_SLOTS], time[OSL_BENCH_SLOTS]; + + if (startend == OSL_BENCH_INIT) { + val[slot]=0; + time[slot]=0; + curr_ms[slot]=0; + gettimeofday(&start[slot],0); + } + else if (startend == OSL_BENCH_START) + gettimeofday(&start[slot],0); + else if (startend == OSL_BENCH_END) { + gettimeofday(&end,0); + time[slot] += (end.tv_sec - start[slot].tv_sec) * 1000000; + time[slot] += end.tv_usec - start[slot].tv_usec; + val[slot]++; + if (val[slot] >= OSL_BENCH_SAMPLES) + { + val[slot] = 0; + curr_ms[slot] = time[slot] / OSL_BENCH_SAMPLES; + time[slot] = 0; + } + } + //Returns the last measure + else if (startend == OSL_BENCH_GET_LAST) { + if (val[slot] != 0) + return time[slot] / val[slot]; + } + +/* else if (startend == OSL_BENCH_DISPLAY) { + pspDebugScreenSetXY(0,0); + pspDebugScreenPrintf("%i.%03i", curr_ms[slot]/1000, curr_ms[slot]%1000); + }*/ + return curr_ms[slot]; +} + +int oslBenchmarkTestEx(int startend, int slot) { + static struct timeval start[OSL_BENCH_SLOTS]; + struct timeval end; + static int time[OSL_BENCH_SLOTS]; + + if (startend == OSL_BENCH_START) + gettimeofday(&start[slot],0); + else if (startend == OSL_BENCH_END) { + gettimeofday(&end,0); + time[slot] = (end.tv_sec - start[slot].tv_sec) * 1000000; + time[slot] += end.tv_usec - start[slot].tv_usec; + } + return time[slot]; +} + +static int osl_exitCbId = 0; //<-- STAS: Store the OSL's standard exitcallback ID here + +void oslQuit() +{ //<-- STAS: Totally rewritten routine + osl_quit = 1; // OSL mustQuit mark for another threads + sceKernelDelayThread(500000); // Let another threads to handle osl_quit marker + + if (!osl_exitCbId) + sceKernelExitGame(); // We'll fall here if the OSL's exit callback was not set + else { + sceKernelNotifyCallback(osl_exitCbId, 0); // Wake up our exit callback + sceKernelSleepThreadCB(); // Sleep the thread forever... + } //<-- STAS END --> +} + +#ifdef PSP + /* Exit callback */ + int oslStandardExitCallback(int arg1, int arg2, void *common) + { + osl_quit = 1; + if (osl_exitCallback) + osl_exitCallback(arg1, arg2, common); + sceKernelExitGame(); //<-- STAS: It's a good pratice to place sceKernelExitGame() here ! + return 0; + } + + int oslStandardPowerCallback(int unknown, int pwrflags,void *common){ +// int cbid = sceKernelCreateCallback("powerCallback", oslStandardPowerCallback, NULL); +// scePowerRegisterCallback(0, cbid); + if (osl_powerCallback) + return osl_powerCallback(unknown, pwrflags, common); + else + return 0; + } + + /* Callback thread */ + int oslCallbackThread(SceSize args, void *argp) + { + int cbid; + + cbid = sceKernelCreateCallback("exitCallback", oslStandardExitCallback, NULL); + sceKernelRegisterExitCallback(cbid); + osl_exitCbId = cbid; //<-- STAS: store the exitcallback cbid for further use... + cbid = sceKernelCreateCallback("powerCallback", oslStandardPowerCallback,NULL ); + scePowerRegisterCallback(0, cbid ); + + sceKernelSleepThreadCB(); + + return 0; + } + + /* Sets up the callback thread and returns its thread id */ + int oslSetupCallbacks() + { + int thid = 0; + + thid = sceKernelCreateThread("update_thread", oslCallbackThread, 0x11, 0xFA0, 0, 0); + if(thid >= 0) + { + sceKernelStartThread(thid, 0, 0); + } + + return thid; + } +#endif + +//osl_currentFrameRate CANNOT be > 60! +volatile int osl_vblCount=0, osl_vblCountMultiple=0, osl_currentFrameRate, osl_vblCallCount=0, osl_skip=0, osl_nbSkippedFrames=0, osl_vblankCounterActive=1; +volatile int osl_vblShouldSwap = 0; + +void oslVblankNextFrame() { + osl_vblCountMultiple += osl_currentFrameRate; + //osl_currentFrameRate CANNOT be > 60! (else a while or a better method would be needed here) + if (osl_vblCountMultiple >= 60) { + osl_vblCountMultiple -= 60; + osl_vblCount++; + } +} + +void oslVblankInterrupt(int sub, void *parg) +{ + if (osl_vblankCounterActive) + oslVblankNextFrame(); + + //This is done so to avoid screen tearing when sound takes too long + if (osl_vblShouldSwap) { + oslSwapBuffers(); + osl_vblShouldSwap = 0; + } +} + +int osl_maxFrameskip=0, osl_vsyncEnabled=0, osl_frameskip=0; + +void oslInit(int flags) +{ + void *arg = 0; + int i; + + osl_keys = &osl_pad; + osl_remotekeys = &osl_remote; + + osl_quit = 0; + osl_vblCount = 0; + osl_vblCallCount = 0; + osl_skip = 0; + osl_nbSkippedFrames = 0; + osl_maxFrameskip=5; + osl_vsyncEnabled=4; + osl_frameskip=0; + osl_currentFrameRate = 60; + + //Configure l'autorepeat (il n'y en a pas au début) + oslSetKeyAutorepeat(OSL_KEYMASK_UP|OSL_KEYMASK_RIGHT|OSL_KEYMASK_DOWN|OSL_KEYMASK_LEFT|OSL_KEYMASK_R|OSL_KEYMASK_L,0,0); + +#ifdef PSP + if (!(flags & OSL_IF_USEOWNCALLBACKS)) + oslSetupCallbacks(); + + //No interrupt handler... + if (!(flags & OSL_IF_NOVBLANKIRQ)) { + sceKernelRegisterSubIntrHandler(PSP_VBLANK_INT,osl_vblInterruptNumber,oslVblankInterrupt,arg); + sceKernelEnableSubIntr(PSP_VBLANK_INT,osl_vblInterruptNumber); + } +#endif + for (i=0;i1: dépend de vsync, saute 1 frame sur X + + Max frameskip: + >=1: Frameskip maximum autorisé + VSync: + 0: pas de VSync + 1: vsync activée + +4: si on rajoute 4, avec un frameskip >1, synchronise au framerate souhaité, par ex. 2 -> 30 fps + +0: sinon, fixe le frameskip minimum (ex. avec 2, le jeu tournera à 60 fps, 30 images par seconde) + +8: synchro maximale (impression de triple buffering), sans vsync + +16: pas de swapbuffers + Exemples: + //30 fps (pas de frameskip) + oslSyncFrameEx(2,0,0); + //30 fps, jeu à 60, frameskip max de 2, c'est-à-dire pas plus d'une frame skippée pour une affichée + oslSyncFrameEx(2,2,4); + //synchronise à 60 fps + oslSyncFrameEx(0,0,0); +*/ + +#if 1 + +int oslSyncFrameEx(int frameskip, int max_frameskip, int vsync) +{ + #ifdef OSL_SYSTEM_BENCHMARK_ENABLED + int lastOslSkip; + #endif + int i, wasDrawing=0; + if (osl_isDrawingStarted) + oslEndDrawing(), wasDrawing=1; + if (frameskip==0) { + #ifdef OSL_SYSTEM_BENCHMARK_ENABLED + oslMeanBenchmarkTestEx(OSL_BENCH_END, 4); + oslMeanBenchmarkTestEx(OSL_BENCH_END, 6); + #endif + //Dans les temps -> vsync +/* i = osl_vblCount; + if (vsync || osl_vblCallCount+1 > i) { + oslWaitVSync(); + i++; + } + osl_vblCallCount = i;*/ + + //We need to do this outside of the handler to be more precise + osl_vblankCounterActive = 0; + if ((vsync & 5) || (osl_vblCallCount+1 > osl_vblCount)) { //<-- STAS: (vsync&5) is more adequate here + do { + oslWaitVSync(); + oslVblankNextFrame(); + } while (osl_vblCallCount+1 > osl_vblCount); //<-- STAS: check the condition AFTER VSync() ! + } + osl_vblCallCount = osl_vblCount; + osl_vblankCounterActive = 1; //<-- STAS: resume counter in the intr handler + + osl_skip = 0; + #ifdef OSL_SYSTEM_BENCHMARK_ENABLED + oslMeanBenchmarkTestEx(OSL_BENCH_START, 4); + oslMeanBenchmarkTestEx(OSL_BENCH_START, 6); + #endif + if (!(vsync & 16)) + oslSwapBuffers(); + } + else { + osl_vblCallCount++; //<-- STAS: osl_vblCallCount+=frameskip is not good here + // because it wouldn't change osl_vblCallCount%frameskip value ! + /*if (vsync&4) + osl_vblCallCount++; + else + osl_vblCallCount+=frameskip; <-- STAS END -->*/ + #ifdef OSL_SYSTEM_BENCHMARK_ENABLED + lastOslSkip = osl_skip; + if (osl_skip) + oslMeanBenchmarkTestEx(OSL_BENCH_END, 5); + else { + oslMeanBenchmarkTestEx(OSL_BENCH_END, 4); + } + #endif + //La référence quand vsync = 0 + i=((vsync&1) && !osl_skip && !(vsync&8))?1:0; + //On est en retard? <-- STAS: add frameskip-1 here + if ((osl_vblCount+i > osl_vblCallCount+frameskip-1 || (vsync&4 && osl_vblCallCount%frameskip)) && osl_nbSkippedFrames < max_frameskip-1) { + if (!osl_skip) { //La frame a été dessinée -> on l'affiche + #ifdef OSL_SYSTEM_BENCHMARK_ENABLED + oslMeanBenchmarkTestEx(OSL_BENCH_END, 6); + #endif + if (vsync&1) //Activer pour avoir vraiment la VSync + oslWaitVSync(); + if (!(vsync & 16)) + oslSwapBuffers(); + #ifdef OSL_SYSTEM_BENCHMARK_ENABLED + oslMeanBenchmarkTestEx(OSL_BENCH_START, 6); + #endif + } + osl_nbSkippedFrames++; + //Dernière fois -> la prochaine c'est en-dessous + if (frameskip > 1 && osl_vblCallCount%frameskip == frameskip - 1) + osl_skip = 0; + else + osl_skip = 1; + } + else { + #ifdef OSL_SYSTEM_BENCHMARK_ENABLED + if (!osl_skip) + oslMeanBenchmarkTestEx(OSL_BENCH_END, 6); + #endif + if (vsync&1 && !osl_skip) //Activer pour avoir vraiment la VSync + oslWaitVSync(); + //Dans les temps +/* i = osl_vblCount; + while (i < osl_vblCallCount + ((vsync & 8) ? (1 - osl_skip) : (0))) { + oslWaitVSync(); + i++; + }*/ + if (!(vsync&4)) //<-- STAS: add frameskip-1 to osl_vblCallCount + osl_vblCallCount+=frameskip-1; // in order to skip correct number of frames + //We need to do this outside of the handler to be more precise + osl_vblankCounterActive = 0; + while (osl_vblCount < osl_vblCallCount + ((vsync & 8) ? (1 - osl_skip) : (0))) { + oslWaitVSync(); + oslVblankNextFrame(); + } + osl_vblankCounterActive = 1; + + //La référence (meilleur frameskip), mais bidouillage +/* if (osl_vblCount < osl_vblCallCount) { + do { + oslWaitVSync(); + } while (osl_vblCount+1 <=osl_vblCallCount); + }*/ + if (!osl_skip) { + if (!(vsync & 16)) + oslSwapBuffers(); + } + #ifdef OSL_SYSTEM_BENCHMARK_ENABLED + if (!osl_skip) + oslMeanBenchmarkTestEx(OSL_BENCH_START, 6); + #endif + //Trop de frameskip tue le frameskip +// if (osl_nbSkippedFrames >= max_frameskip-1) //<-- STAS: this is ALWAYS true at this point ! + osl_vblCallCount = osl_vblCount; +// osl_nbSkippedFrames=0; //<-- STAS: osl_nbSkippedFrames shouldn't be reset here + osl_skip = 0; + //Bidouille pour le frameskip fixé -> on repasse en-dessus + if (vsync&4 && frameskip > 1 && osl_vblCallCount%frameskip == 0) + osl_skip = 1; + } + #ifdef OSL_SYSTEM_BENCHMARK_ENABLED + if (osl_skip) + oslMeanBenchmarkTestEx(OSL_BENCH_START, 5); + else + oslMeanBenchmarkTestEx(OSL_BENCH_START, 4); + #endif + } + if (!osl_skip) osl_nbSkippedFrames=0; //<-- STAS: reset the osl_nbSkippedFrames + if (wasDrawing) + oslStartDrawing(); + return osl_skip; +} +#else + +//Routine originale, écrite entre deux. La nouvelle est dégueulasse mais elle permet d'éviter le cisaillement du haut de l'écran quand un son demande trop de puissance. +#if 0 +static void waitNextFrame() { + osl_vblankCounterActive = 0; +// while (osl_vblCallCount >= osl_vblCount) { + oslWaitVSync(); + oslVblankNextFrame(); +// } + osl_vblankCounterActive = 1; +} + +int oslSyncFrameEx(int frameskip, int max_frameskip, int vsync) +{ +// int lastOslSkip = osl_skip; + int wasDrawing=0; + + if (osl_isDrawingStarted) + oslEndDrawing(), wasDrawing=1; + + //We need to do this outside of the handler to be more precise +// osl_vblankCounterActive = 0; + osl_vblCallCount++; + + #ifdef OSL_SYSTEM_BENCHMARK_ENABLED + if (!osl_skip) + oslMeanBenchmarkTestEx(OSL_BENCH_END, 4); + else + oslMeanBenchmarkTestEx(OSL_BENCH_END, 5); + #endif + + //Soit on est en retard, soit on a un frameskip fixé. oslMax => éviter une division par zéro ;) + if (osl_vblCallCount < osl_vblCount + || (osl_vblCallCount % oslMax(frameskip, 1))) { + //Do not skip more frames than indicated + osl_nbSkippedFrames++; + if (osl_nbSkippedFrames >= max_frameskip) { + osl_vblCallCount = osl_vblCount; + goto noskip; + } + osl_skip = 1; + #ifdef OSL_SYSTEM_BENCHMARK_ENABLED + oslMeanBenchmarkTestEx(OSL_BENCH_START, 5); + #endif + } + else { + /* + En mettant le label noskip ici au lieu d'en bas, on évite le problème qui fait que lorsqu'on dépasse le frameskip max la VSync n'est plus prise en compte. Dans ce cas la VSync est toujours + attendue, même si le frameskip max a été dépassé, alors que pour l'instant ce n'est pas le cas: si le frameskip max a été dépassé, la VSync n'est pas attendue, quel que soit le paramètre + Vsync actuel. + */ +noskip: + + #ifdef OSL_SYSTEM_BENCHMARK_ENABLED + //To measure the total time of a frame (until it has been swapped) + oslMeanBenchmarkTestEx(OSL_BENCH_END, 6); + #endif + + //Pour attendre la prochaine frame - toujours en mode VSync, si on a assez d'avance en mode Auto + /* + Note: Le fait qu'on le fasse lorsque le skip passe à zéro fait que le framerate se remet de lui même au max. possible, alors qu'en le mettant dans le cas où lastOslSkip est 0 "fixe" le framerate + à 30 fps, il est difficile de remonter, ça évite un peu les saccades aléatoires, à voir. + Attention: Pareil pour swapbuffers! + */ + if (vsync & 1) { + while (osl_vblCallCount >= osl_vblCount) + waitNextFrame(); + } + else { + while (osl_vblCallCount > osl_vblCount) + waitNextFrame(); + } + +//noskip: + osl_skip = 0; + osl_nbSkippedFrames = 0; + } + + //Pas de support pour le frameskip? On n'active jamais le skip. + if (!frameskip) + osl_skip = 0; + + #ifdef OSL_SYSTEM_BENCHMARK_ENABLED + if (!osl_skip) { + oslMeanBenchmarkTestEx(OSL_BENCH_START, 4); + oslMeanBenchmarkTestEx(OSL_BENCH_START, 6); + } + else { + oslMeanBenchmarkTestEx(OSL_BENCH_START, 5); + } + #endif + + //Flag 16 pour ne pas swapper les buffers + if (!(vsync & 16) && !osl_skip) { + oslSwapBuffers(); + } + + return osl_skip; +} + +#else + +#ifdef PSP +#define swap() ({ if (!(vsync & 16) && !swapped) osl_vblShouldSwap = 1; swapped = 1; }) +#else +#define swap() +#endif + +static void waitNextFrame() { + osl_vblankCounterActive = 0; +// while (osl_vblCallCount >= osl_vblCount) { + oslWaitVSync(); + oslVblankNextFrame(); +// } + osl_vblankCounterActive = 1; +} + +int oslSyncFrameEx(int frameskip, int max_frameskip, int vsync) +{ +// int lastOslSkip = osl_skip; + int wasDrawing=0, swapped = 0; + + if (osl_isDrawingStarted) + oslEndDrawing(), wasDrawing=1; + + //We need to do this outside of the handler to be more precise +// osl_vblankCounterActive = 0; + osl_vblCallCount++; + + #ifdef OSL_SYSTEM_BENCHMARK_ENABLED + if (!osl_skip) + oslMeanBenchmarkTestEx(OSL_BENCH_END, 4); + else + oslMeanBenchmarkTestEx(OSL_BENCH_END, 5); + #endif + + //Soit on est en retard, soit on a un frameskip fixé. oslMax => éviter une division par zéro ;) + if (osl_vblCallCount < osl_vblCount + || (osl_vblCallCount % oslMax(frameskip, 1))) { + //Do not skip more frames than indicated + osl_nbSkippedFrames++; + if (osl_nbSkippedFrames >= max_frameskip) { + osl_vblCallCount = osl_vblCount; + goto noskip; + } + osl_skip = 1; + #ifdef OSL_SYSTEM_BENCHMARK_ENABLED + oslMeanBenchmarkTestEx(OSL_BENCH_START, 5); + #endif + } + else { + /* + En mettant le label noskip ici au lieu d'en bas, on évite le problème qui fait que lorsqu'on dépasse le frameskip max la VSync n'est plus prise en compte. Dans ce cas la VSync est toujours + attendue, même si le frameskip max a été dépassé, alors que pour l'instant ce n'est pas le cas: si le frameskip max a été dépassé, la VSync n'est pas attendue, quel que soit le paramètre + Vsync actuel. + */ +noskip: + + #ifdef OSL_SYSTEM_BENCHMARK_ENABLED + //To measure the total time of a frame (until it has been swapped) + oslMeanBenchmarkTestEx(OSL_BENCH_END, 6); + #endif + + //Pour attendre la prochaine frame - toujours en mode VSync, si on a assez d'avance en mode Auto + /* + Note: Le fait qu'on le fasse lorsque le skip passe à zéro fait que le framerate se remet de lui même au max. possible, alors qu'en le mettant dans le cas où lastOslSkip est 0 "fixe" le framerate + à 30 fps, il est difficile de remonter, ça évite un peu les saccades aléatoires, à voir. + Attention: Pareil pour swapbuffers! + */ + if (vsync & 1) { + if (osl_vblCallCount >= osl_vblCount) { + swap(); + } + while (osl_vblCallCount >= osl_vblCount) + waitNextFrame(); + } + else { + if (osl_vblCallCount > osl_vblCount) { + swap(); + } + while (osl_vblCallCount > osl_vblCount) + waitNextFrame(); + } + +//noskip: + osl_skip = 0; + osl_nbSkippedFrames = 0; + } + + //Pas de support pour le frameskip? On n'active jamais le skip. + if (!frameskip) + osl_skip = 0; + + #ifdef OSL_SYSTEM_BENCHMARK_ENABLED + if (!osl_skip) { + oslMeanBenchmarkTestEx(OSL_BENCH_START, 4); + oslMeanBenchmarkTestEx(OSL_BENCH_START, 6); + } + else { + oslMeanBenchmarkTestEx(OSL_BENCH_START, 5); + } + #endif + + //Flag 16 pour ne pas swapper les buffers + if (!swapped && !(vsync & 16) && !osl_skip) { + oslSwapBuffers(); + } + + return osl_skip; +} +#endif +#endif + +/*int oslSyncFrameEx(int frameskip, int max_frameskip, int vsync) +{ + osl_vblCallCount++; + if (osl_vblCount > osl_vblCallCount) { + if (!osl_skip) { +// if (vsync) +// oslWaitVSync(); + oslSwapBuffers(); + } + osl_skip = 1; + } + else { + if (osl_vblCount <= osl_vblCallCount) { + do { + oslWaitVSync(); + } while (osl_vblCount+1 <=osl_vblCallCount); + } + if (!osl_skip) { + oslSwapBuffers(); + } + osl_nbSkippedFrames=0; + osl_skip = 0; + } + + return osl_skip; +}*/ + +void oslEndFrame() { + oslAudioVSync(); +} + diff --git a/oslib.h b/oslib.h index 369ec07..89b8a17 100644 --- a/oslib.h +++ b/oslib.h @@ -48,7 +48,7 @@ extern "C" { */ /** OSLib version */ -#define OSL_VERSION "MOD 1.1.0" +#define OSL_VERSION "MOD 1.1.1" extern int osl_intraInit; diff --git a/text.c b/text.c index cef831b..bd28812 100644 --- a/text.c +++ b/text.c @@ -272,6 +272,7 @@ OSL_FONTINFO osl_sceFontInfo= { 1, // 1 bit par pixel NULL, // Proportionnelle 7, 8, 1, // 7x8 (1 octet par ligne) + 0, 0, 0, NULL //<-- STAS: Initialize ALL the fontinfo fields ! }; //bitplanes: format (bits par pixel) de la fonte, imagePlanes: format de la texture à remplir (puissance de deux) @@ -315,6 +316,7 @@ OSL_FONT *oslLoadFont(OSL_FONTINFO *fi) f = (OSL_FONT*)malloc(sizeof(OSL_FONT)); if (!f) return NULL; + memset(f, 0, sizeof(OSL_FONT)); //<-- STAS: Initialize the OSL_FONT structure f->fontType = OSL_FONT_OFT; @@ -336,6 +338,7 @@ OSL_FONT *oslLoadFont(OSL_FONTINFO *fi) for (i=0;i<256;i++) f->charWidths[i] = fi->charWidth; f->isCharWidthConstant = 1; + f->charWidth = fi->charWidth; //<-- STAS: Initialize f->charWidth somehow... } //Position des caractères (pour les fontes non proportionnelles) f->charPositions = (u16*)malloc(256*sizeof(short)); @@ -370,15 +373,16 @@ OSL_FONT *oslLoadFont(OSL_FONTINFO *fi) //La palette f->img->palette = oslCreatePalette(16, OSL_PF_8888); if (!f->img->palette) { + oslDeleteImage(f->img); //<-- STAS: It would beter to do it before free(f) :-) free(f->charPositions); free(f->charWidths); free(f); - oslDeleteImage(f->img); +// oslDeleteImage(f->img); //<-- STAS: wow! f was just freed !!! return NULL; } if (fi->paletteCount) { - for (i=0;ipaletteCount;i++) + for (i=0;ipaletteCount,f->img->palette->nElements);i++) //<-- STAS: check i against oslMin(...) ! ((unsigned long*)f->img->palette->data)[i] = fi->paletteData[i]; } else { @@ -402,33 +406,13 @@ OSL_FONT *oslLoadFont(OSL_FONTINFO *fi) return f; } -int updateIntraFontCharWidth(OSL_FONT *font, intraFont *intra) -{ - if (!font || !intra) - return 0; - - font->charHeight = intra->texYSize; - if (!font->charWidths){ - font->charWidths = (u8*)malloc(256*sizeof(char)); - if (!font->charWidths) - return -1; - } - - int i = 0; - char tchar[2] = ""; - for (i=0; i<256; i++){ - tchar[0] = i; - font->charWidths[i] = (int)intraFontMeasureText(intra, tchar); - } - return 0; -} - OSL_FONT *oslLoadIntraFontFile(const char *filename, unsigned int options) { OSL_FONT *font = NULL; font = (OSL_FONT*)malloc(sizeof(OSL_FONT)); if (!font) return NULL; + memset(font, 0, sizeof(OSL_FONT)); //<-- STAS: Initialize the OSL_FONT structure font->fontType = OSL_FONT_INTRA; font->intra = intraFontLoad(filename, options); if (!font->intra){ @@ -437,8 +421,6 @@ OSL_FONT *oslLoadIntraFontFile(const char *filename, unsigned int options) { oslHandleLoadNoFailError(filename); }else{ intraFontSetStyle(font->intra, 1.0f, 0xFFFFFFFF, 0xFF000000, INTRAFONT_ALIGN_LEFT); - font->charWidths = NULL; - updateIntraFontCharWidth(font, font->intra); font->charHeight = font->intra->texYSize; } return font; @@ -468,8 +450,11 @@ OSL_FONT *oslLoadFontFile(const char *filename) { unsigned char tcTaillesCar[256], *tcCaracteres; char *start = (char *)filename + (strlen(filename) - 4); - if (!strncmp(start, ".pgf", 4) || !strncmp(start, ".PGF", 4)){ - font = (OSL_FONT*)malloc(sizeof(OSL_FONT)); + char *bwfon = (char *)filename + (strlen(filename) - 6); //<-- STAS: BWFON intrafont support + if (!strncmp(start, ".pgf", 4) || !strncmp(start, ".PGF", 4) || + !strncmp(bwfon, ".bwfon", 6) || !strncmp(bwfon, ".BWFON", 6)) { + font = oslLoadIntraFontFile(filename, intra_options); //<-- STAS: just to get rid of duplicate code +/* font = (OSL_FONT*)malloc(sizeof(OSL_FONT)); if (!font) return NULL; font->fontType = OSL_FONT_INTRA; @@ -481,14 +466,7 @@ OSL_FONT *oslLoadFontFile(const char *filename) { }else{ intraFontSetStyle(font->intra, 1.0f, 0xFFFFFFFF, 0xFF000000, INTRAFONT_ALIGN_LEFT); font->charHeight = font->intra->texYSize; - font->charWidths = NULL; - - if (updateIntraFontCharWidth(font, font->intra)){ - free(font); - font = NULL; - oslHandleLoadNoFailError(filename); - } - } + } //<-- STAS END --> */ }else{ f = VirtualFileOpen((void*)filename, 0, VF_AUTO, VF_O_READ); if (f) { @@ -554,8 +532,6 @@ void oslDeleteFont(OSL_FONT *f) { } intraFontUnload(f->intra); f->intra = NULL; - free(f->charWidths); - f->charWidths = NULL; }else if (f->fontType == OSL_FONT_OFT){ oslDeleteImage(f->img); free(f->charPositions); @@ -573,7 +549,8 @@ void oslDrawTextTileBack(int x, int y, int tX, int tY) { OSL_LINE_VERTEX_COLOR32 *vertices; vertices = (OSL_LINE_VERTEX_COLOR32*)sceGuGetMemory(2 * sizeof(OSL_LINE_VERTEX_COLOR32)); - x += osl_curFont->addedSpace; +// x += osl_curFont->addedSpace; //<-- STAS: tX seems to be more appropiate here :-) + tX += osl_curFont->addedSpace; //<-- STAS END --> vertices[0].color = color; vertices[0].x = x; @@ -649,10 +626,12 @@ void oslDrawChar(int x, int y, unsigned char c) void oslDrawString(int x, int y, const char *str) { + if (!osl_curFont) //<-- STAS: it would nice to check it here + return; //<-- STAS END --> if (osl_curFont->fontType == OSL_FONT_OFT){ unsigned char c; - if (!osl_curFont) - return; +// if (!osl_curFont) //<-- STAS: strange place for such a check :-(( +// return; //<-- STAS END --> oslSetTexture(osl_curFont->img); while(*str) { c = *(unsigned char*)str++; @@ -668,11 +647,13 @@ void oslDrawString(int x, int y, const char *str) void oslDrawStringLimited(int x, int y, int width, const char *str) { + if (!osl_curFont) //<-- STAS: it would nice to check it here + return; //<-- STAS END --> if (osl_curFont->fontType == OSL_FONT_OFT){ int limitX = x + width; unsigned char c; - if (!osl_curFont) - return; +// if (!osl_curFont) //<-- STAS: strange place for such a check :-(( +// return; //<-- STAS END --> oslSetTexture(osl_curFont->img); while(*str) { c = *(unsigned char*)str++; @@ -688,6 +669,9 @@ void oslDrawStringLimited(int x, int y, int width, const char *str) void oslDrawTextBox(int x0, int y0, int x1, int y1, const char *text, int format) { + if (!osl_curFont || osl_curFont->fontType != OSL_FONT_OFT) //<-- STAS: it would nice to check it here + return; //<-- STAS END --> + int x,y, x2; unsigned char c; const char *text2; @@ -814,6 +798,9 @@ int oslGetStringWidth(const char *str) int oslGetTextBoxHeight(int width, int maxHeight, const char *text, int format) { + if (!osl_curFont || osl_curFont->fontType != OSL_FONT_OFT) //<-- STAS: it would nice to check it here + return 0; //<-- STAS END --> + int x,y, x2; unsigned char c, newLine = 1; const char *text2; @@ -874,7 +861,6 @@ void oslIntraFontShutdown(){ void oslIntraFontSetStyle(OSL_FONT *f, float size, unsigned int color, unsigned int shadowColor, unsigned int options){ if (f->intra){ intraFontSetStyle(f->intra, size, color, shadowColor, options); - updateIntraFontCharWidth(f, f->intra); if(f->intra->altFont) intraFontSetStyle(f->intra->altFont, size, color, shadowColor, options); }