commit 56b69d2281cbcf75bb6a7a88e04e90a4da81caa6 Author: Godzil Date: Sun Sep 1 21:43:40 2019 +0100 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3e94626 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +.DS_Store +*.bak +*.o +*.bin +*.wsc +*~ +testserial +wonderswan +*.orig +*.rej diff --git a/oswan/Makefile b/oswan/Makefile new file mode 100644 index 0000000..3d718e4 --- /dev/null +++ b/oswan/Makefile @@ -0,0 +1,54 @@ + +wonderswan_CXX_SRCS = main.cpp \ + source/2xSaI.cpp \ + source/audio.cpp \ + source/gpu.cpp \ + source/io.cpp \ + source/log.cpp \ + source/memory.cpp \ + source/rom.cpp \ + source/ws.cpp \ + source/nec/nec.cpp + +OBJS = $(wonderswan_CXX_SRCS:.cpp=.o) + + + +all: wonderswan + +CXX = clang++ +CXXFLAGS = -g -O2 `sdl-config --cflags` -arch i386 +OPTIONS = -D_REENTRANT -I. -I../seal-hack/include + +LIBRARY_PATH = -L../seal-hack/lib/SDL +LIBS = -g $(LIBRARY_PATH) `sdl-config --libs` -arch i386 + +ALLCFLAGS = $(CFLAGS) $(CEXTRA) $(OPTIONS) $(ALLFLAGS) +ALLCXXFLAGS=$(CXXFLAGS) $(CXXEXTRA) $(OPTIONS) $(ALLFLAGS) + +CLEAN_FILES = wonderswan + +.SUFFIXES: .cpp + +main.o: main.cpp source/filters/2xsai.h source/filters/doubled.h source/filters/filter_partA.h source/filters/filter_partB.h source/filters/filter_partC.h source/filters/filter_partD.h source/filters/filter_partE.h source/filters/halfscanlines.h source/filters/interpolate.h source/filters/scanlines.h source/filters/special.h source/filters/standard.h source/filters/super2xsai.h source/filters/supereagle.h source/SDLptc.h + $(CXX) -c $(ALLCXXFLAGS) -o $@ $< + +.c.o: + $(CC) -c $(ALLCFLAGS) -o $@ $< + +.cpp.o: + $(CXX) -c $(ALLCXXFLAGS) -o $@ $< + +.PHONY: all install uninstall clean distclean depend dummy + +$(SUBDIRS:%=%/__clean__): dummy + cd `dirname $@` && $(MAKE) clean + +$(EXTRASUBDIRS:%=%/__clean__): dummy + -cd `dirname $@` && $(RM) $(CLEAN_FILES) + +clean:: $(SUBDIRS:%=%/__clean__) $(EXTRASUBDIRS:%=%/__clean__) + $(RM) $(CLEAN_FILES) $(RC_SRCS:.rc=.res) $(OBJS) $(EXES:%.exe=%) $(EXES:%=%.so) $(EXES:%=%.spec.o) $(DLLS:%=%.so) $(DLLS:%=%.spec.o) + +wonderswan: $(OBJS) + $(CXX) $(LIBS) -o $@ $(OBJS) -laudio diff --git a/oswan/Wondersnake.txt b/oswan/Wondersnake.txt new file mode 100644 index 0000000..6bdddc7 --- /dev/null +++ b/oswan/Wondersnake.txt @@ -0,0 +1,32 @@ + _____ _____ ___ _ __ + \ | /___ /\__ ___> /___ /\__ ___ /\__ ___ | |/ / ___ + \ / \ // .\/ . \/ . // __\/ _// __>/ . \/. || < / __\ + \_____/ \___/\_/\_/\___/ \___/\_/ <___ \\_/\_/\___||_|\_\\___/ + --- Wondersnake for WSC -------------\___/----- 09. 11. 2001 --- + + This game is Freeware! You are more than welcome to copy it to + your friends or anyone else! Please note that it is not allowed + to charge any money for this game in any case! It is Freeware and + it will stay Freeware! + + ................................................................. + : Code: Dox dox@space.pl http://cygne.emuunlim.com : + : Gfx: Dox dox@space.pl http://cygne.emuunlim.com : + : Levels: Kojote kojote1980@yahoo.com http://www.pdroms.com : + :...............................................................: + + Special "Thank you" goes out to Sir Dragoon for Hardwaretesting! + (Yes... Wondersnake will work on real Hardware!!!) But it will + even work on the latest version of Cygne! URL above... + + Since some people were complaining that we forgot to mention them + in some of our previous productions, we want to greet everyone who + knows us ;) ... but Kojote want's to greet his wife "Amina" ;)) + + We hope you'll enjoy Wondersnake for Wonderswan Color, and if you + like it, please sent Feedback to both of us! + + ===================== + Regards, Dox & Kojote + ===================== + diff --git a/oswan/gui.aps b/oswan/gui.aps new file mode 100644 index 0000000..6e47ca5 Binary files /dev/null and b/oswan/gui.aps differ diff --git a/oswan/gui.rc b/oswan/gui.rc new file mode 100644 index 0000000..f6357a4 --- /dev/null +++ b/oswan/gui.rc @@ -0,0 +1,150 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// French (France) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA) +#ifdef _WIN32 +LANGUAGE LANG_FRENCH, SUBLANG_FRENCH +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG_MAIN DIALOG DISCARDABLE 0, 0, 283, 236 +STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Oswan 0.70" +FONT 8, "MS Sans Serif" +BEGIN + PUSHBUTTON "&Load",IDC_BUTTON_LOAD,25,170,80,14 + PUSHBUTTON "&Reset",IDC_BUTTON_RESET,110,170,50,14 + PUSHBUTTON "&Exit",IDC_BUTTON_EXIT,170,170,85,14 + GROUPBOX "Video mode",IDC_STATIC,105,30,60,40 + CONTROL "Windowed",IDC_RADIO_WINDOWED,"Button", + BS_AUTORADIOBUTTON | WS_GROUP,111,40,49,10 + CONTROL "Fullscreen",IDC_RADIO_FULLSCREEN,"Button", + BS_AUTORADIOBUTTON,111,54,49,10 + PUSHBUTTON "L&oad state",IDC_BUTTON_LOADSTATE,170,110,85,14 + PUSHBUTTON "&Save state",IDC_BUTTON_SAVESTATE,170,130,85,14 + GROUPBOX "Video enhancement",IDC_STATIC,25,30,75,135 + CONTROL 102,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,1,1,281,23 + GROUPBOX "System",IDC_STATIC,171,30,85,55 + CONTROL "Autodetect",IDC_RADIO_SYSTEM_AUTODETECT,"Button", + BS_AUTORADIOBUTTON | WS_GROUP,175,41,51,10 + CONTROL "Wonderswan mono",IDC_RADIO_SYSTEM_MONO,"Button", + BS_AUTORADIOBUTTON,175,54,77,10 + CONTROL "Wonderswan color",IDC_RADIO_SYSTEM_COLOR,"Button", + BS_AUTORADIOBUTTON,175,70,75,10 + CONTROL 103,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN | + WS_BORDER,0,192,283,43 + GROUPBOX "Colour scheme",IDC_STATIC,105,75,60,90 + CONTROL "Default",IDC_COLOUR_DEFAULT,"Button",BS_AUTORADIOBUTTON | + WS_GROUP,111,86,39,10 + CONTROL "Amber",IDC_COLOUR_AMBER,"Button",BS_AUTORADIOBUTTON,111, + 100,36,10 + CONTROL "Green",IDC_COLOUR_GREEN,"Button",BS_AUTORADIOBUTTON,111, + 116,35,10 + PUSHBUTTON "&Return to game",IDC_BUTTON_CONTINUE,170,90,85,14 + PUSHBUTTON "Co&nfigure controls",IDC_BUTTON_CONTROLS,170,150,85,14, + WS_DISABLED + CONTROL "None",IDC_RADIO_STANDARD_MODE,"Button", + BS_AUTORADIOBUTTON | WS_GROUP,31,41,60,10 + CONTROL "Double size",IDC_RADIO_DOUBLESIZE_MODE,"Button", + BS_AUTORADIOBUTTON,31,54,60,10 + CONTROL "Scanlines",IDC_RADIO_SCANLINES_MODE,"Button", + BS_AUTORADIOBUTTON,31,70,60,10 + CONTROL "50% scanlines",IDC_RADIO_50PRCTSCANLINES_MODE,"Button", + BS_AUTORADIOBUTTON,31,86,60,10 + CONTROL "Special",IDC_RADIO_SPECIAL_MODE,"Button", + BS_AUTORADIOBUTTON,31,99,60,10 + CONTROL "2xSaI",IDC_RADIO_2XSAI,"Button",BS_AUTORADIOBUTTON,31, + 114,60,10 + CONTROL "Super 2xSaI",IDC_RADIO_SUPER2XSAI,"Button", + BS_AUTORADIOBUTTON,31,130,60,10 + CONTROL "Super Eagle",IDC_RADIO_SUPEREAGLE,"Button", + BS_AUTORADIOBUTTON,31,145,60,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_DIALOG_MAIN, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 276 + TOPMARGIN, 6 + BOTTOMMARGIN, 229 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_BITMAP1 BITMAP DISCARDABLE "source\\gui\\logo.bmp" +IDB_BITMAP2 BITMAP DISCARDABLE "source\\gui\\sponsor.bmp" +#endif // French (France) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/oswan/hexdump b/oswan/hexdump new file mode 100644 index 0000000..e69de29 diff --git a/oswan/main.cpp b/oswan/main.cpp new file mode 100644 index 0000000..b48456e --- /dev/null +++ b/oswan/main.cpp @@ -0,0 +1,650 @@ +/////////////////////////////////////////////////////////////////////////////// +// Wonderswan emulator +//////////////////////////////////////////////////////////////////////////////// +// +// 13.04.2002: Fixed a small bug causing crashes +// +// +// +// +////////////////////////////////////////////////////////////////////////////// + +/*#include +#include + +#include */ + +#include +#include +#include +#include +#include +#include +//#include "resource.h" +#include "SDL.h" +#include "source/types.h" +#include "source/SDLptc.h" +#include "source/log.h" +#include "source/rom.h" +#include "source/nec/nec.h" +#include "source/memory.h" +#include "source/gpu.h" +#include "source/io.h" +#include "source/ws.h" +#include "source/ticker.h" +#include "source/2xSaI.h" +#include "source/audio.h" + +#undef DWORD +#include + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +#define LOG_PATH "wswan.log" + +#define KEY_ENTER 0x0D +#define KEY_SPACE 0x20 +#define KEY_ESC 0x1b +#define KEY_UP 0x26 +#define KEY_DOWN 0x28 +#define KEY_LEFT 0x25 +#define KEY_RIGHT 0x27 +#define KEY_BUTTON1 0x57 +#define KEY_BUTTON2 0x58 + +#define GUI_COMMAND_NONE 0 +#define GUI_COMMAND_RESET 1 +#define GUI_COMMAND_SCHEME_CHANGE 2 +#define GUI_COMMAND_FILTER_CHANGE 3 + +char *app_window_title="Oswan 0.70 - Esc to return to GUI"; +int app_gameRunning=0; +int app_terminate=0; +int app_fullscreen=0; +SDL_Event app_input_event; +int app_rotated=0; + +int gui_command=GUI_COMMAND_NONE; +int gui_mainDialogRunning; +int gui_controls_configuration_Running; +int gui_get_key_Running; +int gui_get_key_key; +SDL_Joystick *joystick=NULL; + +int ws_videoEnhancementType=0; +int ws_colourScheme=COLOUR_SCHEME_DEFAULT; +int ws_system=WS_SYSTEM_COLOR; +char *ws_rom_path; +extern char *ws_sram_path; +int sram_path_explicit = 0; +char old_rom_path[4096]; + +#if 0 +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +char *gui_getRomPath(HWND hWnd) +{ + static OPENFILENAME ofn; // common dialog box structure + static char szFile[260]; // buffer for file name + HWND hwnd; // owner window + HANDLE hf; // file handle + static char oldDir[1024]; + + InitCommonControls(); + _getcwd(oldDir,1024); + szFile[0]=0; + // Initialize OPENFILENAME + ZeroMemory(&ofn, sizeof(OPENFILENAME)); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = NULL; + ofn.lpstrFile = szFile; + ofn.nMaxFile = sizeof(szFile); + ofn.lpstrFilter = "Wonderswan mono\0*.ws\0Wonderswan color\0*.wsc\0\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + ofn.hInstance=NULL; + // Display the Open dialog box. + + if (GetOpenFileName(&ofn)==TRUE) + return(ofn.lpstrFile); + chdir(oldDir); + return(NULL); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +char *gui_loadState(HWND hWnd) +{ + static OPENFILENAME ofn; // common dialog box structure + static char szFile[260]; // buffer for file name + HWND hwnd; // owner window + HANDLE hf; // file handle + static char oldDir[1024]; + + InitCommonControls(); + _getcwd(oldDir,1024); + szFile[0]=0; + // Initialize OPENFILENAME + ZeroMemory(&ofn, sizeof(OPENFILENAME)); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = NULL; + ofn.lpstrFile = szFile; + ofn.nMaxFile = sizeof(szFile); + ofn.lpstrFilter = "Wonderswan state\0*.wss\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + ofn.hInstance=NULL; + // Display the Open dialog box. + + if (GetOpenFileName(&ofn)==TRUE) + return(ofn.lpstrFile); + chdir(oldDir); + return(NULL); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +char *gui_saveState(HWND hWnd) +{ + static OPENFILENAME ofn; // common dialog box structure + static char szFile[260]; // buffer for file name + HWND hwnd; // owner window + HANDLE hf; // file handle + static char oldDir[1024]; + + InitCommonControls(); + _getcwd(oldDir,1024); + szFile[0]=0; + // Initialize OPENFILENAME + ZeroMemory(&ofn, sizeof(OPENFILENAME)); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = NULL; + ofn.lpstrFile = szFile; + ofn.nMaxFile = sizeof(szFile); + ofn.lpstrFilter = "Wonderswan state\0*.wss\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.Flags = 0; + ofn.hInstance=NULL; + // Display the Open dialog box. + + if (GetSaveFileName(&ofn)==TRUE) + return(ofn.lpstrFile); + chdir(oldDir); + return(NULL); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +BOOL CALLBACK GuiMainDialogProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + static BOOL bButton = FALSE; + + + switch(message) + { + case WM_INITDIALOG: + break; + + case WM_CLOSE: + { + gui_mainDialogRunning=0; + DestroyWindow(hWnd); + return 1; + } + case WM_COMMAND: + { + + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_BUTTON_LOAD)) + { + ws_rom_path=gui_getRomPath(hWnd); + if (ws_rom_path) + SendMessage(hWnd, WM_CLOSE, 0,0); + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_BUTTON_SAVESTATE)) + { + char *path=gui_saveState(hWnd); + if (path) + { + int err=ws_saveState(path); + if (err==0) + MessageBox(hWnd,"State cannot be saved","Error",MB_OK); + else + SendMessage(hWnd, WM_CLOSE, 0,0); + } + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_BUTTON_LOADSTATE)) + { + char *path=gui_loadState(hWnd); + if (path) + { + int err=ws_loadState(path); + if (err==0) + MessageBox(hWnd,"State cannot be loaded","Error",MB_OK); + else + if (err==-1) + MessageBox(hWnd,"Please load the correct rom first","Error",MB_OK); + else + SendMessage(hWnd, WM_CLOSE, 0,0); + } + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_BUTTON_RESET)) + { + gui_command=GUI_COMMAND_RESET; + SendMessage(hWnd, WM_CLOSE, 0,0); + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_BUTTON_CONTINUE)) + { + SendMessage(hWnd, WM_CLOSE, 0,0); + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_BUTTON_EXIT)) + { + SendMessage(hWnd, WM_CLOSE, 0,0); + app_terminate=1; + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_RADIO_STANDARD_MODE)) + { + if (SendMessage(GetDlgItem(hWnd, IDC_RADIO_STANDARD_MODE),BM_GETCHECK ,0,0)==BST_CHECKED) + ws_videoEnhancementType=0; + gui_command=GUI_COMMAND_FILTER_CHANGE; + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_RADIO_DOUBLESIZE_MODE)) + { + if (SendMessage(GetDlgItem(hWnd, IDC_RADIO_DOUBLESIZE_MODE),BM_GETCHECK ,0,0)==BST_CHECKED) + ws_videoEnhancementType=1; + gui_command=GUI_COMMAND_FILTER_CHANGE; + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_RADIO_SCANLINES_MODE)) + { + if (SendMessage(GetDlgItem(hWnd, IDC_RADIO_SCANLINES_MODE),BM_GETCHECK ,0,0)==BST_CHECKED) + ws_videoEnhancementType=2; + gui_command=GUI_COMMAND_FILTER_CHANGE; + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_RADIO_50PRCTSCANLINES_MODE)) + { + if (SendMessage(GetDlgItem(hWnd, IDC_RADIO_50PRCTSCANLINES_MODE),BM_GETCHECK ,0,0)==BST_CHECKED) + ws_videoEnhancementType=3; + gui_command=GUI_COMMAND_FILTER_CHANGE; + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_RADIO_SPECIAL_MODE)) + { + if (SendMessage(GetDlgItem(hWnd, IDC_RADIO_SPECIAL_MODE),BM_GETCHECK ,0,0)==BST_CHECKED) + ws_videoEnhancementType=4; + gui_command=GUI_COMMAND_FILTER_CHANGE; + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_RADIO_2XSAI)) + { + if (SendMessage(GetDlgItem(hWnd, IDC_RADIO_2XSAI),BM_GETCHECK ,0,0)==BST_CHECKED) + ws_videoEnhancementType=5; + gui_command=GUI_COMMAND_FILTER_CHANGE; + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_RADIO_SUPER2XSAI)) + { + if (SendMessage(GetDlgItem(hWnd, IDC_RADIO_SUPER2XSAI),BM_GETCHECK ,0,0)==BST_CHECKED) + ws_videoEnhancementType=6; + gui_command=GUI_COMMAND_FILTER_CHANGE; + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_RADIO_SUPEREAGLE)) + { + if (SendMessage(GetDlgItem(hWnd, IDC_RADIO_SUPEREAGLE),BM_GETCHECK ,0,0)==BST_CHECKED) + ws_videoEnhancementType=7; + gui_command=GUI_COMMAND_FILTER_CHANGE; + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_RADIO_FULLSCREEN)) + { + if (SendMessage(GetDlgItem(hWnd, IDC_RADIO_FULLSCREEN),BM_GETCHECK ,0,0)==BST_CHECKED) + app_fullscreen=1; + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_RADIO_WINDOWED)) + { + if (SendMessage(GetDlgItem(hWnd, IDC_RADIO_WINDOWED),BM_GETCHECK ,0,0)==BST_CHECKED) + app_fullscreen=0; + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_COLOUR_DEFAULT)) + { + if (SendMessage(GetDlgItem(hWnd, IDC_COLOUR_DEFAULT),BM_GETCHECK ,0,0)==BST_CHECKED) + ws_colourScheme=COLOUR_SCHEME_DEFAULT; + gui_command=GUI_COMMAND_SCHEME_CHANGE; + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_COLOUR_AMBER)) + { + if (SendMessage(GetDlgItem(hWnd, IDC_COLOUR_AMBER),BM_GETCHECK ,0,0)==BST_CHECKED) + ws_colourScheme=COLOUR_SCHEME_AMBER; + gui_command=GUI_COMMAND_SCHEME_CHANGE; + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_COLOUR_GREEN)) + { + if (SendMessage(GetDlgItem(hWnd, IDC_COLOUR_GREEN),BM_GETCHECK ,0,0)==BST_CHECKED) + ws_colourScheme=COLOUR_SCHEME_GREEN; + gui_command=GUI_COMMAND_SCHEME_CHANGE; + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_RADIO_SYSTEM_AUTODETECT)) + { + if (SendMessage(GetDlgItem(hWnd, IDC_RADIO_SYSTEM_AUTODETECT),BM_GETCHECK ,0,0)==BST_CHECKED) + ws_system=WS_SYSTEM_AUTODETECT; + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_RADIO_SYSTEM_COLOR)) + { + if (SendMessage(GetDlgItem(hWnd, IDC_RADIO_SYSTEM_COLOR),BM_GETCHECK ,0,0)==BST_CHECKED) + ws_system=WS_SYSTEM_COLOR; + return 1; + } + if ((HIWORD(wParam)==BN_CLICKED)&&(LOWORD(wParam)==IDC_RADIO_SYSTEM_MONO)) + { + if (SendMessage(GetDlgItem(hWnd, IDC_RADIO_SYSTEM_MONO),BM_GETCHECK ,0,0)==BST_CHECKED) + ws_system=WS_SYSTEM_MONO; + return 1; + } + } + } + if(message == WM_INITDIALOG) + return(TRUE); + return (FALSE); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void gui_open(void) +{ + HWND hwnd, hCtrl; + MSG msg; + + gui_command=GUI_COMMAND_NONE; + InitCommonControls(); + ws_rom_path=NULL; + hwnd = CreateDialog(gui_hInstance, MAKEINTRESOURCE(IDD_DIALOG_MAIN), NULL, (DLGPROC)GuiMainDialogProc); + + if (hwnd==NULL) + { + MessageBox(NULL,"Cannot create gui","Error",MB_OK); + return; + } + if (ws_colourScheme==COLOUR_SCHEME_DEFAULT) + SendMessage(GetDlgItem(hwnd, IDC_COLOUR_DEFAULT),BM_SETCHECK ,(WPARAM)BST_CHECKED,0); + else + if (ws_colourScheme==COLOUR_SCHEME_AMBER) + SendMessage(GetDlgItem(hwnd, IDC_COLOUR_AMBER),BM_SETCHECK ,(WPARAM)BST_CHECKED,0); + else + if (ws_colourScheme==COLOUR_SCHEME_GREEN) + SendMessage(GetDlgItem(hwnd, IDC_COLOUR_GREEN),BM_SETCHECK ,(WPARAM)BST_CHECKED,0); + + if (ws_videoEnhancementType==0) + SendMessage(GetDlgItem(hwnd, IDC_RADIO_STANDARD_MODE),BM_SETCHECK ,(WPARAM)BST_CHECKED,0); + else + if (ws_videoEnhancementType==1) + SendMessage(GetDlgItem(hwnd, IDC_RADIO_DOUBLESIZE_MODE),BM_SETCHECK ,(WPARAM)BST_CHECKED,0); + else + if (ws_videoEnhancementType==2) + SendMessage(GetDlgItem(hwnd, IDC_RADIO_SCANLINES_MODE),BM_SETCHECK ,(WPARAM)BST_CHECKED,0); + else + if (ws_videoEnhancementType==3) + SendMessage(GetDlgItem(hwnd, IDC_RADIO_50PRCTSCANLINES_MODE),BM_SETCHECK ,(WPARAM)BST_CHECKED,0); + else + if (ws_videoEnhancementType==4) + SendMessage(GetDlgItem(hwnd, IDC_RADIO_SPECIAL_MODE),BM_SETCHECK ,(WPARAM)BST_CHECKED,0); + else + if (ws_videoEnhancementType==5) + SendMessage(GetDlgItem(hwnd, IDC_RADIO_2XSAI),BM_SETCHECK ,(WPARAM)BST_CHECKED,0); + else + if (ws_videoEnhancementType==6) + SendMessage(GetDlgItem(hwnd, IDC_RADIO_SUPER2XSAI),BM_SETCHECK ,(WPARAM)BST_CHECKED,0); + else + if (ws_videoEnhancementType==7) + SendMessage(GetDlgItem(hwnd, IDC_RADIO_SUPEREAGLE),BM_SETCHECK ,(WPARAM)BST_CHECKED,0); + + if (app_fullscreen) + SendMessage(GetDlgItem(hwnd, IDC_RADIO_FULLSCREEN),BM_SETCHECK ,(WPARAM)BST_CHECKED,0); + else + SendMessage(GetDlgItem(hwnd, IDC_RADIO_WINDOWED),BM_SETCHECK ,(WPARAM)BST_CHECKED,0); + + if (ws_system==WS_SYSTEM_AUTODETECT) + SendMessage(GetDlgItem(hwnd, IDC_RADIO_SYSTEM_AUTODETECT),BM_SETCHECK ,(WPARAM)BST_CHECKED,0); + else + if (ws_system==WS_SYSTEM_COLOR) + SendMessage(GetDlgItem(hwnd, IDC_RADIO_SYSTEM_COLOR),BM_SETCHECK ,(WPARAM)BST_CHECKED,0); + else + if (ws_system==WS_SYSTEM_MONO) + SendMessage(GetDlgItem(hwnd, IDC_RADIO_SYSTEM_MONO),BM_SETCHECK ,(WPARAM)BST_CHECKED,0); + + gui_mainDialogRunning=1; + ShowWindow(hwnd, SW_SHOWDEFAULT); + UpdateWindow(hwnd); + + while(gui_mainDialogRunning) + { + if (GetMessage(&msg, hwnd, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + DestroyWindow(hwnd); +} + +#endif + +int ws_mk_savpath() +{ + char *w; + + if (sram_path_explicit) return 0; + + if (ws_sram_path != NULL) free(ws_sram_path); + ws_sram_path = (char *)malloc(strlen(ws_rom_path) + 2); + strcpy(ws_sram_path, ws_rom_path); + w = strrchr(ws_sram_path, '.'); + if (NULL == w) + { + strcpy(ws_sram_path, "error.sav"); + return 1; + } + strcpy(w, ".sav"); + return 0; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +#include "./source/filters/standard.h" +#include "./source/filters/doubled.h" +#include "./source/filters/scanlines.h" +#include "./source/filters/halfscanlines.h" +#include "./source/filters/2xsai.h" +#include "./source/filters/super2xsai.h" +#include "./source/filters/supereagle.h" +#include "./source/filters/special.h" + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// + +int main(int argc, char *argv[]) +{ + atexit(SDL_Quit); + SDL_Init(SDL_INIT_TIMER); + if (!log_init(LOG_PATH)) printf("Warning: cannot open log file %s\n",LOG_PATH); + fprintf(log_get(),"Wonderswan emulator v0.70/portable (built at: %s %s)\n",__DATE__,__TIME__); + //fprintf(log_get(),"port hacking by hmaon@bumba.net\n"); + ws_videoEnhancementType=1; + //ws_system = WS_SYSTEM_AUTODETECT; + ws_system = WS_SYSTEM_COLOR; + + Init_2xSaI(555); + ws_rom_path = NULL; + /*gui_hInstance=hInstance; + gui_open();*/ + + // the hard-core UI, a command line: + for (int n = 1; n < argc; ++n) + { + if (argv[n][0] == '-') + { + switch(argv[n][1]) + { + case 'E': + if (++n < argc) ws_videoEnhancementType = atoi(argv[n]); + else + { + fprintf(stderr, "\n0 - plain\n1 - doubled\n2 - scanlines\n3 - 1/2 bright scanlines\n4 - \"special\"\n5 - 2xSaI\n6 - Super2xSaI (default)\n7 - SuperEagle\n\n"); + exit(1); + } + + break; + case 'C': + if (++n < argc) ws_cyclesByLine = atoi(argv[n]); + fprintf(log_get(), "Cycles by line set to %d\n", ws_cyclesByLine); + break; + case 'w': + if (++n < argc) ws_system = atoi(argv[n]); + fprintf(log_get(), "WonderSwan set to %d\n", ws_system); + break; + case 's': + if (++n < argc) ws_sram_path = argv[n]; + sram_path_explicit = 1; + break; + + default: + break; + } + } else + { + ws_rom_path = argv[n]; + ws_mk_savpath(); + } + } + + while (!app_terminate) + { + if (!ws_rom_path) + { + app_gameRunning=0; + //gui_open(); + exit(0); // nothing to wait for at the moment... + } + if (ws_rom_path) + { + if (ws_init(ws_rom_path)) + { + app_rotated=ws_rotated(); + app_gameRunning=1; + ws_set_system(ws_system); + if (ws_system == WS_SYSTEM_COLOR) + ws_gpu_operatingInColor=1; + ws_set_colour_scheme(ws_colourScheme); + ws_buildHalfBrightnessTable(); + ws_reset(); + switch (ws_videoEnhancementType) + { + case 0: ws_emulate_standard(); break; + case 1: ws_emulate_doubled(); break; + case 2: ws_emulate_scanlines(); break; + case 3: ws_emulate_halfBrightnessScanlines(); break; + case 4: ws_emulate_special(); break; + case 5: ws_emulate_2xSaI(); break; + case 6: ws_emulate_Super2xSaI(); break; + case 7: ws_emulate_SuperEagle(); break; + } + } + ws_done(); + } + } + log_done(); + return(0); +} + diff --git a/oswan/resource.h b/oswan/resource.h new file mode 100644 index 0000000..05fe485 --- /dev/null +++ b/oswan/resource.h @@ -0,0 +1,50 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by gui.rc +// +#define IDD_DIALOG_MAIN 101 +#define IDB_BITMAP1 102 +#define IDB_BITMAP2 103 +#define IDC_BUTTON_LOAD 1000 +#define IDC_BUTTON_RESET 1001 +#define IDC_BUTTON_EXIT 1002 +#define IDC_RADIO1 1003 +#define IDC_RADIO_WINDOWED 1003 +#define IDC_RADIO2 1004 +#define IDC_RADIO_FULLSCREEN 1004 +#define IDC_BUTTON_LOADSTATE 1005 +#define IDC_BUTTON_SAVESTATE 1006 +#define IDC_RADIO3 1007 +#define IDC_BUTTON_CONTINUE 1007 +#define IDC_RADIO4 1008 +#define IDC_BUTTON_CONTROLS 1008 +#define IDC_RADIO5 1009 +#define IDC_RADIO_STANDARD_MODE 1009 +#define IDC_RADIO6 1010 +#define IDC_RADIO_DOUBLESIZE_MODE 1010 +#define IDC_RADIO7 1011 +#define IDC_RADIO_SCANLINES_MODE 1011 +#define IDC_RADIO8 1012 +#define IDC_RADIO_50PRCTSCANLINES_MODE 1012 +#define IDC_RADIO9 1013 +#define IDC_RADIO_SPECIAL_MODE 1013 +#define IDC_RADIO_SYSTEM_AUTODETECT 1014 +#define IDC_RADIO_SYSTEM_MONO 1015 +#define IDC_RADIO_SYSTEM_COLOR 1016 +#define IDC_RADIO_2XSAI 1017 +#define IDC_RADIO_SUPER2XSAI 1018 +#define IDC_COLOUR_DEFAULT 1019 +#define IDC_COLOUR_AMBER 1020 +#define IDC_COLOUR_GREEN 1021 +#define IDC_RADIO_SUPEREAGLE 1022 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 108 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1021 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/oswan/source/2xSaI.cpp b/oswan/source/2xSaI.cpp new file mode 100644 index 0000000..006b254 --- /dev/null +++ b/oswan/source/2xSaI.cpp @@ -0,0 +1,773 @@ +/* + * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. + * + * (c) Copyright 1996 - 2001 Gary Henderson (gary@daniver.demon.co.uk) and + * Jerremy Koot (jkoot@snes9x.com) + * + * Super FX C emulator code + * (c) Copyright 1997 - 1999 Ivar (Ivar@snes9x.com) and + * Gary Henderson. + * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_. + * + * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson. + * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_. + * C4 C code (c) Copyright 2001 Gary Henderson (gary@daniver.demon.co.uk). + * + * DOS port code contains the works of other authors. See headers in + * individual files. + * + * Snes9x homepage: www.snes9x.com + * + * Permission to use, copy, modify and distribute Snes9x in both binary and + * source form, for non-commercial purposes, is hereby granted without fee, + * providing that this license information and copyright notice appear with + * all copies and any derived work. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event shall the authors be held liable for any damages + * arising from the use of this software. + * + * Snes9x is freeware for PERSONAL USE only. Commercial users should + * seek permission of the copyright holders first. Commercial use includes + * charging money for Snes9x or software derived from Snes9x. + * + * The copyright holders request that bug fixes and improvements to the code + * should be forwarded to them so everyone can benefit from the modifications + * in future versions. + * + * Super NES and Super Nintendo Entertainment System are trademarks of + * Nintendo Co., Limited and its subsidiary companies. + */ +#include "types.h" +#include "2xSaI.h" + +static u32 colorMask = 0xF7DEF7DE; +static u32 lowPixelMask = 0x08210821; +static u32 qcolorMask = 0xE79CE79C; +static u32 qlowpixelMask = 0x18631863; +static u32 redblueMask = 0xF81F; +static u32 greenMask = 0x7E0; + +int Init_2xSaI(u32 BitFormat) +{ + if (BitFormat == 565) { + colorMask = 0xF7DEF7DE; + lowPixelMask = 0x08210821; + qcolorMask = 0xE79CE79C; + qlowpixelMask = 0x18631863; + redblueMask = 0xF81F; + greenMask = 0x7E0; + } else if (BitFormat == 555) { + colorMask = 0x7BDE7BDE; + lowPixelMask = 0x04210421; + qcolorMask = 0x739C739C; + qlowpixelMask = 0x0C630C63; + redblueMask = 0x7C1F; + greenMask = 0x3E0; + } else { + return 0; + } + + return 1; +} + +static inline int GetResult1 (u32 A, u32 B, u32 C, u32 D, + u32 /* E */) +{ + int x = 0; + int y = 0; + int r = 0; + + if (A == C) + x += 1; + else if (B == C) + y += 1; + if (A == D) + x += 1; + else if (B == D) + y += 1; + if (x <= 1) + r += 1; + if (y <= 1) + r -= 1; + return r; +} + +static inline int GetResult2 (u32 A, u32 B, u32 C, u32 D, + u32 /* E */) +{ + int x = 0; + int y = 0; + int r = 0; + + if (A == C) + x += 1; + else if (B == C) + y += 1; + if (A == D) + x += 1; + else if (B == D) + y += 1; + if (x <= 1) + r -= 1; + if (y <= 1) + r += 1; + return r; +} + +static inline int GetResult (u32 A, u32 B, u32 C, u32 D) +{ + int x = 0; + int y = 0; + int r = 0; + + if (A == C) + x += 1; + else if (B == C) + y += 1; + if (A == D) + x += 1; + else if (B == D) + y += 1; + if (x <= 1) + r += 1; + if (y <= 1) + r -= 1; + return r; +} + +static inline u32 INTERPOLATE (u32 A, u32 B) +{ + if (A != B) { + return (((A & colorMask) >> 1) + ((B & colorMask) >> 1) + + (A & B & lowPixelMask)); + } else + return A; +} + +static inline u32 Q_INTERPOLATE (u32 A, u32 B, u32 C, u32 D) +{ + register u32 x = ((A & qcolorMask) >> 2) + + ((B & qcolorMask) >> 2) + + ((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2); + register u32 y = (A & qlowpixelMask) + + (B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask); + + y = (y >> 2) & qlowpixelMask; + return x + y; +} + +#define BLUE_MASK565 0x001F001F +#define RED_MASK565 0xF800F800 +#define GREEN_MASK565 0x07E007E0 + +#define BLUE_MASK555 0x001F001F +#define RED_MASK555 0x7C007C00 +#define GREEN_MASK555 0x03E003E0 + +void Super2xSaI (u8 *srcPtr, u32 srcPitch, + u8 *deltaPtr, u8 *dstPtr, u32 dstPitch, + int width, int height) +{ + u16 *bP; + u8 *dP; + u32 inc_bP; + u32 Nextline = srcPitch >> 1; + + { + inc_bP = 1; + + for (; height; height--) { + bP = (u16 *) srcPtr; + dP = (u8 *) dstPtr; + + for (u32 finish = width; finish; finish -= inc_bP) { + u32 color4, color5, color6; + u32 color1, color2, color3; + u32 colorA0, colorA1, colorA2, colorA3, + colorB0, colorB1, colorB2, colorB3, colorS1, colorS2; + u32 product1a, product1b, product2a, product2b; + + //--------------------------------------- B1 B2 + // 4 5 6 S2 + // 1 2 3 S1 + // A1 A2 + + colorB0 = *(bP - Nextline - 1); + colorB1 = *(bP - Nextline); + colorB2 = *(bP - Nextline + 1); + colorB3 = *(bP - Nextline + 2); + + color4 = *(bP - 1); + color5 = *(bP); + color6 = *(bP + 1); + colorS2 = *(bP + 2); + + color1 = *(bP + Nextline - 1); + color2 = *(bP + Nextline); + color3 = *(bP + Nextline + 1); + colorS1 = *(bP + Nextline + 2); + + colorA0 = *(bP + Nextline + Nextline - 1); + colorA1 = *(bP + Nextline + Nextline); + colorA2 = *(bP + Nextline + Nextline + 1); + colorA3 = *(bP + Nextline + Nextline + 2); + + //-------------------------------------- + if (color2 == color6 && color5 != color3) { + product2b = product1b = color2; + } else if (color5 == color3 && color2 != color6) { + product2b = product1b = color5; + } else if (color5 == color3 && color2 == color6) { + register int r = 0; + + r += GetResult (color6, color5, color1, colorA1); + r += GetResult (color6, color5, color4, colorB1); + r += GetResult (color6, color5, colorA2, colorS1); + r += GetResult (color6, color5, colorB2, colorS2); + + if (r > 0) + product2b = product1b = color6; + else if (r < 0) + product2b = product1b = color5; + else { + product2b = product1b = INTERPOLATE (color5, color6); + } + } else { + if (color6 == color3 && color3 == colorA1 + && color2 != colorA2 && color3 != colorA0) + product2b = + Q_INTERPOLATE (color3, color3, color3, color2); + else if (color5 == color2 && color2 == colorA2 + && colorA1 != color3 && color2 != colorA3) + product2b = + Q_INTERPOLATE (color2, color2, color2, color3); + else + product2b = INTERPOLATE (color2, color3); + + if (color6 == color3 && color6 == colorB1 + && color5 != colorB2 && color6 != colorB0) + product1b = + Q_INTERPOLATE (color6, color6, color6, color5); + else if (color5 == color2 && color5 == colorB2 + && colorB1 != color6 && color5 != colorB3) + product1b = + Q_INTERPOLATE (color6, color5, color5, color5); + else + product1b = INTERPOLATE (color5, color6); + } + + if (color5 == color3 && color2 != color6 && color4 == color5 + && color5 != colorA2) + product2a = INTERPOLATE (color2, color5); + else + if (color5 == color1 && color6 == color5 + && color4 != color2 && color5 != colorA0) + product2a = INTERPOLATE (color2, color5); + else + product2a = color2; + + if (color2 == color6 && color5 != color3 && color1 == color2 + && color2 != colorB2) + product1a = INTERPOLATE (color2, color5); + else + if (color4 == color2 && color3 == color2 + && color1 != color5 && color2 != colorB0) + product1a = INTERPOLATE (color2, color5); + else + product1a = color5; + + product1a = product1a | (product1b << 16); + product2a = product2a | (product2b << 16); + + *((u32 *) dP) = product1a; + *((u32 *) (dP + dstPitch)) = product2a; + + bP += inc_bP; + dP += sizeof (u32); + } // end of for ( finish= width etc..) + + srcPtr += srcPitch; + dstPtr += dstPitch * 2; +// deltaPtr += srcPitch; + } // endof: for (; height; height--) + } +} + +void SuperEagle (u8 *srcPtr, u32 srcPitch, u8 *deltaPtr, + u8 *dstPtr, u32 dstPitch, int width, int height) +{ + u8 *dP; + u16 *bP; + u16 *xP; + u32 inc_bP; + + { + inc_bP = 1; + + u32 Nextline = srcPitch >> 1; + + for (; height; height--) { + bP = (u16 *) srcPtr; +// xP = (u16 *) deltaPtr; + dP = dstPtr; + for (u32 finish = width; finish; finish -= inc_bP) { + u32 color4, color5, color6; + u32 color1, color2, color3; + u32 colorA1, colorA2, colorB1, colorB2, colorS1, colorS2; + u32 product1a, product1b, product2a, product2b; + + colorB1 = *(bP - Nextline); + colorB2 = *(bP - Nextline + 1); + + color4 = *(bP - 1); + color5 = *(bP); + color6 = *(bP + 1); + colorS2 = *(bP + 2); + + color1 = *(bP + Nextline - 1); + color2 = *(bP + Nextline); + color3 = *(bP + Nextline + 1); + colorS1 = *(bP + Nextline + 2); + + colorA1 = *(bP + Nextline + Nextline); + colorA2 = *(bP + Nextline + Nextline + 1); + + // -------------------------------------- + if (color2 == color6 && color5 != color3) { + product1b = product2a = color2; + if ((color1 == color2) || (color6 == colorB2)) { + product1a = INTERPOLATE (color2, color5); + product1a = INTERPOLATE (color2, product1a); + // product1a = color2; + } else { + product1a = INTERPOLATE (color5, color6); + } + + if ((color6 == colorS2) || (color2 == colorA1)) { + product2b = INTERPOLATE (color2, color3); + product2b = INTERPOLATE (color2, product2b); + // product2b = color2; + } else { + product2b = INTERPOLATE (color2, color3); + } + } else if (color5 == color3 && color2 != color6) { + product2b = product1a = color5; + + if ((colorB1 == color5) || (color3 == colorS1)) { + product1b = INTERPOLATE (color5, color6); + product1b = INTERPOLATE (color5, product1b); + // product1b = color5; + } else { + product1b = INTERPOLATE (color5, color6); + } + + if ((color3 == colorA2) || (color4 == color5)) { + product2a = INTERPOLATE (color5, color2); + product2a = INTERPOLATE (color5, product2a); + // product2a = color5; + } else { + product2a = INTERPOLATE (color2, color3); + } + + } else if (color5 == color3 && color2 == color6) { + register int r = 0; + + r += GetResult (color6, color5, color1, colorA1); + r += GetResult (color6, color5, color4, colorB1); + r += GetResult (color6, color5, colorA2, colorS1); + r += GetResult (color6, color5, colorB2, colorS2); + + if (r > 0) { + product1b = product2a = color2; + product1a = product2b = INTERPOLATE (color5, color6); + } else if (r < 0) { + product2b = product1a = color5; + product1b = product2a = INTERPOLATE (color5, color6); + } else { + product2b = product1a = color5; + product1b = product2a = color2; + } + } else { + product2b = product1a = INTERPOLATE (color2, color6); + product2b = + Q_INTERPOLATE (color3, color3, color3, product2b); + product1a = + Q_INTERPOLATE (color5, color5, color5, product1a); + + product2a = product1b = INTERPOLATE (color5, color3); + product2a = + Q_INTERPOLATE (color2, color2, color2, product2a); + product1b = + Q_INTERPOLATE (color6, color6, color6, product1b); + + // product1a = color5; + // product1b = color6; + // product2a = color2; + // product2b = color3; + } + product1a = product1a | (product1b << 16); + product2a = product2a | (product2b << 16); + + *((u32 *) dP) = product1a; + *((u32 *) (dP + dstPitch)) = product2a; +// *xP = color5; + + bP += inc_bP; +// xP += inc_bP; + dP += sizeof (u32); + } // end of for ( finish= width etc..) + + srcPtr += srcPitch; + dstPtr += dstPitch * 2; +// deltaPtr += srcPitch; + } // endof: for (height; height; height--) + } +} + +void _2xSaI (u8 *srcPtr, u32 srcPitch, u8 *deltaPtr, + u8 *dstPtr, u32 dstPitch, int width, int height) +{ + u8 *dP; + u16 *bP; + u32 inc_bP; + + { + inc_bP = 1; + + u32 Nextline = srcPitch >> 1; + + for (; height; height--) { + bP = (u16 *) srcPtr; + dP = dstPtr; + + for (u32 finish = width; finish; finish -= inc_bP) { + + register u32 colorA, colorB; + u32 colorC, colorD, + colorE, colorF, colorG, colorH, + colorI, colorJ, colorK, colorL, + + colorM, colorN, colorO, colorP; + u32 product, product1, product2; + + //--------------------------------------- + // Map of the pixels: I|E F|J + // G|A B|K + // H|C D|L + // M|N O|P + colorI = *(bP - Nextline - 1); + colorE = *(bP - Nextline); + colorF = *(bP - Nextline + 1); + colorJ = *(bP - Nextline + 2); + + colorG = *(bP - 1); + colorA = *(bP); + colorB = *(bP + 1); + colorK = *(bP + 2); + + colorH = *(bP + Nextline - 1); + colorC = *(bP + Nextline); + colorD = *(bP + Nextline + 1); + colorL = *(bP + Nextline + 2); + + colorM = *(bP + Nextline + Nextline - 1); + colorN = *(bP + Nextline + Nextline); + colorO = *(bP + Nextline + Nextline + 1); + colorP = *(bP + Nextline + Nextline + 2); + + if ((colorA == colorD) && (colorB != colorC)) { + if (((colorA == colorE) && (colorB == colorL)) || + ((colorA == colorC) && (colorA == colorF) + && (colorB != colorE) && (colorB == colorJ))) { + product = colorA; + } else { + product = INTERPOLATE (colorA, colorB); + } + + if (((colorA == colorG) && (colorC == colorO)) || + ((colorA == colorB) && (colorA == colorH) + && (colorG != colorC) && (colorC == colorM))) { + product1 = colorA; + } else { + product1 = INTERPOLATE (colorA, colorC); + } + product2 = colorA; + } else if ((colorB == colorC) && (colorA != colorD)) { + if (((colorB == colorF) && (colorA == colorH)) || + ((colorB == colorE) && (colorB == colorD) + && (colorA != colorF) && (colorA == colorI))) { + product = colorB; + } else { + product = INTERPOLATE (colorA, colorB); + } + + if (((colorC == colorH) && (colorA == colorF)) || + ((colorC == colorG) && (colorC == colorD) + && (colorA != colorH) && (colorA == colorI))) { + product1 = colorC; + } else { + product1 = INTERPOLATE (colorA, colorC); + } + product2 = colorB; + } else if ((colorA == colorD) && (colorB == colorC)) { + if (colorA == colorB) { + product = colorA; + product1 = colorA; + product2 = colorA; + } else { + register int r = 0; + + product1 = INTERPOLATE (colorA, colorC); + product = INTERPOLATE (colorA, colorB); + + r += + GetResult1 (colorA, colorB, colorG, colorE, + colorI); + r += + GetResult2 (colorB, colorA, colorK, colorF, + colorJ); + r += + GetResult2 (colorB, colorA, colorH, colorN, + colorM); + r += + GetResult1 (colorA, colorB, colorL, colorO, + colorP); + + if (r > 0) + product2 = colorA; + else if (r < 0) + product2 = colorB; + else { + product2 = + Q_INTERPOLATE (colorA, colorB, colorC, + colorD); + } + } + } else { + product2 = Q_INTERPOLATE (colorA, colorB, colorC, colorD); + + if ((colorA == colorC) && (colorA == colorF) + && (colorB != colorE) && (colorB == colorJ)) { + product = colorA; + } else if ((colorB == colorE) && (colorB == colorD) + && (colorA != colorF) && (colorA == colorI)) { + product = colorB; + } else { + product = INTERPOLATE (colorA, colorB); + } + + if ((colorA == colorB) && (colorA == colorH) + && (colorG != colorC) && (colorC == colorM)) { + product1 = colorA; + } else if ((colorC == colorG) && (colorC == colorD) + && (colorA != colorH) && (colorA == colorI)) { + product1 = colorC; + } else { + product1 = INTERPOLATE (colorA, colorC); + } + } + + product = colorA | (product << 16); + product1 = product1 | (product2 << 16); + *((s32 *) dP) = product; + *((u32 *) (dP + dstPitch)) = product1; + + bP += inc_bP; + dP += sizeof (u32); + } // end of for ( finish= width etc..) + + srcPtr += srcPitch; + dstPtr += dstPitch * 2; +// deltaPtr += srcPitch; + } // endof: for (height; height; height--) + } +} + +static u32 Bilinear (u32 A, u32 B, u32 x) +{ + unsigned long areaA, areaB; + unsigned long result; + + if (A == B) + return A; + + areaB = (x >> 11) & 0x1f; // reduce 16 bit fraction to 5 bits + areaA = 0x20 - areaB; + + A = (A & redblueMask) | ((A & greenMask) << 16); + B = (B & redblueMask) | ((B & greenMask) << 16); + + result = ((areaA * A) + (areaB * B)) >> 5; + + return (result & redblueMask) | ((result >> 16) & greenMask); +} + +static u32 Bilinear4 (u32 A, u32 B, u32 C, u32 D, u32 x, + u32 y) +{ + unsigned long areaA, areaB, areaC, areaD; + unsigned long result, xy; + + x = (x >> 11) & 0x1f; + y = (y >> 11) & 0x1f; + xy = (x * y) >> 5; + + A = (A & redblueMask) | ((A & greenMask) << 16); + B = (B & redblueMask) | ((B & greenMask) << 16); + C = (C & redblueMask) | ((C & greenMask) << 16); + D = (D & redblueMask) | ((D & greenMask) << 16); + + areaA = 0x20 + xy - x - y; + areaB = x - xy; + areaC = y - xy; + areaD = xy; + + result = ((areaA * A) + (areaB * B) + (areaC * C) + (areaD * D)) >> 5; + + return (result & redblueMask) | ((result >> 16) & greenMask); +} + +void Scale_2xSaI (u8 *srcPtr, u32 srcPitch, u8 * /* deltaPtr */, + u8 *dstPtr, u32 dstPitch, + u32 dstWidth, u32 dstHeight, int width, int height) +{ + u8 *dP; + u16 *bP; + + u32 w; + u32 h; + u32 dw; + u32 dh; + u32 hfinish; + u32 wfinish; + + u32 Nextline = srcPitch >> 1; + + wfinish = (width - 1) << 16; // convert to fixed point + dw = wfinish / (dstWidth - 1); + hfinish = (height - 1) << 16; // convert to fixed point + dh = hfinish / (dstHeight - 1); + + for (h = 0; h < hfinish; h += dh) { + u32 y1, y2; + + y1 = h & 0xffff; // fraction part of fixed point + bP = (u16 *) (srcPtr + ((h >> 16) * srcPitch)); + dP = dstPtr; + y2 = 0x10000 - y1; + + w = 0; + + for (; w < wfinish;) { + u32 A, B, C, D; + u32 E, F, G, H; + u32 I, J, K, L; + u32 x1, x2, a1, f1, f2; + u32 position, product1; + + position = w >> 16; + A = bP[position]; // current pixel + B = bP[position + 1]; // next pixel + C = bP[position + Nextline]; + D = bP[position + Nextline + 1]; + E = bP[position - Nextline]; + F = bP[position - Nextline + 1]; + G = bP[position - 1]; + H = bP[position + Nextline - 1]; + I = bP[position + 2]; + J = bP[position + Nextline + 2]; + K = bP[position + Nextline + Nextline]; + L = bP[position + Nextline + Nextline + 1]; + + x1 = w & 0xffff; // fraction part of fixed point + x2 = 0x10000 - x1; + + /*0*/ + if (A == B && C == D && A == C) + product1 = A; + else /*1*/ if (A == D && B != C) { + f1 = (x1 >> 1) + (0x10000 >> 2); + f2 = (y1 >> 1) + (0x10000 >> 2); + if (y1 <= f1 && A == J && A != E) // close to B + { + a1 = f1 - y1; + product1 = Bilinear (A, B, a1); + } else if (y1 >= f1 && A == G && A != L) // close to C + { + a1 = y1 - f1; + product1 = Bilinear (A, C, a1); + } + else if (x1 >= f2 && A == E && A != J) // close to B + { + a1 = x1 - f2; + product1 = Bilinear (A, B, a1); + } + else if (x1 <= f2 && A == L && A != G) // close to C + { + a1 = f2 - x1; + product1 = Bilinear (A, C, a1); + } + else if (y1 >= x1) // close to C + { + a1 = y1 - x1; + product1 = Bilinear (A, C, a1); + } + else if (y1 <= x1) // close to B + { + a1 = x1 - y1; + product1 = Bilinear (A, B, a1); + } + } + else + /*2*/ + if (B == C && A != D) + { + f1 = (x1 >> 1) + (0x10000 >> 2); + f2 = (y1 >> 1) + (0x10000 >> 2); + if (y2 >= f1 && B == H && B != F) // close to A + { + a1 = y2 - f1; + product1 = Bilinear (B, A, a1); + } + else if (y2 <= f1 && B == I && B != K) // close to D + { + a1 = f1 - y2; + product1 = Bilinear (B, D, a1); + } + else if (x2 >= f2 && B == F && B != H) // close to A + { + a1 = x2 - f2; + product1 = Bilinear (B, A, a1); + } + else if (x2 <= f2 && B == K && B != I) // close to D + { + a1 = f2 - x2; + product1 = Bilinear (B, D, a1); + } + else if (y2 >= x1) // close to A + { + a1 = y2 - x1; + product1 = Bilinear (B, A, a1); + } + else if (y2 <= x1) // close to D + { + a1 = x1 - y2; + product1 = Bilinear (B, D, a1); + } + } + /*3*/ + else + { + product1 = Bilinear4 (A, B, C, D, x1, y1); + } + + //end First Pixel + *(u32 *) dP = product1; + dP += 2; + w += dw; + } + dstPtr += dstPitch; + } +} + diff --git a/oswan/source/2xSaI.h b/oswan/source/2xSaI.h new file mode 100644 index 0000000..9243f5a --- /dev/null +++ b/oswan/source/2xSaI.h @@ -0,0 +1,22 @@ +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef __2XSAI_H__ +#define __2XSAI_H__ + +int Init_2xSaI(u32 BitFormat); +void Super2xSaI (u8 *srcPtr, u32 srcPitch, u8 *deltaPtr, u8 *dstPtr, u32 dstPitch, int width, int height); +void SuperEagle (u8 *srcPtr, u32 srcPitch, u8 *deltaPtr, u8 *dstPtr, u32 dstPitch, int width, int height); +void _2xSaI (u8 *srcPtr, u32 srcPitch, u8 *deltaPtr, u8 *dstPtr, u32 dstPitch, int width, int height); +void Scale_2xSaI (u8 *srcPtr, u32 srcPitch, u8 * /*deltaPtr */, u8 *dstPtr, u32 dstPitch, u32 dstWidth, u32 dstHeight, int width, int height); + +#endif + diff --git a/oswan/source/SDLptc.h b/oswan/source/SDLptc.h new file mode 100644 index 0000000..d432a84 --- /dev/null +++ b/oswan/source/SDLptc.h @@ -0,0 +1,246 @@ + +/* Some simple emulation classes to get PTC code running on SDL */ + +#include +#include + +#include "SDL.h" + +typedef Uint8 char8; +typedef Sint32 int32; + +#define randomize() srand(time(NULL)) +#define random(max) (rand()%(max)) + +#ifndef stricmp +#define stricmp strcasecmp +#endif + +class Error { + +public: + Error(const char *message) { + strcpy(_message, message); + } + + void report(void) { + printf("Error: %s\n", _message); + } + +private: + + char _message[1024]; +}; + +class Area { + +public: + Area(int left, int top, int right, int bottom) { + _left = left; + _top = top; + _right = right; + _bottom = bottom; + } + + int left(void) const { + return(_left); + } + int right(void) const { + return(_right); + } + int top(void) const { + return(_top); + } + int bottom(void) const { + return(_bottom); + } + int width(void) const { + return(_right-_left); + } + int height(void) const { + return(_bottom-_top); + } + +private: + int _left, _top, _right, _bottom; +}; + + +class Format { + +public: + Format(int bpp, int maskR = 0, int maskG = 0, int maskB = 0) { + _bpp = bpp; + _maskR = maskR; + _maskG = maskG; + _maskB = maskB; + } + + Uint8 BPP(void) const { return(_bpp); } + Uint32 MaskR(void) const { return(_maskR); } + Uint32 MaskG(void) const { return(_maskG); } + Uint32 MaskB(void) const { return(_maskB); } + +private: + Uint8 _bpp; + Uint32 _maskR, _maskG, _maskB; +}; + +class Surface { + +public: + Surface(int w, int h, const Format &format) { + surface = SDL_AllocSurface(SDL_SWSURFACE, w, h, format.BPP(), + format.MaskR(),format.MaskG(),format.MaskB(),0); + if ( surface == NULL ) { + throw Error(SDL_GetError()); + } + nupdates = 0; + is_console = 0; + } + Surface(void) { + nupdates = 0; + is_console = 1; + } + ~Surface() { + if ( ! is_console ) { + SDL_FreeSurface(surface); + } + } + + virtual int width(void) { + return surface->w; + } + virtual int height(void) { + return surface->h; + } + virtual int pitch(void) { + return surface->pitch; + } + + virtual void palette(int32 *pcolors) { + SDL_Color colors[256]; + + for ( int i=0; i<256; ++i ) { + colors[i].r = (pcolors[i]>>16)&0xFF; + colors[i].g = (pcolors[i]>>8)&0xFF; + colors[i].b = (pcolors[i]>>0)&0xFF; + } + SDL_SetColors(surface, colors, 0, 256); + } + + virtual void *lock(void) { + if ( SDL_MUSTLOCK(surface) ) { + while ( SDL_LockSurface(surface) < 0 ) { + SDL_Delay(10); + } + } + return (Uint8 *)surface->pixels; + } + + virtual void unlock(void) { + if ( SDL_MUSTLOCK(surface) ) { + SDL_UnlockSurface(surface); + } + } + + virtual void copy(Surface &dst, + const Area &srcarea, const Area &dstarea) { + SDL_Rect srcrect, dstrect; + srcrect.x = srcarea.left(); + srcrect.y = srcarea.top(); + srcrect.w = srcarea.width(); + srcrect.h = srcarea.height(); + dstrect.x = dstarea.left(); + dstrect.y = dstarea.top(); + dstrect.w = dstarea.width(); + dstrect.h = dstarea.height(); + SDL_BlitSurface(surface, &srcrect, dst.surface, &dstrect); + dst.updates[dst.nupdates++] = dstrect; + } + virtual void copy(Surface &dst) { + SDL_Rect srcrect, dstrect; + srcrect.x = 0; + srcrect.y = 0; + srcrect.w = surface->w; + srcrect.h = surface->h; + dstrect.x = 0; + dstrect.y = 0; + dstrect.w = surface->w; + dstrect.h = surface->h; + SDL_LowerBlit(surface, &srcrect, dst.surface, &dstrect); + dst.updates[dst.nupdates++] = dstrect; + } + + virtual void update(void) { + SDL_UpdateRects(surface, nupdates, updates); + nupdates = 0; + } + +protected: + SDL_Surface *surface; + int nupdates; + SDL_Rect updates[1]; /* Definitely increase this.. */ + int is_console; +}; + +class Console : public Surface { + int fullscreen; +public: + Console() : Surface() { + fullscreen=0; + } + ~Console() { + + SDL_Quit(); + } + void close(void) + { + SDL_Quit(); + } + void option(char *option) + { + if (!stricmp(option,"fullscreen output")) + fullscreen=1; + else + if (!stricmp(option,"windowed output")) + fullscreen=0; + } + void open(const char *title, int width, int height, const Format &format) { + Uint32 flags; + + if ( SDL_InitSubSystem(SDL_INIT_VIDEO|SDL_INIT_JOYSTICK) < 0 ) { + throw Error(SDL_GetError()); + } + //flags = (SDL_HWSURFACE|SDL_HWPALETTE|SDL_FULLSCREEN); + flags = (SDL_HWSURFACE|SDL_HWPALETTE); + if (fullscreen) + flags|=SDL_FULLSCREEN; + surface = SDL_SetVideoMode(width, height, 0, flags); + if ( surface == NULL ) { + throw Error(SDL_GetError()); + } + SDL_WM_SetCaption(title, title); + } + + int key(void) { + SDL_Event event; + int keyevent; + + keyevent = 0; + while ( SDL_PollEvent(&event) ) { + /* Real key events trigger this function */ + if ( event.type == SDL_KEYDOWN ) { + keyevent = 1; + } + /* So do quit events -- let the app know about it */ + if ( event.type == SDL_QUIT ) { + keyevent = 1; + } + } + return(keyevent); + } + +private: + +}; diff --git a/oswan/source/audio.cpp b/oswan/source/audio.cpp new file mode 100644 index 0000000..a55af2c --- /dev/null +++ b/oswan/source/audio.cpp @@ -0,0 +1,1382 @@ +//////////////////////////////////////////////////////////////////////////////// +// Audio +//////////////////////////////////////////////////////////////////////////////// +// +// Sound information thanks to toshi (wscamp wonderswan emulator) +// Note that sound is far from perfect for now. +// +// fixes by zalas 2002-08-21 +// +// +// +//////////////////////////////////////////////////////////////////////////////// + +// alternate the commenting of the following defines to get audio port tracing +#define dbgprintf // +//#define dbgprintf printf + +#include +#include +#include +#include +#include +#include +#include "log.h" +#include "rom.h" +#include "./nec/nec.h" +#include "memory.h" +#include "io.h" +#include "audio.h" + +// seal's retarded definitions conflict with types.h +#undef DWORD + +#include + +#define SNDP ws_ioRam[0x80] +#define SNDV ws_ioRam[0x88] +#define SNDSWP ws_ioRam[0x8C] +#define SWPSTP ws_ioRam[0x8D] +#define NSCTL ws_ioRam[0x8E] +#define WAVDTP ws_ioRam[0x8F] +#define SNDMOD ws_ioRam[0x90] +#define SNDOUT ws_ioRam[0x91] +#define PCSRL ws_ioRam[0x92] +#define PCSRH ws_ioRam[0x93] +#define DMASL ws_ioRam[0x40] +#define DMASH ws_ioRam[0x41] +#define DMASB ws_ioRam[0x42] +#define DMADB ws_ioRam[0x43] +#define DMADL ws_ioRam[0x44] +#define DMADH ws_ioRam[0x45] +#define DMACL ws_ioRam[0x46] +#define DMACH ws_ioRam[0x47] +#define DMACTL ws_ioRam[0x48] +#define SDMASL ws_ioRam[0x4A] +#define SDMASH ws_ioRam[0x4B] +#define SDMASB ws_ioRam[0x4C] +#define SDMACL ws_ioRam[0x4E] +#define SDMACH ws_ioRam[0x4F] +#define SDMACTL ws_ioRam[0x52] + +#define BPS 44100 +#define BPSMAX AUDIO_MAX_FREQUENCY +#define BPSMIN AUDIO_MIN_FREQUENCY +#define BUFSIZE 1024 +#define BUFSIZEN 0x10000 +#define BUFSIZEP 159 +#define PCMNUM 100 +#define POFF 128 +#define PDIV 3 +#define PH POFF+PDIV*8 +#define PL POFF-PDIV*7 + +int WaveMap; +int ChPerInit; +int SwpTime; +int SwpStep; +unsigned int SwpCurPeriod; + +int MainVol=15; +int HardVol=3; + +int ChCurVol[6]={-1,-1,-1,-1,-1,-1}; +int ChCurPer[6]={-1,-1,-1,-1,-1,-1}; +long ChCurPan[6]={-1,-1,-1,-1,-1,-1}; + +unsigned char PData[4][BUFSIZE]; +unsigned char PDataP[BUFSIZEP<<4]; +unsigned char PDataN[8][BUFSIZEN]; + +int RandData[BUFSIZEN]; + +int CntSwp=0; +int PcmWrPos=0; + +const long TblChVol[16]={ // n/15 n=0~15 + -10000,-2352,-1750,-1398,-1148,-954,-796,-662, + -546,-444,-352,-269,-194,-124,-60,0 +}; + +const long TblMainVol[4]={ // 1,1/2,1/4,1/8 + 0,-602,-1204,-1806 +}; + +//////////////////////////////////////////////////////////////////////////////// +// seal audio specific +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +HAC ws_audio_pcm_voice[4]; +HAC ws_audio_noise_voice; +HAC ws_audio_sweep_voice; + +AUDIOWAVE ws_audio_pcm_wave[4]; +AUDIOWAVE ws_audio_noise_wave; +AUDIOWAVE ws_audio_sweep_wave; + +UINT32 ws_audio_channel_isPlaying[6]; + +static unsigned int ws_audio_log; +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_audio_init(void) +{ + fprintf(log_get(), "audio init\n"); + fflush(log_get()); + ws_audio_log=0; + ws_audio_seal_init(); + ws_audio_reset(); + SDL_PauseAudio(0); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_audio_reset(void) +{ + WaveMap=-1; + for (int i=0;i<6;i++) + { + ws_audio_stop_channel(i); + ws_audio_play_channel(i); + ws_audio_set_channel_frequency(i,0); + if (i!=4) + ws_audio_set_channel_pan(i,0,0); + ws_audio_clear_channel(i); + } + ws_audio_set_channel_frequency(4,0); + ws_audio_set_channel_frequency(4,1792); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_audio_port_write(Uint32 port, Uint8 value) +{ + Uint32 n,i,j,k,b; + + //printf("0x%2x <- 0x%2x\n", port, (Uint32)value); + + ws_ioRam[port]=value; + + switch (port) + { + case 0x48: if (value&0x80) + { + n=(DMACH<<8)|DMACL; + i=(DMASB<<16)|(DMASH<<8)|DMASL; + j=(DMADH<<8)|DMADL; + for(k=0;k>16)&0xFF); + DMASH=(Uint8)((i>>8)&0xFF); + DMASL=(Uint8)(i&0xFF); + DMADB=(Uint8)((j>>16)&0xFF); + DMADH=(Uint8)((j>>8)&0xFF); + DMADL=(Uint8)(j&0xFF); + DMACH=(Uint8)((n>>8)&0xFF); + DMACL=(Uint8)(n&0xFF); + value&=0x7F; + } + break; + case 0x80: + case 0x81: i=(((unsigned int)ws_ioRam[0x81])<<8)+((unsigned int)ws_ioRam[0x80]); + ws_audio_set_channel_frequency(0,i); + dbgprintf("0x%2x ... freq = 0x%x\n", port, i); + break; + case 0x82: + case 0x83: i=(((unsigned int)ws_ioRam[0x83])<<8)+((unsigned int)ws_ioRam[0x82]); + ws_audio_set_channel_frequency(1,i); + break; + case 0x84: + case 0x85: i=(((unsigned int)ws_ioRam[0x85])<<8)+((unsigned int)ws_ioRam[0x84]); + ws_audio_set_channel_frequency(2,i); + break; + case 0x86: + case 0x87: i=(((unsigned int)(ws_ioRam[0x87]&0x07))<<8)+((unsigned int)ws_ioRam[0x86]); + ws_audio_set_channel_frequency(5,i); + ws_audio_set_channel_frequency(3,i); + break; + case 0x88: + dbgprintf("0x88 <- 0x%2x\n", value); fflush(stdout); + ws_audio_set_channel_pan(0,(value&0xF0)>>4,value&0x0F); + break; + case 0x89: + dbgprintf("0x89 <- 0x%2x\n", value); fflush(stdout); + ws_audio_set_channel_pan(1,(value&0xF0)>>4,value&0x0F); + break; + case 0x8A: + ws_audio_set_channel_pan(2,(value&0xF0)>>4,value&0x0F); + break; + case 0x8B: + ws_audio_set_channel_pan(5,(value&0xF0)>>4,value&0x0F); + ws_audio_set_channel_pan(3,(value&0xF0)>>4,value&0x0F); + break; + case 0x8C: + SwpStep=(signed char)value; + break; + case 0x8D: + //SwpTime=(((unsigned int)value)+1)<<5; + SwpTime=(((unsigned int)value)+1)<<5; + break; + case 0x8E: + dbgprintf("0x8E <- 0x%2x = %d %d %d %d %d %d %d %d \n", value, value & 0x80 ? 1 : 0, value & 0x40 ? 1 : 0, value & 0x20 ? 1 : 0, value & 0x10 ? 1 : 0, value & 8 ? 1 : 0, value & 4 ? 1 : 0, value & 2 ? 1 : 0, value & 1), fflush(stdout); /* ctl */ + if (value & 0x10) + { + ws_audio_set_channel_pdata(5,value&0x07); + } else + { + // hmmm.. shut up! + } + break; + case 0x8F: + WaveMap=((unsigned int)value)<<6; + break; + case 0x90: + dbgprintf("0x90 <- 0x%2x = %d %d %d %d %d %d %d %d \n", value, value & 0x80 ? 1 : 0, value & 0x40 ? 1 : 0, value & 0x20 ? 1 : 0, value & 0x10 ? 1 : 0, value & 8 ? 1 : 0, value & 4 ? 1 : 0, value & 2 ? 1 : 0, value & 1), fflush(stdout); /* ctl */ + + if (value&0x01) + { + ws_audio_play_channel(0); +// for(int ii=0;ii<32;ii++) +// fprintf(log_get(),"%02X ",PData[0][ii]); +// fprintf(log_get(),"\n"); + } + else + ws_audio_stop_channel(0); + + if ((value&0x22)==0x02) + ws_audio_play_channel(1); + else + ws_audio_stop_channel(1); + + if (value&0x04) + ws_audio_play_channel(2); + else + ws_audio_stop_channel(2); + + if ((value&0x88)==0x08) + ws_audio_play_channel(3); + else + ws_audio_stop_channel(3); + + if ((value&0x88)==0x88) + ws_audio_play_channel(5); + else + ws_audio_stop_channel(5); + break; + case 0x91: +/* printf("Channels [ %c %c %c %c %c %c %c %c ]\n", + (value>>0)&1?'S':'M', + (value>>1)&1?'H':'l', + (value>>2)&1?'H':'l', + (value>>3)&1?'E':' ', + (value>>4)&1?'4':' ', + (value>>5)&1?'5':' ', + (value>>6)&1?'6':' ', + (value>>7)&1?'E':' '); + //0x91 <- %x\n", value); + fflush(stdout);*/ + //MainVol=0; + value|=0x80; + HardVol = (value>>1)&0x3; + + ws_ioRam[port]=value; // Always have external speaker + + value=ws_ioRam[0x88]; + + ws_audio_set_channel_pan(0,(value&0xF0)>>4,value&0x0F); + + value=ws_ioRam[0x89]; + + ws_audio_set_channel_pan(1,(value&0xF0)>>4,value&0x0F); + + value=ws_ioRam[0x8A]; + + ws_audio_set_channel_pan(2,(value&0xF0)>>4,value&0x0F); + + value=ws_ioRam[0x8B]; + + ws_audio_set_channel_pan(3,(value&0xF0)>>4,value&0x0F); + + ws_audio_set_channel_pan(5,(value&0xF0)>>4,value&0x0F); + + break; + case 0x92: + dbgprintf("0x92 <- 0x%2x\n", value); fflush(stdout); + break; + case 0x93: + dbgprintf("0x93 <- 0x%2x\n", value); fflush(stdout); + break; + case 0x94: + dbgprintf("0x94 <- 0x%2x\n", value); fflush(stdout); + MainVol=(value&0x0f)>>2; + value=ws_ioRam[0x88]; + + ws_audio_set_channel_pan(0,(value&0xF0)>>4,value&0x0F); + + value=ws_ioRam[0x89]; + + ws_audio_set_channel_pan(1,(value&0xF0)>>4,value&0x0F); + + value=ws_ioRam[0x8A]; + + ws_audio_set_channel_pan(2,(value&0xF0)>>4,value&0x0F); + + value=ws_ioRam[0x8B]; + + ws_audio_set_channel_pan(3,(value&0xF0)>>4,value&0x0F); + + ws_audio_set_channel_pan(5,(value&0xF0)>>4,value&0x0F); + + break; + } +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +BYTE ws_audio_port_read(BYTE port) +{ + return(ws_ioRam[port]); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_audio_done(void) +{ + ws_audio_seal_done(); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +unsigned int ws_audio_mrand(unsigned int Degree) +{ +#define BIT(n) (1<InputBit-1; + int XorReg=0; + int Masked; + + if(pTbl->N!=Degree) + { + pTbl=TblMask; + while(pTbl->N) + { + if(pTbl->N==Degree) + { + break; + } + pTbl++; + } + if(!pTbl->N) + { + pTbl--; + } + + ShiftReg&=pTbl->InputBit-1; + if(!ShiftReg) + { + ShiftReg=pTbl->InputBit-1; + } + } + + Masked=ShiftReg&pTbl->Mask; + while(Masked) + { + XorReg^=Masked&0x01; + Masked>>=1; + } + + if(XorReg) + { + ShiftReg|=pTbl->InputBit; + } + else + { + ShiftReg&=~pTbl->InputBit; + } + ShiftReg>>=1; + + return ShiftReg; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +int ws_audio_seal_init(void) +{ + int i, j; + AUDIOINFO info; + AUDIOCAPS caps; + UINT rc; + UINT nDevId; + + fprintf(log_get(),"audio: using seal audio library\n"); + /* initialize audio library */ + AInitialize(); + + /* show registered device drivers */ + fprintf(log_get(),"audio: registered sound devices:\n"); + for (nDevId = 0; nDevId < AGetAudioNumDevs(); nDevId++) { + AGetAudioDevCaps(nDevId, &caps); + fprintf(log_get(),"audio: %2d. %s\n", nDevId, caps.szProductName); + } + /* open audio device */ + //info.nDeviceId = AUDIO_DEVICE_MAPPER; + info.nDeviceId = 1; + info.wFormat = AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO; // | AUDIO_MIXER_BASS; + info.nSampleRate = 44100; + if ((rc = AOpenAudio(&info)) != AUDIO_ERROR_NONE) + { + CHAR szText[80]; + AGetErrorText(rc, szText, sizeof(szText) - 1); + fprintf(log_get(),"audio: error: %s\n", szText); fflush(log_get()); + return(0); + } + + // open 6 voices ( 4 pcm, one noise, and one sweep) + AOpenVoices(6); + + // create the 4 pcm channels + for (i=0;i<4;i++) + { + // create the channel + ACreateAudioVoice(&ws_audio_pcm_voice[i]); + ASetVoiceVolume ( ws_audio_pcm_voice[i], AUDIO_MAX_VOLUME); + ASetVoicePanning ( ws_audio_pcm_voice[i], AUDIO_MIN_PANNING); + + + // create a looped sound buffer + ws_audio_pcm_wave[i].nSampleRate = info.nSampleRate; + ws_audio_pcm_wave[i].dwLength = BUFSIZE; + ws_audio_pcm_wave[i].dwLoopStart = 0; + ws_audio_pcm_wave[i].dwLoopEnd = ws_audio_pcm_wave[i].dwLength; + ws_audio_pcm_wave[i].wFormat = AUDIO_FORMAT_8BITS | AUDIO_FORMAT_MONO | AUDIO_FORMAT_LOOP; + + ACreateAudioData(&ws_audio_pcm_wave[i]); + + // channel is not playing yet + ws_audio_channel_isPlaying[i]=0; + + // clear the channel + ws_audio_clear_channel(i); + } + + // create the noise channel + { + // create the channel + ACreateAudioVoice(&ws_audio_noise_voice); + ASetVoiceVolume ( ws_audio_noise_voice, AUDIO_MAX_VOLUME); + ASetVoicePanning ( ws_audio_noise_voice, AUDIO_MAX_PANNING>>1); + + + // create a looped sound buffer + ws_audio_noise_wave.nSampleRate = info.nSampleRate; + ws_audio_noise_wave.dwLength = (BUFSIZEP<<4); + ws_audio_noise_wave.dwLoopStart = 0; + ws_audio_noise_wave.dwLoopEnd = ws_audio_noise_wave.dwLength; + ws_audio_noise_wave.wFormat = AUDIO_FORMAT_8BITS | AUDIO_FORMAT_MONO | AUDIO_FORMAT_LOOP; + + ACreateAudioData(&ws_audio_noise_wave); + + // channel is not playing yet + ws_audio_channel_isPlaying[4]=0; + + // clear the channel + ws_audio_clear_channel(4); + } + + // create the sweep channel + { + // create the channel + ACreateAudioVoice(&ws_audio_sweep_voice); + ASetVoiceVolume ( ws_audio_sweep_voice, AUDIO_MAX_VOLUME); + ASetVoicePanning ( ws_audio_sweep_voice, AUDIO_MAX_PANNING); + + + // create a looped sound buffer + ws_audio_sweep_wave.nSampleRate = info.nSampleRate; + ws_audio_sweep_wave.dwLength = BUFSIZEN; + ws_audio_sweep_wave.dwLoopStart = 0; + ws_audio_sweep_wave.dwLoopEnd = ws_audio_sweep_wave.dwLength; + ws_audio_sweep_wave.wFormat = AUDIO_FORMAT_8BITS | AUDIO_FORMAT_MONO | AUDIO_FORMAT_LOOP; + + ACreateAudioData(&ws_audio_sweep_wave); + + // channel is not playing yet + ws_audio_channel_isPlaying[5]=0; + + // clear the channel + ws_audio_clear_channel(5); + } + + // initialize the noise channel data + int rand; + for(i=0;i<8;i++) + { + for(j=0;jBPSMAX) + Freq=BPSMAX; + + else + if(Freq10000) volume=10000; + volume=((volume+10000)*0x3f)/20000; + if(volume<-10000) + volume=-10000;*/ + volume=(Vol+1)*(MainVol+1)*(HardVol+1)/16-1; + if (Channel==5) + ASetVoiceVolume(ws_audio_sweep_voice,volume); + else + if (Channel==4) + { + ASetVoiceVolume(ws_audio_noise_voice,volume); + } + else + { + ASetVoiceVolume(ws_audio_pcm_voice[Channel],volume); +// fprintf(log_get(),"set Channel[%d] volume to %02X (%02X*%02X)\n",Channel,volume,Vol,MainVol); + } +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_audio_set_channel_pan(int Channel,int Left,int Right) +{ + long pan; + + const long TblPan[16][16]= + { + { 0, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000}, + {-10000, 0, 602, 954, 1204, 1398, 1556, 1690, 1806, 1908, 2000, 2082, 2158, 2228, 2292, 2352}, + {-10000, -602, 0, 352, 602, 796, 954, 1088, 1204, 1306, 1398, 1481, 1556, 1626, 1690, 1750}, + {-10000, -954, -352, 0, 250, 444, 602, 736, 852, 954, 1046, 1129, 1204, 1274, 1338, 1398}, + {-10000, -1204, -602, -250, 0, 194, 352, 486, 602, 704, 796, 879, 954, 1024, 1088, 1148}, + {-10000, -1398, -796, -444, -194, 0, 158, 292, 408, 511, 602, 685, 760, 830, 894, 954}, + {-10000, -1556, -954, -602, -352, -158, 0, 134, 250, 352, 444, 526, 602, 672, 736, 796}, + {-10000, -1690, -1088, -736, -486, -292, -134, 0, 116, 218, 310, 393, 468, 538, 602, 662}, + {-10000, -1806, -1204, -852, -602, -408, -250, -116, 0, 102, 194, 277, 352, 422, 486, 546}, + {-10000, -1908, -1306, -954, -704, -511, -352, -218, -102, 0, 92, 174, 250, 319, 384, 444}, + {-10000, -2000, -1398, -1046, -796, -602, -444, -310, -194, -92, 0, 83, 158, 228, 292, 352}, + {-10000, -2082, -1481, -1129, -879, -685, -526, -393, -277, -174, -83, 0, 76, 145, 209, 269}, + {-10000, -2158, -1556, -1204, -954, -760, -602, -468, -352, -250, -158, -76, 0, 70, 134, 194}, + {-10000, -2228, -1626, -1274, -1024, -830, -672, -538, -422, -319, -228, -145, -70, 0, 64, 124}, + {-10000, -2292, -1690, -1338, -1088, -894, -736, -602, -486, -384, -292, -209, -134, -64, 0, 60}, + {-10000, -2352, -1750, -1398, -1148, -954, -796, -662, -546, -444, -352, -269, -194, -124, -60, 0}, + }; + + if(Left>Right) + ws_audio_set_channel_volume(Channel,Left); + else + ws_audio_set_channel_volume(Channel,Right); + + pan=TblPan[Left][Right]; + + if(ChCurPan[Channel]==pan) + return; + + ChCurPan[Channel]=pan; + + if (pan>10000) pan=10000; + pan=((pan+10000)*AUDIO_MAX_PANNING)/20000; + + if (Channel==5) + ASetVoicePanning(ws_audio_sweep_voice,pan); + else + if (Channel==4) + ASetVoicePanning(ws_audio_noise_voice,pan); + else + { + ASetVoicePanning(ws_audio_pcm_voice[Channel],pan); + } +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_audio_set_channel_pdata(int Channel,int Index) +{ + unsigned char *pData; + + if(Channel==5) + { + pData=PDataN[Index]; + + memcpy(ws_audio_sweep_wave.lpData, pData, ws_audio_sweep_wave.dwLength); + AWriteAudioData(&ws_audio_sweep_wave, 0, ws_audio_sweep_wave.dwLength); + } + else if(Channel==4) + { + pData=PDataP; + memcpy(ws_audio_noise_wave.lpData, pData, ws_audio_noise_wave.dwLength); + AWriteAudioData(&ws_audio_noise_wave, 0, ws_audio_noise_wave.dwLength); + } + else + { + pData=PData[Channel]; + memcpy(ws_audio_pcm_wave[Channel].lpData, pData, ws_audio_pcm_wave[Channel].dwLength); + AWriteAudioData(&ws_audio_pcm_wave[Channel], 0, ws_audio_pcm_wave[Channel].dwLength); + } +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_audio_set_channels_pbuf(int Addr,int Data) +{ + int i,j; + + i=(Addr&0x30)>>4; + for(j=(Addr&0x0F)<<1;j>4)-7)); + PData[i][j] = (Data&0x0f)*17-128; + PData[i][j+1] = ((Data>>4)&0x0f)*17-128; + } + if((Addr&0x0F)==0x0F) + ws_audio_set_channel_pdata(i,0); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_audio_rst_channel(int Channel) +{ + if(Channel==2) + { + ws_audio_set_channel_frequency(2,ChPerInit); + SwpCurPeriod=ChPerInit; + } +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +int ws_audio_int(void) +{ + unsigned int value; + static int i; + + if((SwpStep)&&(SNDMOD&0x40)) + { + if(CntSwp<0) + { + CntSwp=SwpTime; + SwpCurPeriod+=SwpStep; + SwpCurPeriod&=0x7FF; + value=3072000/(2048-SwpCurPeriod); + if(value>100000) + { + value=100000; + ws_audio_set_channel_volume(2,0); + } + if(value<100) + { + value=100; + } + ASetVoiceFrequency(ws_audio_pcm_voice[2],value); + } + CntSwp--; + } + i++; + if(i>=BUFSIZEN) + { + i=0; + } + return RandData[i]; +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +static DWORD PCMPos=0; +DWORD TickZ=0,PcmCount; + +void ws_audio_set_pcm(int Data) +{ + DWORD tick; + PDataP[PCMPos++]=(unsigned char)(Data+128); + //tick=GetTickCount(); + tick=SDL_GetTicks(); + PcmCount++; + if(tick>=TickZ) + { + TickZ=tick+125; + PcmCount<<=3; + if(PcmCount>=10000) + { + PcmCount=12000; + } + ASetVoiceFrequency(ws_audio_noise_voice,PcmCount); + PcmCount=0; + } + + if(PCMPos>=BUFSIZEP) + ws_audio_flash_pcm(); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_audio_flash_pcm(void) +{ + int result; + void *ptr1,*ptr2; + DWORD len1,len2; + + const DWORD WrPos[16]= + { + BUFSIZEP*0,BUFSIZEP*1,BUFSIZEP*2,BUFSIZEP*3, + BUFSIZEP*4,BUFSIZEP*5,BUFSIZEP*6,BUFSIZEP*7, + BUFSIZEP*8,BUFSIZEP*9,BUFSIZEP*10,BUFSIZEP*11, + BUFSIZEP*12,BUFSIZEP*13,BUFSIZEP*14,BUFSIZEP*15, + }; + + len1=BUFSIZEP; + memcpy(&ws_audio_noise_wave.lpData[WrPos[PcmWrPos]], PDataP, len1); + AWriteAudioData(&ws_audio_noise_wave, 0, ws_audio_noise_wave.dwLength); + + + PcmWrPos++; + PcmWrPos&=0xF; + memset(PDataP,PL,sizeof(PDataP)); + PCMPos=0; + +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_audio_write_byte(Uint32 offset, Uint8 value) +{ + if (!((offset-WaveMap)&0xFFC0)) + { + ws_audio_set_channels_pbuf(offset&0x003F,value); + internalRam[offset]=value; + } +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_audio_process(void) +{ + Uint32 i, j, b; + i=ws_audio_int(); + PCSRL=(Uint8)(i&0xFF); + PCSRH=(Uint8)((i>>8)&0xFF); + /*if ((SDMACTL & 0x98) == 0x98) + { // Hyper voice + v = Page[SDMASB + b][SDMASA + index++]; + if ((SDMASA + index) == 0) + { + b++; + } + if (v < 0x80) + { + v += 0x80; + } + else + { + v -= 0x80; + } + if (SDMACNT <= index) + { + index = 0; + b = 0; + } + return v; + } + else */ + if((SDMACTL&0x88)==0x80) + { + i=(SDMACH<<8)|SDMACL; + j=(SDMASB<<16)|(SDMASH<<8)|SDMASL; + b=cpu_readmem20(j); + if(!ws_audio_channel_isPlaying[5]) + b=0x80; + ws_ioRam[0x89]=b; + i--; + j++; + if(i<32) + { + i=0; + SDMACTL&=0x7F; + } + SDMASB=(Uint8)((j>>16)&0xFF); + SDMASH=(Uint8)((j>>8)&0xFF); + SDMASL=(Uint8)(j&0xFF); + SDMACH=(Uint8)((i>>8)&0xFF); + SDMACL=(Uint8)(i&0xFF); + } + else if((SNDMOD&0x22)==0x22) + { + b=ws_ioRam[0x89]; + if(!ws_audio_channel_isPlaying[4]) + b=0x80; + } + else + { + b=0x80; + } + b>>=1; + b+=0x40; + if(b>0xAA) + { + b=0xAA; + } + else if(b<0x55) + { + b=0x55; + } + ws_audio_set_pcm(b); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_audio_readState(int fp) +{ + long lpdwPosition; + long lpdwFrequency; + unsigned int lpnVolume; + unsigned int lpnPanning; + int lpnStatus; + unsigned char *pData; + + read(fp,&PCMPos,sizeof(DWORD)); + read(fp,&TickZ,sizeof(DWORD)); + read(fp,&PcmCount,sizeof(DWORD)); + read(fp,&WaveMap,sizeof(int)); + read(fp,&ChPerInit,sizeof(int)); + read(fp,&SwpTime,sizeof(int)); + read(fp,&SwpStep,sizeof(int)); + read(fp,&SwpCurPeriod,sizeof(int)); + read(fp,&MainVol,sizeof(int)); + read(fp,&CntSwp,sizeof(int)); + read(fp,&PcmWrPos,sizeof(int)); + + read(fp,ws_audio_channel_isPlaying,sizeof(UINT32)*6); + + read(fp,PData,sizeof(unsigned char)*4*BUFSIZE); + read(fp,PDataP,sizeof(unsigned char)*(BUFSIZEP<<4)); + read(fp,PDataN,sizeof(unsigned char)*8*BUFSIZEN); + read(fp,PDataN,sizeof(int)*BUFSIZEN); + + for (int i=0;i<4;i++) + { + read(fp,&lpdwPosition,sizeof(long)); + read(fp,&lpdwFrequency,sizeof(long)); + read(fp,&lpnVolume,sizeof(unsigned int)); + read(fp,&lpnPanning,sizeof(unsigned int)); + read(fp,&lpnStatus,sizeof(int)); + ASetVoicePosition(ws_audio_pcm_voice[i],lpdwPosition); + ASetVoiceFrequency(ws_audio_pcm_voice[i], lpdwFrequency); + ASetVoiceVolume(ws_audio_pcm_voice[i], lpnVolume); + ASetVoicePanning(ws_audio_pcm_voice[i], lpnPanning); + pData=PData[i]; + memcpy(ws_audio_pcm_wave[i].lpData, pData, ws_audio_pcm_wave[i].dwLength); + AWriteAudioData(&ws_audio_pcm_wave[i], 0, ws_audio_pcm_wave[i].dwLength); + if (ws_audio_channel_isPlaying[i]) + APlayVoice(ws_audio_pcm_voice[i], &ws_audio_pcm_wave[i]); + } + ASetVoicePosition(ws_audio_noise_voice,lpdwPosition); + ASetVoiceFrequency(ws_audio_noise_voice, lpdwFrequency); + ASetVoiceVolume(ws_audio_noise_voice, lpnVolume); + ASetVoicePanning(ws_audio_noise_voice, lpnPanning); + pData=PDataP; + memcpy(ws_audio_noise_wave.lpData, pData, ws_audio_noise_wave.dwLength); + AWriteAudioData(&ws_audio_noise_wave, 0, ws_audio_noise_wave.dwLength); + if (ws_audio_channel_isPlaying[4]) + APlayVoice(ws_audio_noise_voice, &ws_audio_noise_wave); + + read(fp,&lpdwPosition,sizeof(long)); + read(fp,&lpdwFrequency,sizeof(long)); + read(fp,&lpnVolume,sizeof(unsigned int)); + read(fp,&lpnPanning,sizeof(unsigned int)); + read(fp,&lpnStatus,sizeof(int)); + + ASetVoicePosition(ws_audio_sweep_voice,lpdwPosition); + ASetVoiceFrequency(ws_audio_sweep_voice, lpdwFrequency); + ASetVoiceVolume(ws_audio_sweep_voice, lpnVolume); + ASetVoicePanning(ws_audio_sweep_voice, lpnPanning); + pData=PDataN[0]; + memcpy(ws_audio_sweep_wave.lpData, pData, ws_audio_sweep_wave.dwLength); + AWriteAudioData(&ws_audio_sweep_wave, 0, ws_audio_sweep_wave.dwLength); + if (ws_audio_channel_isPlaying[5]) + APlayVoice(ws_audio_sweep_voice, &ws_audio_sweep_wave); + + read(fp,&lpdwPosition,sizeof(long)); + read(fp,&lpdwFrequency,sizeof(long)); + read(fp,&lpnVolume,sizeof(unsigned int)); + read(fp,&lpnPanning,sizeof(unsigned int)); + read(fp,&lpnStatus,sizeof(int)); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_audio_writeState(int fp) +{ + long lpdwPosition; + long lpdwFrequency; + unsigned int lpnVolume; + unsigned int lpnPanning; + int lpnStatus; + + write(fp,&PCMPos,sizeof(DWORD)); + write(fp,&TickZ,sizeof(DWORD)); + write(fp,&PcmCount,sizeof(DWORD)); + write(fp,&WaveMap,sizeof(int)); + write(fp,&ChPerInit,sizeof(int)); + write(fp,&SwpTime,sizeof(int)); + write(fp,&SwpStep,sizeof(int)); + write(fp,&SwpCurPeriod,sizeof(int)); + write(fp,&MainVol,sizeof(int)); + write(fp,&CntSwp,sizeof(int)); + write(fp,&PcmWrPos,sizeof(int)); + + write(fp,ws_audio_channel_isPlaying,sizeof(UINT32)*6); + + write(fp,PData,sizeof(unsigned char)*4*BUFSIZE); + write(fp,PDataP,sizeof(unsigned char)*(BUFSIZEP<<4)); + write(fp,PDataN,sizeof(unsigned char)*8*BUFSIZEN); + write(fp,PDataN,sizeof(int)*BUFSIZEN); + + for (int i=0;i<4;i++) + { + AGetVoicePosition(ws_audio_pcm_voice[i],&lpdwPosition); + AGetVoiceFrequency(ws_audio_pcm_voice[i], &lpdwFrequency); + AGetVoiceVolume(ws_audio_pcm_voice[i], &lpnVolume); + AGetVoicePanning(ws_audio_pcm_voice[i], &lpnPanning); + AGetVoiceStatus(ws_audio_pcm_voice[i], &lpnStatus); + + write(fp,&lpdwPosition,sizeof(long)); + write(fp,&lpdwFrequency,sizeof(long)); + write(fp,&lpnVolume,sizeof(unsigned int)); + write(fp,&lpnPanning,sizeof(unsigned int)); + write(fp,&lpnStatus,sizeof(int)); + } + AGetVoicePosition(ws_audio_noise_voice,&lpdwPosition); + AGetVoiceFrequency(ws_audio_noise_voice, &lpdwFrequency); + AGetVoiceVolume(ws_audio_noise_voice, &lpnVolume); + AGetVoicePanning(ws_audio_noise_voice, &lpnPanning); + AGetVoiceStatus(ws_audio_noise_voice, &lpnStatus); + + write(fp,&lpdwPosition,sizeof(long)); + write(fp,&lpdwFrequency,sizeof(long)); + write(fp,&lpnVolume,sizeof(unsigned int)); + write(fp,&lpnPanning,sizeof(unsigned int)); + write(fp,&lpnStatus,sizeof(int)); + + AGetVoicePosition(ws_audio_sweep_voice,&lpdwPosition); + AGetVoiceFrequency(ws_audio_sweep_voice, &lpdwFrequency); + AGetVoiceVolume(ws_audio_sweep_voice, &lpnVolume); + AGetVoicePanning(ws_audio_sweep_voice, &lpnPanning); + AGetVoiceStatus(ws_audio_sweep_voice, &lpnStatus); + + write(fp,&lpdwPosition,sizeof(long)); + write(fp,&lpdwFrequency,sizeof(long)); + write(fp,&lpnVolume,sizeof(unsigned int)); + write(fp,&lpnPanning,sizeof(unsigned int)); + write(fp,&lpnStatus,sizeof(int)); +} diff --git a/oswan/source/audio.h b/oswan/source/audio.h new file mode 100644 index 0000000..d437d4d --- /dev/null +++ b/oswan/source/audio.h @@ -0,0 +1,43 @@ +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef __AUDIO_H__ +#define __AUDIO_H__ + +void ws_audio_init(); +void ws_audio_reset(); +void ws_audio_port_write(DWORD port,BYTE value); +BYTE ws_audio_port_read(BYTE port); +void ws_audio_done(); + +unsigned int ws_audio_mrand(unsigned int Degree); +int ws_audio_seal_init(); +void ws_audio_seal_done(); +int ws_audio_play_channel(int Channel); +int ws_audio_stop_channel(int Channel); +void ws_audio_clear_channel(int Channel); +void ws_audio_set_channel_frequency(int Channel,int Period); +void ws_audio_set_channel_volume(int Channel,int Vol); +void ws_audio_set_channel_pan(int Channel,int Left,int Right); +void ws_audio_set_channel_pdata(int Channel,int Index); +void ws_audio_set_channels_pbuf(int Addr,int Data); +void ws_audio_rst_channel(int Channel); +int ws_audio_int(); +void ws_audio_set_pcm(int Data); +void ws_audio_flash_pcm(); +void ws_audio_write_byte(DWORD offset, BYTE value); +void ws_audio_process(); +void ws_audio_readState(int fp); +void ws_audio_writeState(int fp); +Uint32 timer_callupdate(Uint32, void*); + +#endif + diff --git a/oswan/source/filters/2xsai.h b/oswan/source/filters/2xsai.h new file mode 100644 index 0000000..813510f --- /dev/null +++ b/oswan/source/filters/2xsai.h @@ -0,0 +1,56 @@ +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_emulate_2xSaI(void) +{ + #include "filter_partA.h" + if (app_rotated) + { + surface=new Surface(144*2,224*2,format); + #include "filter_partB.h" + console.open(app_window_title,144*2,224*2,format); + + while (1) + { + #include "filter_partC.h" + console.open(app_window_title,144*2,224*2,format); + #include "filter_partD.h" + ws_rotate_backbuffer(backbuffer); + int16 *vs = (int16 *)surface->lock(); + _2xSaI ((u8*)backbuffer,144*2, NULL,(u8*)vs, surfacePitch<<1,144,224); + surface->unlock(); + surface->copy(console); + console.update(); + } + } + #include "filter_partE.h" + } + else + { + surface=new Surface(224*2,144*2,format); + #include "filter_partB.h" + console.open(app_window_title,224*2,144*2,format); + + while (1) + { + #include "filter_partC.h" + console.open(app_window_title,224*2,144*2,format); + #include "filter_partD.h" + int16 *vs = (int16 *)surface->lock(); + _2xSaI ((u8*)backbuffer,224*2, NULL,(u8*)vs, surfacePitch<<1,224,144); + surface->unlock(); + surface->copy(console); + console.update(); + } + } + #include "filter_partE.h" + } +} diff --git a/oswan/source/filters/doubled.h b/oswan/source/filters/doubled.h new file mode 100644 index 0000000..093d4b8 --- /dev/null +++ b/oswan/source/filters/doubled.h @@ -0,0 +1,220 @@ +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +__inline void ws_drawDoubledScanline(int16 *vs, int16 *backbuffer_alias) +{ + register int32 *vs_alias=(int32*)vs; + register int32 data; + + for (int pixel=0;pixel<224;pixel+=8) + { + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + } +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +__inline void ws_drawDoubledRotatedScanline(int16 *vs, int16 *backbuffer_alias) +{ + register int32 *vs_alias=(int32*)vs; + register int32 data; + + for (int pixel=0;pixel<144;pixel+=8) + { + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + } +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +uint16 ws_halfBrightnessTable[32]; +#define M_HALFBRIGHTNESS(D) (ws_halfBrightnessTable[(D>>10)&0x1f]<<10)|(ws_halfBrightnessTable[(D>>5)&0x1f]<<5)|(ws_halfBrightnessTable[D&0x1f]); + +__inline void ws_drawDoubledHalfBrightnessScanline(int16 *vs, int16 *backbuffer_alias) +{ + register int32 *vs_alias=(int32*)vs; + register int32 data; + + for (int pixel=0;pixel<224;pixel+=4) + { + data=*backbuffer_alias++; data=M_HALFBRIGHTNESS(data); data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data=M_HALFBRIGHTNESS(data); data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data=M_HALFBRIGHTNESS(data); data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data=M_HALFBRIGHTNESS(data); data|=(data<<16); *vs_alias++=data; + } +} + +__inline void ws_drawDoubledHalfBrightnessScanlineSpecialEven(int16 *vs, int16 *backbuffer_alias) +{ + register int32 *vs_alias=(int32*)vs; + register int32 data; + + for (int pixel=0;pixel<224;pixel+=4) + { + data=*backbuffer_alias++; data=M_HALFBRIGHTNESS(data); data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data=M_HALFBRIGHTNESS(data); data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + } +} +__inline void ws_drawDoubledHalfBrightnessScanlineSpecialOdd(int16 *vs, int16 *backbuffer_alias) +{ + register int32 *vs_alias=(int32*)vs; + register int32 data; + + for (int pixel=0;pixel<224;pixel+=4) + { + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data=M_HALFBRIGHTNESS(data); data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data=M_HALFBRIGHTNESS(data); data|=(data<<16); *vs_alias++=data; + } +} +__inline void ws_drawDoubledHalfBrightnessRotatedScanline(int16 *vs, int16 *backbuffer_alias) +{ + register int32 *vs_alias=(int32*)vs; + register int32 data; + + for (int pixel=0;pixel<144;pixel+=4) + { + data=*backbuffer_alias++; data=M_HALFBRIGHTNESS(data); data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data=M_HALFBRIGHTNESS(data); data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data=M_HALFBRIGHTNESS(data); data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data=M_HALFBRIGHTNESS(data); data|=(data<<16); *vs_alias++=data; + } +} + +__inline void ws_drawDoubledHalfBrightnessRotatedScanlineSpecialEven(int16 *vs, int16 *backbuffer_alias) +{ + register int32 *vs_alias=(int32*)vs; + register int32 data; + + for (int pixel=0;pixel<144;pixel+=4) + { + data=*backbuffer_alias++; data=M_HALFBRIGHTNESS(data); data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data=M_HALFBRIGHTNESS(data); data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + } +} +__inline void ws_drawDoubledHalfBrightnessRotatedScanlineSpecialOdd(int16 *vs, int16 *backbuffer_alias) +{ + register int32 *vs_alias=(int32*)vs; + register int32 data; + + for (int pixel=0;pixel<144;pixel+=4) + { + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data=M_HALFBRIGHTNESS(data); data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; + data=*backbuffer_alias++; data=M_HALFBRIGHTNESS(data); data|=(data<<16); *vs_alias++=data; + } +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_emulate_doubled(void) +{ + #include "filter_partA.h" + if (app_rotated) + { + surface=new Surface(144*2,224*2,format); + #include "filter_partB.h" + console.open(app_window_title,144*2,224*2,format); + while (1) + { + #include "filter_partC.h" + console.open(app_window_title,144*2,224*2,format); + #include "filter_partD.h" + ws_rotate_backbuffer(backbuffer); + int16 *vs = (int16 *)surface->lock(); + int16 *backbuffer_alias=backbuffer; + for (int line=0;line<224;line++) + { + ws_drawDoubledRotatedScanline(vs,backbuffer_alias); + vs+=surfacePitch; + ws_drawDoubledRotatedScanline(vs,backbuffer_alias); + vs+=surfacePitch; + backbuffer_alias+=144; + } + surface->unlock(); + surface->copy(console); + console.update(); + } + } + #include "filter_partE.h" + } + else + { + surface=new Surface(224*2,144*2,format); + #include "filter_partB.h" + console.open(app_window_title,224*2,144*2,format); + while (1) + { + #include "filter_partC.h" + console.open(app_window_title,224*2,144*2,format); + #include "filter_partD.h" + int16 *vs = (int16 *)surface->lock(); + int16 *backbuffer_alias=backbuffer; + for (int line=0;line<144;line++) + { + ws_drawDoubledScanline(vs,backbuffer_alias); + vs+=surfacePitch; + ws_drawDoubledScanline(vs,backbuffer_alias); + vs+=surfacePitch; + backbuffer_alias+=224; + } + surface->unlock(); + surface->copy(console); + console.update(); + } + } + #include "filter_partE.h" + } +} diff --git a/oswan/source/filters/filter_partA.h b/oswan/source/filters/filter_partA.h new file mode 100644 index 0000000..1dc04f5 --- /dev/null +++ b/oswan/source/filters/filter_partA.h @@ -0,0 +1,13 @@ + + Sint32 startTime, endTime, totalFrames; + Uint32 nNormalLast=0; + Sint32 nNormalFrac=0; + Sint32 nTime=0,nCount=0; int i=0; + + double dTime = 0.0, dNormalLast = 0.0, dTemp; + Sint32 surfacePitch; + + // 15 bits RGB555 + Format format(16,0x007c00,0x00003e0,0x0000001f); + Console console; + Surface *surface; diff --git a/oswan/source/filters/filter_partB.h b/oswan/source/filters/filter_partB.h new file mode 100644 index 0000000..51860c0 --- /dev/null +++ b/oswan/source/filters/filter_partB.h @@ -0,0 +1,23 @@ + int16 *backbuffer=(int16*)malloc(224*144*sizeof(int16)); + memset(backbuffer,0x00,224*144*sizeof(int16)); + surfacePitch=(surface->pitch()>>1); + console.option("DirectX"); + if (app_fullscreen) + console.option("fullscreen output"); + else + console.option("windowed output"); + console.option("fixed window"); + console.option("center window"); + totalFrames=0; + startTime=clock(); + nNormalLast=0;// Last value of timeGetTime() + nNormalFrac=0; // Extra fraction we did + //nNormalLast=timeGetTime(); + // hopefully, we only care about time delta, not time of day... + //nNormalLast = SDL_GetTicks(); + dNormalLast = (double) SDL_GetTicks(); + // filter change + if (gui_command==GUI_COMMAND_FILTER_CHANGE) + { + ws_loadState("oswan.wss"); + } diff --git a/oswan/source/filters/filter_partC.h b/oswan/source/filters/filter_partC.h new file mode 100644 index 0000000..830bb79 --- /dev/null +++ b/oswan/source/filters/filter_partC.h @@ -0,0 +1,77 @@ + //nTime=SDL_GetTicks()-nNormalLast; // calcule le temps écoulé depuis le dernier affichage + dTemp = (double) SDL_GetTicks(); + dTime = dTemp - dNormalLast; + + // nTime est en mili-secondes. + // détermine le nombre de trames à passer + 1 + //nCount = (Sint32) ((((double)nTime)*600.0 - (double)nNormalFrac) / 10000.0); + nCount = (Sint32) (dTime * 0.07547); // does this calculation make sense? + // 75.47Hz vblank is according to wstech22.txt + //printf("%d ", nCount); + + // si le nombre de trames à passer + 1 est nul ou négatif, + // ne rien faire pendant 2 ms + //AUpdateAudio(); + if (nCount<=0) + { + SDL_Delay(2); + } // No need to do anything for a bit + else + { + //nNormalFrac+=nCount*10000; // + //nNormalLast+=nNormalFrac/600; // add the duration of nNormalFrac frames + //nNormalFrac%=600; // + //dNormalLast = dTemp; + dNormalLast += nCount * (1/0.07547); + + // Pas plus de 9 (10-1) trames non affichées + if (nCount>10) + nCount=10; + +/* + ws_key_start=0; + ws_key_left=0; + ws_key_right=0; + ws_key_up=0; + ws_key_down=0; + ws_key_button_1=0; + ws_key_button_2=0; +*/ + int ws_key_esc=0; + + #include "source/temp/key.h" + if (ws_key_esc) + { + console.close(); + if (ws_rom_path) + strcpy(old_rom_path,ws_rom_path); + //gui_open(); +#ifndef GUI_OPEN_WARNED +#warning XXX something ought to take place here... +#define GUI_OPEN_WARNED +#endif + app_terminate = 1; + + if ((ws_rom_path!=NULL)||(app_terminate)) + break; + if (gui_command) + { + if (gui_command==GUI_COMMAND_RESET) + ws_reset(); + if (gui_command==GUI_COMMAND_SCHEME_CHANGE) + ws_set_colour_scheme(ws_colourScheme); + if (gui_command==GUI_COMMAND_FILTER_CHANGE) + { + ws_saveState("oswan.wss"); + ws_rom_path=old_rom_path; + delete surface; + return; + } + } + console.option("DirectX"); + if (app_fullscreen) + console.option("fullscreen output"); + else + console.option("windowed output"); + console.option("fixed window"); + console.option("center window"); diff --git a/oswan/source/filters/filter_partD.h b/oswan/source/filters/filter_partD.h new file mode 100644 index 0000000..a89be85 --- /dev/null +++ b/oswan/source/filters/filter_partD.h @@ -0,0 +1,10 @@ + + } + + + for (i=0;ilock(); + int16 *backbuffer_alias=backbuffer; + for (int line=0;line<224;line++) + { + ws_drawDoubledRotatedScanline(vs,backbuffer_alias); + vs+=surfacePitch; + ws_drawDoubledHalfBrightnessRotatedScanline(vs,backbuffer_alias); + vs+=surfacePitch; + backbuffer_alias+=144; + } + surface->unlock(); + surface->copy(console); + console.update(); + } + } + #include "filter_partE.h" + } + else + { + surface=new Surface(224*2,144*2,format); + #include "filter_partB.h" + console.open(app_window_title,224*2,144*2,format); + while (1) + { + #include "filter_partC.h" + console.open(app_window_title,224*2,144*2,format); + #include "filter_partD.h" + int16 *vs = (int16 *)surface->lock(); + int16 *backbuffer_alias=backbuffer; + for (int line=0;line<144;line++) + { + ws_drawDoubledScanline(vs,backbuffer_alias); + vs+=surfacePitch; + ws_drawDoubledHalfBrightnessScanline(vs,backbuffer_alias); + vs+=surfacePitch; + backbuffer_alias+=224; + } + surface->unlock(); + surface->copy(console); + console.update(); + } + } + #include "filter_partE.h" + } +} diff --git a/oswan/source/filters/interpolate.h b/oswan/source/filters/interpolate.h new file mode 100644 index 0000000..ba89122 --- /dev/null +++ b/oswan/source/filters/interpolate.h @@ -0,0 +1,188 @@ +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +#define M_R(A) ((A&0x7c00)>>10) +#define M_G(A) ((A&0x03e0)>>5) +#define M_B(A) (A&0x1f) +#define NB_BUFFERS 8 +#define NB_BUFFERS_DIV 3 +void ws_mergeBackbuffers(int16 **buffers) +{ + int16 *buffersAlias[NB_BUFFERS+1]; + + memcpy(buffersAlias,buffers,sizeof(int16*)*(NB_BUFFERS+1)); + + for (int i=0;i<224*144;i++) + { + int r,g,b; + r=g=b=0; + for (int j=0;j>=NB_BUFFERS_DIV; + g>>=NB_BUFFERS_DIV; + b>>=NB_BUFFERS_DIV; + *buffersAlias[NB_BUFFERS]++=(r<<10)|(g<<5)|b; + } +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_emulate_standard_interpolate(void) +{ + #define KEY_ENTER 0x0D + #define KEY_ESC 0x1b + #define KEY_UP 0x26 + #define KEY_DOWN 0x28 + #define KEY_LEFT 0x25 + #define KEY_RIGHT 0x27 + #define KEY_BUTTON1 0x57 + #define KEY_BUTTON2 0x58 + + uint32 startTime, endTime, totalFrames; + unsigned int nNormalLast=0; + int nNormalFrac=0; + int nTime=0,nCount=0; int i=0; + + // 15 bits RGB555 + Format format(16,0x007c00,0x00003e0,0x0000001f); + Console console; + Surface *surface; + if (app_rotated) + surface=new Surface(144,224,format); + else + surface=new Surface(224,144,format); + + console.option("DirectX"); + if (app_fullscreen) + console.option("fullscreen output"); + else + console.option("windowed output"); + console.option("fixed window"); + console.option("center window"); + + console.open("Oswan",224,144,format); + int16 *backbuffer[NB_BUFFERS+1]; + for (int fr=0;fr10) + nCount=10; + +/* + ws_key_start=0; + ws_key_left=0; + ws_key_right=0; + ws_key_up=0; + ws_key_down=0; + ws_key_button_1=0; + ws_key_button_2=0; +*/ int ws_key_esc=0; + + #include "./source/temp/key.h" + if (ws_key_esc) + { + console.close(); + strcpy(old_rom_path,ws_rom_path); + gui_open(); + + if ((ws_rom_path!=NULL)||(app_terminate)) + break; + if (gui_command) + { + if (gui_command==GUI_COMMAND_RESET) + ws_reset(); + if (gui_command==GUI_COMMAND_SCHEME_CHANGE) + ws_set_colour_scheme(ws_colourScheme); + if (gui_command==GUI_COMMAND_FILTER_CHANGE) + { + ws_saveState("oswan.wss"); + ws_rom_path=old_rom_path; + delete surface; + return; + } + } + console.option("DirectX"); + if (app_fullscreen) + console.option("fullscreen output"); + else + console.option("windowed output"); + console.option("fixed window"); + console.option("center window"); + console.open("Oswan",224,144,format); + } + + + for (i=0;ilock(); + memcpy(vs,backbuffer[NB_BUFFERS],224*144*2); + surface->unlock(); + surface->copy(console); + console.update(); + } + } + endTime=clock(); + float fps=totalFrames/(((float)(endTime-startTime))/(float)CLOCKS_PER_SEC); + printf("%f fps (%i %% the original speed)\n",fps, (int)((fps*100)/60)); + console.close(); + delete surface; +} diff --git a/oswan/source/filters/scanlines.h b/oswan/source/filters/scanlines.h new file mode 100644 index 0000000..891bddf --- /dev/null +++ b/oswan/source/filters/scanlines.h @@ -0,0 +1,68 @@ +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_emulate_scanlines(void) +{ + #include "filter_partA.h" + if (app_rotated) + { + surface=new Surface(144*2,224*2,format); + #include "filter_partB.h" + console.open(app_window_title,144*2,224*2,format); + while (1) + { + #include "filter_partC.h" + console.open(app_window_title,144*2,224*2,format); + #include "filter_partD.h" + ws_rotate_backbuffer(backbuffer); + int16 *vs = (int16 *)surface->lock(); + int16 *backbuffer_alias=backbuffer; + for (int line=0;line<224;line++) + { + ws_drawDoubledRotatedScanline(vs,backbuffer_alias); + vs+=surfacePitch; + vs+=surfacePitch; + backbuffer_alias+=144; + } + surface->unlock(); + surface->copy(console); + console.update(); + } + } + #include "filter_partE.h" + } + else + { + surface=new Surface(224*2,144*2,format); + #include "filter_partB.h" + console.open(app_window_title,224*2,144*2,format); + while (1) + { + #include "filter_partC.h" + console.open(app_window_title,224*2,144*2,format); + #include "filter_partD.h" + int16 *vs = (int16 *)surface->lock(); + int16 *backbuffer_alias=backbuffer; + for (int line=0;line<144;line++) + { + ws_drawDoubledScanline(vs,backbuffer_alias); + vs+=surfacePitch; + vs+=surfacePitch; + backbuffer_alias+=224; + } + surface->unlock(); + surface->copy(console); + console.update(); + } + } + #include "filter_partE.h" + } +} diff --git a/oswan/source/filters/special.h b/oswan/source/filters/special.h new file mode 100644 index 0000000..57b582c --- /dev/null +++ b/oswan/source/filters/special.h @@ -0,0 +1,71 @@ +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_emulate_special(void) +{ + #include "filter_partA.h" + if (app_rotated) + { + surface=new Surface(144*2,224*2,format); + #include "filter_partB.h" + console.open(app_window_title,144*2,224*2,format); + while (1) + { + #include "filter_partC.h" + console.open(app_window_title,144*2,224*2,format); + #include "filter_partD.h" + ws_rotate_backbuffer(backbuffer); + int16 *vs = (int16 *)surface->lock(); + int16 *backbuffer_alias=backbuffer; + for (int line=0;line<224;line++) + { + ws_drawDoubledHalfBrightnessRotatedScanlineSpecialEven(vs,backbuffer_alias); + vs+=surfacePitch; + ws_drawDoubledHalfBrightnessRotatedScanlineSpecialOdd(vs,backbuffer_alias); + vs+=surfacePitch; + backbuffer_alias+=144; + } + surface->unlock(); + surface->copy(console); + console.update(); + } + } + #include "filter_partE.h" + } + else + { + surface=new Surface(224*2,144*2,format); + #include "filter_partB.h" + console.open(app_window_title,224*2,144*2,format); + while (1) + { + #include "filter_partC.h" + console.open(app_window_title,224*2,144*2,format); + #include "filter_partD.h" + while (!ws_executeLine(backbuffer,1)); + int16 *vs = (int16 *)surface->lock(); + int16 *backbuffer_alias=backbuffer; + for (int line=0;line<144;line++) + { + ws_drawDoubledHalfBrightnessScanlineSpecialEven(vs,backbuffer_alias); + vs+=surfacePitch; + ws_drawDoubledHalfBrightnessScanlineSpecialOdd(vs,backbuffer_alias); + vs+=surfacePitch; + backbuffer_alias+=224; + } + surface->unlock(); + surface->copy(console); + console.update(); + } + } + #include "filter_partE.h" + } +} diff --git a/oswan/source/filters/standard.h b/oswan/source/filters/standard.h new file mode 100644 index 0000000..9d6bb69 --- /dev/null +++ b/oswan/source/filters/standard.h @@ -0,0 +1,75 @@ +//////////////////////////////////////////////////////////////////////////////// +// VERY SLOW !!!! +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_rotate_backbuffer(int16 *backbuffer) +{ + static int16 temp[224*144]; + memcpy(temp,backbuffer,224*144*2); + + for (int line=0;line<144;line++) + for (int column=0;column<224;column++) + backbuffer[line+((223-column)<<7)+((223-column)<<4)]=temp[column+(line<<7)+(line<<6)+(line<<5)]; +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_emulate_standard(void) +{ + #include "filter_partA.h" + if (app_rotated) + { + surface=new Surface(144,224,format); + #include "filter_partB.h" + surfacePitch>>=1; + console.open(app_window_title,144,224,format); + while (1) + { + #include "filter_partC.h" + console.open(app_window_title,144,224,format); + #include "filter_partD.h" + ws_rotate_backbuffer(backbuffer); + int32 *vs = (int32 *)surface->lock(); + memcpy(vs,backbuffer,224*144*2); + surface->unlock(); + surface->copy(console); + console.update(); + } + } + #include "filter_partE.h" + } + else + { + surface=new Surface(224,144,format); + #include "filter_partB.h" + console.open(app_window_title,224,144,format); + while (1) + { + #include "filter_partC.h" + console.open(app_window_title,224,144,format); + #include "filter_partD.h" + int32 *vs = (int32 *)surface->lock(); + memcpy(vs,backbuffer,224*144*2); + surface->unlock(); + surface->copy(console); + console.update(); + } + } + #include "filter_partE.h" + } +} diff --git a/oswan/source/filters/super2xsai.h b/oswan/source/filters/super2xsai.h new file mode 100644 index 0000000..eb2de17 --- /dev/null +++ b/oswan/source/filters/super2xsai.h @@ -0,0 +1,54 @@ +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_emulate_Super2xSaI(void) +{ + #include "filter_partA.h" + if (app_rotated) + { + surface=new Surface(144*2,224*2,format); + #include "filter_partB.h" + console.open(app_window_title,144*2,224*2,format); + while (1) + { + #include "filter_partC.h" + console.open(app_window_title,144*2,224*2,format); + #include "filter_partD.h" + ws_rotate_backbuffer(backbuffer); + int16 *vs = (int16 *)surface->lock(); + Super2xSaI ((u8*)backbuffer,144*2, NULL,(u8*)vs, surfacePitch<<1,144,224); + surface->unlock(); + surface->copy(console); + console.update(); + } + } + #include "filter_partE.h" + } + else + { + surface=new Surface(224*2,144*2,format); + #include "filter_partB.h" + console.open(app_window_title,224*2,144*2,format); + while (1) + { + #include "filter_partC.h" + console.open(app_window_title,224*2,144*2,format); + #include "filter_partD.h" + int16 *vs = (int16 *)surface->lock(); + Super2xSaI ((u8*)backbuffer,224*2, NULL,(u8*)vs, surfacePitch<<1,224,144); + surface->unlock(); + surface->copy(console); + console.update(); + } + } + #include "filter_partE.h" + } +} diff --git a/oswan/source/filters/supereagle.h b/oswan/source/filters/supereagle.h new file mode 100644 index 0000000..3cf0434 --- /dev/null +++ b/oswan/source/filters/supereagle.h @@ -0,0 +1,54 @@ +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_emulate_SuperEagle(void) +{ + #include "filter_partA.h" + if (app_rotated) + { + surface=new Surface(144*2,224*2,format); + #include "filter_partB.h" + console.open(app_window_title,144*2,224*2,format); + while (1) + { + #include "filter_partC.h" + console.open(app_window_title,144*2,224*2,format); + #include "filter_partD.h" + ws_rotate_backbuffer(backbuffer); + int16 *vs = (int16 *)surface->lock(); + SuperEagle ((u8*)backbuffer,144*2, NULL,(u8*)vs, surfacePitch<<1,144,224); + surface->unlock(); + surface->copy(console); + console.update(); + } + } + #include "filter_partE.h" + } + else + { + surface=new Surface(224*2,144*2,format); + #include "filter_partB.h" + console.open(app_window_title,224*2,144*2,format); + while (1) + { + #include "filter_partC.h" + console.open(app_window_title,224*2,144*2,format); + #include "filter_partD.h" + int16 *vs = (int16 *)surface->lock(); + SuperEagle ((u8*)backbuffer,224*2, NULL,(u8*)vs, surfacePitch<<1,224,144); + surface->unlock(); + surface->copy(console); + console.update(); + } + } + #include "filter_partE.h" + } +} diff --git a/oswan/source/gpu.cpp b/oswan/source/gpu.cpp new file mode 100644 index 0000000..3880558 --- /dev/null +++ b/oswan/source/gpu.cpp @@ -0,0 +1,1605 @@ +//////////////////////////////////////////////////////////////////////////////// +// GPU +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// 7.04.2002: Fixed sprites order +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// + +//#define STATISTICS + +#include +#include +#include +#include +#include +#include "log.h" +#include "rom.h" +#include "./nec/nec.h" +#include "io.h" +#include "gpu.h" + +#ifdef STATISTICS + #include "ticker.h" +#endif +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +extern uint8 *internalRam; + +enum VideoModes +{ + DISPLAY_MODE_GRAY = 0, + DISPLAY_MODE_2BPP = 4, + DISPLAY_MODE_P_4BPP = 7, + DISPLAY_MODE_L_4BPP = 6, +}; + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +#ifdef STATISTICS + long ws_4_shades_tiles_cache_update_time=0; + long ws_4_colors_tiles_cache_update_time=0; + long ws_16_colors_packed_tiles_cache_update_time=0; + long ws_16_colors_layered_tiles_cache_update_time=0; + + long ws_4_shades_tiles_cache_update_number=0; + long ws_4_colors_tiles_cache_update_number=0; + long ws_16_colors_packed_tiles_cache_update_number=0; + long ws_16_colors_layered_tiles_cache_update_number=0; + + long ws_background_color_rendering_time=0; + long ws_background_rendering_time=0; + long ws_foreground_rendering_time=0; + long ws_priority_0_sprites_rendering_time=0; + long ws_priority_1_sprites_rendering_time=0; +#endif +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +#define RGB555(R,G,B) ((((int)(R))<<10)|(((int)(G))<<5)|((int)(B))) + +uint8 ws_gpu_operatingInColor; +uint8 ws_videoMode; +uint8 ws_gpu_scanline=0; +int16 ws_palette[16*4]; +int8 ws_paletteColors[8]; +int16 wsc_palette[16*16]; +int16 ws_shades[16]; +int ws_gpu_forceColorSystemBool=0; +int ws_gpu_forceMonoSystemBool=0; + + + +// white +#define SHADE_COLOR_RED 1.00 +#define SHADE_COLOR_GREEN 1.00 +#define SHADE_COLOR_BLUE 1.00 + +int16 ws_colour_scheme_default[16]={ + RGB555(SHADE_COLOR_RED*30,SHADE_COLOR_GREEN*30,SHADE_COLOR_BLUE*30), + RGB555(SHADE_COLOR_RED*28,SHADE_COLOR_GREEN*28,SHADE_COLOR_BLUE*28), + RGB555(SHADE_COLOR_RED*26,SHADE_COLOR_GREEN*26,SHADE_COLOR_BLUE*26), + RGB555(SHADE_COLOR_RED*24,SHADE_COLOR_GREEN*24,SHADE_COLOR_BLUE*24), + RGB555(SHADE_COLOR_RED*22,SHADE_COLOR_GREEN*22,SHADE_COLOR_BLUE*22), + RGB555(SHADE_COLOR_RED*20,SHADE_COLOR_GREEN*20,SHADE_COLOR_BLUE*20), + RGB555(SHADE_COLOR_RED*18,SHADE_COLOR_GREEN*18,SHADE_COLOR_BLUE*18), + RGB555(SHADE_COLOR_RED*16,SHADE_COLOR_GREEN*16,SHADE_COLOR_BLUE*16), + RGB555(SHADE_COLOR_RED*14,SHADE_COLOR_GREEN*14,SHADE_COLOR_BLUE*14), + RGB555(SHADE_COLOR_RED*12,SHADE_COLOR_GREEN*12,SHADE_COLOR_BLUE*12), + RGB555(SHADE_COLOR_RED*10,SHADE_COLOR_GREEN*10,SHADE_COLOR_BLUE*10), + RGB555(SHADE_COLOR_RED*8,SHADE_COLOR_GREEN*8,SHADE_COLOR_BLUE*8), + RGB555(SHADE_COLOR_RED*6,SHADE_COLOR_GREEN*6,SHADE_COLOR_BLUE*6), + RGB555(SHADE_COLOR_RED*4,SHADE_COLOR_GREEN*4,SHADE_COLOR_BLUE*4), + RGB555(SHADE_COLOR_RED*2,SHADE_COLOR_GREEN*2,SHADE_COLOR_BLUE*2), + RGB555(SHADE_COLOR_RED*0,SHADE_COLOR_GREEN*0,SHADE_COLOR_BLUE*0) + }; +// green +#undef SHADE_COLOR_RED +#undef SHADE_COLOR_GREEN +#undef SHADE_COLOR_BLUE +#define SHADE_COLOR_RED 0.20 +#define SHADE_COLOR_GREEN 0.90 +#define SHADE_COLOR_BLUE 0.20 + +int16 ws_colour_scheme_green[16]={ + RGB555(SHADE_COLOR_RED*30,SHADE_COLOR_GREEN*30,SHADE_COLOR_BLUE*30), + RGB555(SHADE_COLOR_RED*28,SHADE_COLOR_GREEN*28,SHADE_COLOR_BLUE*28), + RGB555(SHADE_COLOR_RED*26,SHADE_COLOR_GREEN*26,SHADE_COLOR_BLUE*26), + RGB555(SHADE_COLOR_RED*24,SHADE_COLOR_GREEN*24,SHADE_COLOR_BLUE*24), + RGB555(SHADE_COLOR_RED*22,SHADE_COLOR_GREEN*22,SHADE_COLOR_BLUE*22), + RGB555(SHADE_COLOR_RED*20,SHADE_COLOR_GREEN*20,SHADE_COLOR_BLUE*20), + RGB555(SHADE_COLOR_RED*18,SHADE_COLOR_GREEN*18,SHADE_COLOR_BLUE*18), + RGB555(SHADE_COLOR_RED*16,SHADE_COLOR_GREEN*16,SHADE_COLOR_BLUE*16), + RGB555(SHADE_COLOR_RED*14,SHADE_COLOR_GREEN*14,SHADE_COLOR_BLUE*14), + RGB555(SHADE_COLOR_RED*12,SHADE_COLOR_GREEN*12,SHADE_COLOR_BLUE*12), + RGB555(SHADE_COLOR_RED*10,SHADE_COLOR_GREEN*10,SHADE_COLOR_BLUE*10), + RGB555(SHADE_COLOR_RED*8,SHADE_COLOR_GREEN*8,SHADE_COLOR_BLUE*8), + RGB555(SHADE_COLOR_RED*6,SHADE_COLOR_GREEN*6,SHADE_COLOR_BLUE*6), + RGB555(SHADE_COLOR_RED*4,SHADE_COLOR_GREEN*4,SHADE_COLOR_BLUE*4), + RGB555(SHADE_COLOR_RED*2,SHADE_COLOR_GREEN*2,SHADE_COLOR_BLUE*2), + RGB555(SHADE_COLOR_RED*0,SHADE_COLOR_GREEN*0,SHADE_COLOR_BLUE*0) + }; +// amber +#undef SHADE_COLOR_RED +#undef SHADE_COLOR_GREEN +#undef SHADE_COLOR_BLUE +#define SHADE_COLOR_RED 1.00 +#define SHADE_COLOR_GREEN 0.61 +#define SHADE_COLOR_BLUE 0.00 + +int16 ws_colour_scheme_amber[16]={ + RGB555(SHADE_COLOR_RED*30,SHADE_COLOR_GREEN*30,SHADE_COLOR_BLUE*30), + RGB555(SHADE_COLOR_RED*28,SHADE_COLOR_GREEN*28,SHADE_COLOR_BLUE*28), + RGB555(SHADE_COLOR_RED*26,SHADE_COLOR_GREEN*26,SHADE_COLOR_BLUE*26), + RGB555(SHADE_COLOR_RED*24,SHADE_COLOR_GREEN*24,SHADE_COLOR_BLUE*24), + RGB555(SHADE_COLOR_RED*22,SHADE_COLOR_GREEN*22,SHADE_COLOR_BLUE*22), + RGB555(SHADE_COLOR_RED*20,SHADE_COLOR_GREEN*20,SHADE_COLOR_BLUE*20), + RGB555(SHADE_COLOR_RED*18,SHADE_COLOR_GREEN*18,SHADE_COLOR_BLUE*18), + RGB555(SHADE_COLOR_RED*16,SHADE_COLOR_GREEN*16,SHADE_COLOR_BLUE*16), + RGB555(SHADE_COLOR_RED*14,SHADE_COLOR_GREEN*14,SHADE_COLOR_BLUE*14), + RGB555(SHADE_COLOR_RED*12,SHADE_COLOR_GREEN*12,SHADE_COLOR_BLUE*12), + RGB555(SHADE_COLOR_RED*10,SHADE_COLOR_GREEN*10,SHADE_COLOR_BLUE*10), + RGB555(SHADE_COLOR_RED*8,SHADE_COLOR_GREEN*8,SHADE_COLOR_BLUE*8), + RGB555(SHADE_COLOR_RED*6,SHADE_COLOR_GREEN*6,SHADE_COLOR_BLUE*6), + RGB555(SHADE_COLOR_RED*4,SHADE_COLOR_GREEN*4,SHADE_COLOR_BLUE*4), + RGB555(SHADE_COLOR_RED*2,SHADE_COLOR_GREEN*2,SHADE_COLOR_BLUE*2), + RGB555(SHADE_COLOR_RED*0,SHADE_COLOR_GREEN*0,SHADE_COLOR_BLUE*0) + }; + +uint8 *ws_tile_cache; +uint8 *ws_hflipped_tile_cache; + +uint8 *wsc_tile_cache; +uint8 *wsc_hflipped_tile_cache; + +uint8 *ws_modified_tile; +uint8 *wsc_modified_tile; + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_gpu_set_colour_scheme(int scheme) +{ + switch (scheme) + { + case COLOUR_SCHEME_DEFAULT: memcpy(ws_shades,ws_colour_scheme_default,16*sizeof(int16)); break; + case COLOUR_SCHEME_AMBER : memcpy(ws_shades,ws_colour_scheme_amber,16*sizeof(int16)); break; + case COLOUR_SCHEME_GREEN : memcpy(ws_shades,ws_colour_scheme_green,16*sizeof(int16)); break; + } +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_gpu_forceColorSystem(void) +{ + ws_gpu_forceColorSystemBool=1; + ws_gpu_forceMonoSystemBool=0; + ws_gpu_operatingInColor=1; +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_gpu_forceMonoSystem(void) +{ + ws_gpu_forceColorSystemBool=0; + ws_gpu_forceMonoSystemBool=1; + ws_gpu_operatingInColor=0; +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_gpu_init(void) +{ + ws_tile_cache = (uint8*)malloc(512*8*8); + wsc_tile_cache = (uint8*)malloc(1024*8*8); + + ws_hflipped_tile_cache = (uint8*)malloc(512*8*8); + wsc_hflipped_tile_cache = (uint8*)malloc(1024*8*8); + + ws_modified_tile = (uint8*)malloc(512); + wsc_modified_tile = (uint8*)malloc(1024); + + memset(ws_tile_cache,0x00,512*8*8); + memset(wsc_tile_cache,0x00,1024*8*8); + + memset(ws_hflipped_tile_cache,0x00,512*8*8); + memset(wsc_hflipped_tile_cache,0x00,1024*8*8); + + memset(ws_modified_tile,0x01,512); + memset(wsc_modified_tile,0x01,1024); + + ws_gpu_forceColorSystemBool=0; + ws_gpu_forceMonoSystemBool=0; +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_gpu_done(void) +{ + free(ws_tile_cache); + free(wsc_tile_cache); + free(ws_hflipped_tile_cache); + free(wsc_hflipped_tile_cache); + free(ws_modified_tile); + free(wsc_modified_tile); +#ifdef STATISTICS + printf("Statistics:\n"); + printf("\tcache:\n"); + if (ws_4_shades_tiles_cache_update_number) + printf("\t\t4 shades tiles update time : %i\n",ws_4_shades_tiles_cache_update_time/ws_4_shades_tiles_cache_update_number); + if (ws_4_colors_tiles_cache_update_number) + printf("\t\t4 colors tiles update time : %i\n",ws_4_colors_tiles_cache_update_time/ws_4_colors_tiles_cache_update_number); + if (ws_16_colors_packed_tiles_cache_update_number) + printf("\t\t16 colors packed tiles update time : %i\n",ws_16_colors_packed_tiles_cache_update_time/ws_16_colors_packed_tiles_cache_update_number); + if (ws_16_colors_layered_tiles_cache_update_number) + printf("\t\t16 colors layered tiles update time: %i\n",ws_16_colors_layered_tiles_cache_update_time/ws_16_colors_layered_tiles_cache_update_number); + + printf("\tscanline rendering:\n"); + long total= ws_background_color_rendering_time+ws_background_rendering_time+ + ws_foreground_rendering_time+ws_priority_0_sprites_rendering_time+ + ws_priority_1_sprites_rendering_time; + printf("\t\tbackground color : %4i (%3i %%)\n",ws_background_color_rendering_time,(ws_background_color_rendering_time*100)/total); + printf("\t\tbackground : %4i (%3i %%)\n",ws_background_rendering_time,(ws_background_rendering_time*100)/total); + printf("\t\tforeground : %4i (%3i %%)\n",ws_foreground_rendering_time,(ws_foreground_rendering_time*100)/total); + printf("\t\tpriority 0 sprites : %4i (%3i %%)\n",ws_priority_0_sprites_rendering_time,(ws_priority_0_sprites_rendering_time*100)/total); + printf("\t\tpriority 1 sprites : %4i (%3i %%)\n",ws_priority_1_sprites_rendering_time,(ws_priority_1_sprites_rendering_time*100)/total); +#endif +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_gpu_changeVideoMode(uint8 value) +{ + if (ws_videoMode != (value>>5)) + { + ws_videoMode = value >> 5; +// if (ws_videoMode==4) +// ws_videoMode=2; + + // mark all tiles dirty + memset(wsc_modified_tile,0x01,1024); + memset(ws_modified_tile,0x01,512); + } +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_gpu_reset(void) +{ + memset(wsc_modified_tile,0x01,1024); + memset(ws_modified_tile,0x01,512); + ws_gpu_scanline=0; + ws_gpu_changeVideoMode(0x00); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_gpu_clearCache(void) +{ + memset(wsc_modified_tile,0x01,1024); + memset(ws_modified_tile,0x01,512); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +uint8 *ws_tileCache_getTileRow(uint32 tileIndex, uint32 line, + uint32 vFlip, uint32 hFlip, uint32 bank) +{ + if (ws_gpu_operatingInColor) + { + if (bank) + tileIndex+=512; + + // need to update tile cache ? + // 4 colors tiles + if ((ws_videoMode == DISPLAY_MODE_2BPP) && ( ws_modified_tile[tileIndex]) ) + { +#ifdef STATISTICS + ws_4_colors_tiles_cache_update_time+=-ticker(); +#endif + uint8 *tileInCachePtr = &wsc_tile_cache[tileIndex<<6]; + uint8 *hflippedTileInCachePtr = &wsc_hflipped_tile_cache[tileIndex<<6]; + uint16 *tileInRamPtr = (uint16*)&internalRam[0x2000+(tileIndex<<4)]; + uint16 tileLine; + + for (int line=0;line<8;line++) + { + tileLine=*tileInRamPtr++; + + tileInCachePtr[0]=((tileLine&0x80)>>7)|((tileLine&0x8000)>>14); + hflippedTileInCachePtr[7]=tileInCachePtr[0]; + tileInCachePtr[1]=((tileLine&0x40)>>6)|((tileLine&0x4000)>>13); + hflippedTileInCachePtr[6]=tileInCachePtr[1]; + tileInCachePtr[2]=((tileLine&0x20)>>5)|((tileLine&0x2000)>>12); + hflippedTileInCachePtr[5]=tileInCachePtr[2]; + tileInCachePtr[3]=((tileLine&0x10)>>4)|((tileLine&0x1000)>>11); + hflippedTileInCachePtr[4]=tileInCachePtr[3]; + tileInCachePtr[4]=((tileLine&0x08)>>3)|((tileLine&0x0800)>>10); + hflippedTileInCachePtr[3]=tileInCachePtr[4]; + tileInCachePtr[5]=((tileLine&0x04)>>2)|((tileLine&0x0400)>>9); + hflippedTileInCachePtr[2]=tileInCachePtr[5]; + tileInCachePtr[6]=((tileLine&0x02)>>1)|((tileLine&0x0200)>>8); + hflippedTileInCachePtr[1]=tileInCachePtr[6]; + tileInCachePtr[7]=((tileLine&0x01)>>0)|((tileLine&0x0100)>>7); + hflippedTileInCachePtr[0]=tileInCachePtr[7]; + + tileInCachePtr+=8; + hflippedTileInCachePtr+=8; + } + ws_modified_tile[tileIndex]=0; +#ifdef STATISTICS + ws_4_colors_tiles_cache_update_time+=ticker(); + ws_4_colors_tiles_cache_update_number++; +#endif + } + else if (wsc_modified_tile[tileIndex]) + { + // 16 colors by tile layered mode + if (ws_videoMode == DISPLAY_MODE_L_4BPP) + { +#ifdef STATISTICS + ws_16_colors_layered_tiles_cache_update_time+=-ticker(); +#endif + uint8 *tileInCachePtr = &wsc_tile_cache[tileIndex<<6]; + uint8 *hflippedTileInCachePtr = &wsc_hflipped_tile_cache[tileIndex<<6]; + uint32 *tileInRamPtr = (uint32*)&internalRam[0x4000+(tileIndex<<5)]; + uint32 tileLine; + + for (int line=0;line<8;line++) + { + tileLine=*tileInRamPtr++; + + tileInCachePtr[0]=((tileLine&0x00000080)>>7)|((tileLine&0x00008000)>>14)| + ((tileLine&0x00800000)>>21)|((tileLine&0x80000000)>>28); + hflippedTileInCachePtr[7]=tileInCachePtr[0]; + + tileInCachePtr[1]=((tileLine&0x00000040)>>6)|((tileLine&0x00004000)>>13)| + ((tileLine&0x00400000)>>20)|((tileLine&0x40000000)>>27); + hflippedTileInCachePtr[6]=tileInCachePtr[1]; + + tileInCachePtr[2]=((tileLine&0x00000020)>>5)|((tileLine&0x00002000)>>12)| + ((tileLine&0x00200000)>>19)|((tileLine&0x20000000)>>26); + hflippedTileInCachePtr[5]=tileInCachePtr[2]; + + tileInCachePtr[3]=((tileLine&0x00000010)>>4)|((tileLine&0x00001000)>>11)| + ((tileLine&0x00100000)>>18)|((tileLine&0x10000000)>>25); + hflippedTileInCachePtr[4]=tileInCachePtr[3]; + + tileInCachePtr[4]=((tileLine&0x00000008)>>3)|((tileLine&0x00000800)>>10)| + ((tileLine&0x00080000)>>17)|((tileLine&0x08000000)>>24); + hflippedTileInCachePtr[3]=tileInCachePtr[4]; + + tileInCachePtr[5]=((tileLine&0x00000004)>>2)|((tileLine&0x00000400)>>9)| + ((tileLine&0x00040000)>>16)|((tileLine&0x04000000)>>23); + hflippedTileInCachePtr[2]=tileInCachePtr[5]; + + tileInCachePtr[6]=((tileLine&0x00000002)>>1)|((tileLine&0x00000200)>>8)| + ((tileLine&0x00020000)>>15)|((tileLine&0x02000000)>>22); + hflippedTileInCachePtr[1]=tileInCachePtr[6]; + + tileInCachePtr[7]=((tileLine&0x00000001)>>0)|((tileLine&0x00000100)>>7)| + ((tileLine&0x00010000)>>14)|((tileLine&0x01000000)>>21); + hflippedTileInCachePtr[0]=tileInCachePtr[7]; + + tileInCachePtr+=8; + hflippedTileInCachePtr+=8; + } +#ifdef STATISTICS + ws_16_colors_layered_tiles_cache_update_time+=ticker(); + ws_16_colors_layered_tiles_cache_update_number++; +#endif + } + else + // 16 colors by tile packed mode + if (ws_videoMode == DISPLAY_MODE_P_4BPP) + { +#ifdef STATISTICS + ws_16_colors_packed_tiles_cache_update_time+=-ticker(); +#endif + uint8 *tileInCachePtr = &wsc_tile_cache[tileIndex<<6]; + uint8 *hflippedTileInCachePtr = &wsc_hflipped_tile_cache[tileIndex<<6]; + uint32 *tileInRamPtr = (uint32*)&internalRam[0x4000+(tileIndex<<5)]; + uint32 tileLine; + + for (int line=0;line<8;line++) + { + tileLine=*tileInRamPtr++; + + tileInCachePtr[0]=(tileLine>>4)&0x0f; + hflippedTileInCachePtr[7]=tileInCachePtr[0]; + tileInCachePtr[1]=(tileLine>>0)&0x0f; + hflippedTileInCachePtr[6]=tileInCachePtr[1]; + tileInCachePtr[2]=(tileLine>>12)&0x0f; + hflippedTileInCachePtr[5]=tileInCachePtr[2]; + tileInCachePtr[3]=(tileLine>>8)&0x0f; + hflippedTileInCachePtr[4]=tileInCachePtr[3]; + tileInCachePtr[4]=(tileLine>>20)&0x0f; + hflippedTileInCachePtr[3]=tileInCachePtr[4]; + tileInCachePtr[5]=(tileLine>>16)&0x0f; + hflippedTileInCachePtr[2]=tileInCachePtr[5]; + tileInCachePtr[6]=(tileLine>>28)&0x0f; + hflippedTileInCachePtr[1]=tileInCachePtr[6]; + tileInCachePtr[7]=(tileLine>>24)&0x0f; + hflippedTileInCachePtr[0]=tileInCachePtr[7]; + + tileInCachePtr+=8; + hflippedTileInCachePtr+=8; + + } +#ifdef STATISTICS + ws_16_colors_packed_tiles_cache_update_time+=ticker(); + ws_16_colors_packed_tiles_cache_update_number++; +#endif + } + else + { + // unknown mode + } + // tile cache updated + wsc_modified_tile[tileIndex]=0; + } + if (vFlip) + line=7-line; + if (hFlip) + return(&wsc_hflipped_tile_cache[(tileIndex<<6)+(line<<3)]); + else + return(&wsc_tile_cache[(tileIndex<<6)+(line<<3)]); + + } + else + { + // need to update tile cache ? + if (ws_modified_tile[tileIndex]) + { +#ifdef STATISTICS + ws_4_shades_tiles_cache_update_time+=-ticker(); +#endif + uint8 *tileInCachePtr = &ws_tile_cache[tileIndex<<6]; + uint8 *hflippedTileInCachePtr = &ws_hflipped_tile_cache[(tileIndex<<6)+7]; + uint32 *tileInRamPtr = (uint32*)&internalRam[0x2000+(tileIndex<<4)]; + uint32 tileLine; + + for (int line=0;line<4;line++) + { + tileLine=*tileInRamPtr++; + + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x80)>>7)|((tileLine&0x8000)>>14); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x40)>>6)|((tileLine&0x4000)>>13); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x20)>>5)|((tileLine&0x2000)>>12); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x10)>>4)|((tileLine&0x1000)>>11); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x08)>>3)|((tileLine&0x0800)>>10); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x04)>>2)|((tileLine&0x0400)>>9); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x02)>>1)|((tileLine&0x0200)>>8); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x01)>>0)|((tileLine&0x0100)>>7); + hflippedTileInCachePtr+=16; + tileLine>>=16; + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x80)>>7)|((tileLine&0x8000)>>14); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x40)>>6)|((tileLine&0x4000)>>13); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x20)>>5)|((tileLine&0x2000)>>12); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x10)>>4)|((tileLine&0x1000)>>11); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x08)>>3)|((tileLine&0x0800)>>10); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x04)>>2)|((tileLine&0x0400)>>9); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x02)>>1)|((tileLine&0x0200)>>8); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x01)>>0)|((tileLine&0x0100)>>7); + hflippedTileInCachePtr+=16; + } + // tile cache updated + ws_modified_tile[tileIndex]=0; +#ifdef STATISTICS + ws_4_shades_tiles_cache_update_time+=ticker(); + ws_4_shades_tiles_cache_update_number++; +#endif + } + if (vFlip) + line=7-line; + if (hFlip) + return(&ws_hflipped_tile_cache[(tileIndex<<6)+(line<<3)]); + else + return(&ws_tile_cache[(tileIndex<<6)+(line<<3)]); + } + return(NULL); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_drawClippedSpriteLine(int16 *framebuffer, uint16 scanline, + uint32 x, uint32 y, uint32 tileIndex, uint32 paletteIndex, + uint32 vFlip, uint32 hFlip, + uint32 clip_x0, uint32 clip_y0, uint32 clip_x1, uint32 clip_y1) +{ + + if ((scanline(y+7))) + return; + if (((x+7=clip_x1))) + return; +// if (!((y+7=clip_y1))) +// return; + if(scanline>clip_y0 && scanlineclip_x1) + nbPixels=(clip_x1-x); + framebuffer+=x; + + if (ws_gpu_operatingInColor) + { + int16 *wsc_paletteAlias=&wsc_palette[paletteIndex<<4]; + while (nbPixels) + { + if (*ws_tileRow) *framebuffer=wsc_paletteAlias[*ws_tileRow]; + framebuffer++; ws_tileRow++; + nbPixels--; + } + } + else + { + int16 *ws_paletteAlias=&ws_palette[paletteIndex<<2]; + if (paletteIndex&0x04) + { + while (nbPixels) + { + if (*ws_tileRow) *framebuffer=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; + framebuffer++; ws_tileRow++; + nbPixels--; + } + } + else + { + while (nbPixels) + { + *framebuffer=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; + framebuffer++; ws_tileRow++; + nbPixels--; + } + } + } +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_gpu_renderScanline(int16 *framebuffer) +{ + + if (ws_gpu_scanline>143) + return; +#ifdef STATISTICS + long startTime=ticker(); +#endif + framebuffer+=(224*ws_gpu_scanline); + + // fill with background color + int16 backgroundColor; + if (ws_gpu_operatingInColor) + backgroundColor=wsc_palette[ws_ioRam[0x01]]; + else + backgroundColor=ws_shades[ws_paletteColors[ws_palette[((ws_ioRam[0x01]&0xf0)>>2)+(ws_ioRam[0x01]&0x03)]]]; + + for (int i=0;i<224;i++) + framebuffer[i]=backgroundColor; +#ifdef STATISTICS + ws_background_color_rendering_time=ticker(); +#endif + // render background layer + if (ws_ioRam[0x00]&0x01) + { + int ws_bgScroll_x=ws_ioRam[0x10]; + int ws_bgScroll_y=ws_ioRam[0x11]; + + // seek to the first tile + ws_bgScroll_y=(ws_bgScroll_y+ws_gpu_scanline)&0xff; + + // note: byte ordering assumptions! + int ws_currentTile=(ws_bgScroll_x>>3); + uint16 *ws_bgScrollRamBase=(uint16*)(internalRam+(((uint32)ws_ioRam[0x07]&0x0f)<<11)+ + ((ws_bgScroll_y&0xfff8)<<3)); + + int lineInTile = ws_bgScroll_y&0x07; + int columnInTile = ws_bgScroll_x&0x07; + + int16 *scanlinePtr=framebuffer; + + if (ws_gpu_operatingInColor) + { + // render the first clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_bgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *wsc_paletteAlias=&wsc_palette[((tileInfo>>9)&0x0f)<<4]; + ws_tileRow+=columnInTile; + for (int i=columnInTile;i<8;i++) + { + if (*ws_tileRow) + *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; + scanlinePtr++; + ws_tileRow++; + } + } + + // render the tiles between them + int nbTiles=28; + if (columnInTile) + nbTiles=27; + + for (int i=0;i>9)&0x0f)<<4]; + + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + } + + // render the last clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_bgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *wsc_paletteAlias=&wsc_palette[((tileInfo>>9)&0x0f)<<4]; + + + for (int i=0;i>9)&0x0f)<<2]; + ws_tileRow+=columnInTile; + + if ((tileInfo>>9)&0x04) + { + for (int i=columnInTile;i<8;i++) + { + if (*ws_tileRow) + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; + scanlinePtr++; + ws_tileRow++; + } + } + else + { + for (int i=columnInTile;i<8;i++) + { + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; + scanlinePtr++; + ws_tileRow++; + } + } + } + int nbTiles=28; + if (columnInTile) + nbTiles=27; + + for (int i=0;i>9)&0x0f)<<2]; + + if ((tileInfo>>9)&0x04) + { + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + } + else + { + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + } + + } + + // render the last clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_bgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *ws_paletteAlias=&ws_palette[((tileInfo>>9)&0x0f)<<2]; + + + if ((tileInfo>>9)&0x04) + { + for (int i=0;iws_ioRam[0x05];i--) + { + uint32 spr=*ws_sprRamBase--; + + if (!(spr&0x2000)) + { + // sprite window on ? + if ((ws_ioRam[0x00]&0x08)&&(spr&0x1000)&&(ws_sprWindow_x0!=ws_sprWindow_x1)) + { + ws_drawClippedSpriteLine(framebuffer,ws_gpu_scanline,(spr&0xff000000)>>24, (spr&0x00ff0000)>>16, + spr&0x1ff,8+((spr&0xe00)>>9),spr&0x4000,spr&0x8000, + ws_sprWindow_x0,ws_sprWindow_y0,ws_sprWindow_x1,ws_sprWindow_y1); + } + else + { + ws_drawClippedSpriteLine(framebuffer,ws_gpu_scanline,(spr&0xff000000)>>24, (spr&0x00ff0000)>>16, + spr&0x1ff,8+((spr&0xe00)>>9),spr&0x4000,spr&0x8000, + //0,0,224,144); + 0,0,224,0); + } + } + } + } +#ifdef STATISTICS + ws_priority_0_sprites_rendering_time=ticker(); +#endif + // render foreground layer + if (ws_ioRam[0x00]&0x02) + { + int ws_fgWindow_x0=ws_ioRam[0x08]; + int ws_fgWindow_y0=ws_ioRam[0x09]; + int ws_fgWindow_x1=ws_ioRam[0x0a]; + int ws_fgWindow_y1=ws_ioRam[0x0b]; + int ws_fgScroll_x=ws_ioRam[0x12]; + int ws_fgScroll_y=ws_ioRam[0x13]; + + int windowMode=ws_ioRam[0x00]&0x30; + + // seek to the first tile + ws_fgScroll_y=(ws_fgScroll_y+ws_gpu_scanline)&0xff; + + // note: byte ordering assumptions! + int ws_currentTile=(ws_fgScroll_x>>3); + uint16 *ws_fgScrollRamBase=(uint16*)(internalRam+(((uint32)ws_ioRam[0x07]&0xf0)<<7)+ + ((ws_fgScroll_y&0xfff8)<<3)); + + int lineInTile = ws_fgScroll_y&0x07; + int columnInTile = ws_fgScroll_x&0x07; + + int16 *scanlinePtr=framebuffer; + + + // window disabled + if (!windowMode) + { + if (ws_gpu_operatingInColor) + { + // render the first clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_fgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *wsc_paletteAlias=&wsc_palette[((tileInfo>>9)&0x0f)<<4]; + + ws_tileRow+=columnInTile; + + for (int i=columnInTile;i<8;i++) + { + if (*ws_tileRow) + *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; + scanlinePtr++; + ws_tileRow++; + } + } + + // render the tiles between them + int nbTiles=28; + if (columnInTile) + nbTiles=27; + + for (int i=0;i>9)&0x0f)<<4]; + + + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + } + + // render the last clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_fgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *wsc_paletteAlias=&wsc_palette[((tileInfo>>9)&0x0f)<<4]; + + + for (int i=0;i>9)&0x0f)<<2]; + ws_tileRow+=columnInTile; + if ((tileInfo>>9)&0x04) + { + for (int i=columnInTile;i<8;i++) + { + if (*ws_tileRow) + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; + scanlinePtr++; + ws_tileRow++; + } + } + else + { + for (int i=columnInTile;i<8;i++) + { + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; + scanlinePtr++; + ws_tileRow++; + } + } + } + int nbTiles=28; + if (columnInTile) + nbTiles=27; + + for (int i=0;i>9)&0x0f)<<2]; + + if ((tileInfo>>9)&0x04) + { + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + } + else + { + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + } + } + + // render the last clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_fgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *ws_paletteAlias=&ws_palette[((tileInfo>>9)&0x0f)<<2]; + + + if ((tileInfo>>9)&0x04) + { + for (int i=0;i>9)&0x0f)<<4]; + + ws_tileRow+=columnInTile; + + for (int i=columnInTile;i<8;i++) + { + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) + *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; + column++; + scanlinePtr++; + ws_tileRow++; + } + } + + // render the tiles between them + int nbTiles=28; + if (columnInTile) + nbTiles=27; + + for (int i=0;i>9)&0x0f)<<4]; + + + + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + } + + // render the last clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_fgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *wsc_paletteAlias=&wsc_palette[((tileInfo>>9)&0x0f)<<4]; + + + for (int i=0;i=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) + *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; + column++; + scanlinePtr++; + ws_tileRow++; + } + } + } + else + { + // render the first clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_fgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + + int16 *ws_paletteAlias=&ws_palette[((tileInfo>>9)&0x0f)<<2]; + ws_tileRow+=columnInTile; + + for (int i=columnInTile;i<8;i++) + { + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; + column++; + scanlinePtr++; + ws_tileRow++; + } + } + int nbTiles=28; + if (columnInTile) + nbTiles=27; + + for (int i=0;i>9)&0x0f)<<2]; + + + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + } + + // render the last clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_fgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *ws_paletteAlias=&ws_palette[((tileInfo>>9)&0x0f)<<2]; + + + for (int i=0;i=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; + column++; + scanlinePtr++; + ws_tileRow++; + } + } + } + } + else + // foreground layer displayed only outside the window + if (windowMode==0x30) + { + int column=0; + if (ws_gpu_operatingInColor) + { + // render the first clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_fgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *wsc_paletteAlias=&wsc_palette[((tileInfo>>9)&0x0f)<<4]; + + ws_tileRow+=columnInTile; + + for (int i=columnInTile;i<8;i++) + { + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) + *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; + column++; + scanlinePtr++; + ws_tileRow++; + } + } + + // render the tiles between them + int nbTiles=28; + if (columnInTile) + nbTiles=27; + + for (int i=0;i>9)&0x0f)<<4]; + + + + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + } + + // render the last clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_fgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *wsc_paletteAlias=&wsc_palette[((tileInfo>>9)&0x0f)<<4]; + + + for (int i=0;iws_fgWindow_x1))) + *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; + column++; + scanlinePtr++; + ws_tileRow++; + } + } + } + else + { + // render the first clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_fgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + + int16 *ws_paletteAlias=&ws_palette[((tileInfo>>9)&0x0f)<<2]; + ws_tileRow+=columnInTile; + + for (int i=columnInTile;i<8;i++) + { + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; + column++; + scanlinePtr++; + ws_tileRow++; + } + } + int nbTiles=28; + if (columnInTile) + nbTiles=27; + + for (int i=0;i>9)&0x0f)<<2]; + + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + } + + // render the last clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_fgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *ws_paletteAlias=&ws_palette[((tileInfo>>9)&0x0f)<<2]; + + + for (int i=0;iws_fgWindow_x1))) + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; + column++; + scanlinePtr++; + ws_tileRow++; + } + } + } + } + else + { + // unknown + } + } +#ifdef STATISTICS + ws_foreground_rendering_time=ticker(); +#endif + // render sprites + if (ws_ioRam[0x00]&0x04) + { + int ws_sprWindow_x0=ws_ioRam[0x0c]; + int ws_sprWindow_y0=ws_ioRam[0x0d]; + int ws_sprWindow_x1=ws_ioRam[0x0e]; + int ws_sprWindow_y1=ws_ioRam[0x0f]; +// int ws_sprWindow_x1=ws_sprWindow_x0+ws_ioRam[0x0e]; +// int ws_sprWindow_y1=ws_sprWindow_y0+ws_ioRam[0x0f]; + uint32 *ws_sprRamBase=(uint32*)(internalRam+(((uint32)ws_ioRam[0x04])<<9)); + + // seek to first sprite + ws_sprRamBase+=ws_ioRam[0x06]-1; + + for (int i=ws_ioRam[0x06];i>ws_ioRam[0x05];i--) + { + uint32 spr=*ws_sprRamBase--; + + if (spr&0x2000) + { + // sprite window on ? + if ((ws_ioRam[0x00]&0x08)&&(spr&0x1000)&&(ws_sprWindow_x0!=ws_sprWindow_x1)) + { + ws_drawClippedSpriteLine(framebuffer,ws_gpu_scanline,(spr&0xff000000)>>24, (spr&0x00ff0000)>>16, + spr&0x1ff,8+((spr&0xe00)>>9),spr&0x4000,spr&0x8000, + ws_sprWindow_x0,ws_sprWindow_y0,ws_sprWindow_x1,ws_sprWindow_y1); + } + else + { + ws_drawClippedSpriteLine(framebuffer,ws_gpu_scanline,(spr&0xff000000)>>24, (spr&0x00ff0000)>>16, + spr&0x1ff,8+((spr&0xe00)>>9),spr&0x4000,spr&0x8000, + // 0,0,224,144); + 0,0,224,0); + } + } + } + } +#ifdef STATISTICS + ws_priority_1_sprites_rendering_time=ticker(); + + ws_priority_1_sprites_rendering_time-=ws_foreground_rendering_time; + ws_foreground_rendering_time-=ws_priority_0_sprites_rendering_time; + ws_priority_0_sprites_rendering_time-=ws_background_rendering_time; + ws_background_rendering_time-=ws_background_color_rendering_time; + ws_background_color_rendering_time-=startTime; +#endif +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_gpu_write_byte(DWORD offset, BYTE value) +{ + // ws 4 color tiles + if ((offset>=0x2000)&&(offset<0x4000)) + { + if (internalRam[offset]!=value) + ws_modified_tile[(offset&0x1fff)>>4]=1; + // update the ram + internalRam[offset]=value; + } + if (ws_gpu_operatingInColor) + { + // wsc 16 color tiles bank 0 + if ((offset>=0x4000)&&(offset<0x8000)) + { + if (internalRam[offset]!=value) + wsc_modified_tile[(offset&0x3fff)>>5]=1; + } + else + // wsc 16 color tiles bank 1 + if ((offset>=0x8000)&&(offset<0xC000)) + { + if (internalRam[offset]!=value) + wsc_modified_tile[512+((offset&0x3fff)>>5)]=1; + } + + // update the ram + internalRam[offset]=value; + // palette ram + if (offset>=0xfe00) + { + // RGB444 format + uint16 color=(internalRam[(offset&0xfffe)+1]); + color<<=8; + color|=(internalRam[(offset&0xfffe)]); + + wsc_palette[(offset&0x1ff)>>1]=RGB555(((color>>8)&0x0f)<<1,((color>>4)&0x0f)<<1,(color&0x0f)<<1); + } + } + else + if (offset<0x4000) + internalRam[offset]=value; +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +unsigned int ws_gpu_unknownPort; +int ws_gpu_port_write(DWORD port,BYTE value) +{ + ws_gpu_unknownPort=0; + switch (port) + { + case 0x60: ws_gpu_changeVideoMode(value); + return 0; + case 0x1C: ws_paletteColors[0]=value&0xf; + ws_paletteColors[1]=(value>>4)&0xf; + return 0; + case 0x1D: ws_paletteColors[2]=value&0xf; + ws_paletteColors[3]=(value>>4)&0xf; + return 0; + case 0x1E: ws_paletteColors[4]=value&0xf; + ws_paletteColors[5]=(value>>4)&0xf; + return 0; + case 0x1F: ws_paletteColors[6]=value&0xf; + ws_paletteColors[7]=(value>>4)&0xf; + return 0; + default: ws_gpu_unknownPort=1; + } + if ((port>=0x20)&&(port<=0x3f)) + { + ws_gpu_unknownPort=0; + port-=0x20; + int paletteIndex=port>>1; + if (port&0x01) + { + ws_palette[(paletteIndex<<2)+2]=value&0x7; + ws_palette[(paletteIndex<<2)+3]=(value>>4)&0x7; + } + else + { + ws_palette[(paletteIndex<<2)+0]=value&0x7; + ws_palette[(paletteIndex<<2)+1]=(value>>4)&0x7; + } + } + return ws_gpu_unknownPort; +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +BYTE ws_gpu_port_read(BYTE port) +{ + switch(port) + { + case 0xa0: + if (ws_gpu_forceColorSystemBool) + return ws_ioRam[0xa0]|2; + else + if (ws_gpu_forceMonoSystemBool) + return ws_ioRam[0xa0]&(~0x02); + else + { + if (ws_gpu_operatingInColor) + return ws_ioRam[0xa0]|2; + else + return ws_ioRam[0xa0]&(~0x02); + } + break; + case 0xaa: + return vblank_count&0xff; + case 0xab: + return (vblank_count>>8)&0xff; + case 0xac: + return (vblank_count>>16)&0xff; + case 0xad: + return (vblank_count>>24)&0xff; + } + return(ws_ioRam[port]); +} diff --git a/oswan/source/gpu.cpp.orig b/oswan/source/gpu.cpp.orig new file mode 100644 index 0000000..41c2360 --- /dev/null +++ b/oswan/source/gpu.cpp.orig @@ -0,0 +1,1580 @@ +//////////////////////////////////////////////////////////////////////////////// +// GPU +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// 7.04.2002: Fixed sprites order +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// + +//#define STATISTICS + +#include +#include +#include +#include +#include +#include +#include "log.h" +#include "rom.h" +#include "./nec/nec.h" +#include "io.h" +#include "gpu.h" + +#ifdef STATISTICS + #include "ticker.h" +#endif +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +extern uint8 *internalRam; + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +#ifdef STATISTICS + long ws_4_shades_tiles_cache_update_time=0; + long ws_4_colors_tiles_cache_update_time=0; + long ws_16_colors_packed_tiles_cache_update_time=0; + long ws_16_colors_layered_tiles_cache_update_time=0; + + long ws_4_shades_tiles_cache_update_number=0; + long ws_4_colors_tiles_cache_update_number=0; + long ws_16_colors_packed_tiles_cache_update_number=0; + long ws_16_colors_layered_tiles_cache_update_number=0; + + long ws_background_color_rendering_time=0; + long ws_background_rendering_time=0; + long ws_foreground_rendering_time=0; + long ws_priority_0_sprites_rendering_time=0; + long ws_priority_1_sprites_rendering_time=0; +#endif +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +#define RGB555(R,G,B) ((((int)(R))<<10)|(((int)(G))<<5)|((int)(B))) + +uint8 ws_gpu_operatingInColor; +uint8 ws_videoMode; +uint8 ws_gpu_scanline=0; +int16 ws_palette[16*4]; +int8 ws_paletteColors[8]; +int16 wsc_palette[16*16]; +int16 ws_shades[16]; +int ws_gpu_forceColorSystemBool=0; +int ws_gpu_forceMonoSystemBool=0; + + + +// white +#define SHADE_COLOR_RED 1.00 +#define SHADE_COLOR_GREEN 1.00 +#define SHADE_COLOR_BLUE 1.00 + +int16 ws_colour_scheme_default[16]={ + RGB555(SHADE_COLOR_RED*30,SHADE_COLOR_GREEN*30,SHADE_COLOR_BLUE*30), + RGB555(SHADE_COLOR_RED*28,SHADE_COLOR_GREEN*28,SHADE_COLOR_BLUE*28), + RGB555(SHADE_COLOR_RED*26,SHADE_COLOR_GREEN*26,SHADE_COLOR_BLUE*26), + RGB555(SHADE_COLOR_RED*24,SHADE_COLOR_GREEN*24,SHADE_COLOR_BLUE*24), + RGB555(SHADE_COLOR_RED*22,SHADE_COLOR_GREEN*22,SHADE_COLOR_BLUE*22), + RGB555(SHADE_COLOR_RED*20,SHADE_COLOR_GREEN*20,SHADE_COLOR_BLUE*20), + RGB555(SHADE_COLOR_RED*18,SHADE_COLOR_GREEN*18,SHADE_COLOR_BLUE*18), + RGB555(SHADE_COLOR_RED*16,SHADE_COLOR_GREEN*16,SHADE_COLOR_BLUE*16), + RGB555(SHADE_COLOR_RED*14,SHADE_COLOR_GREEN*14,SHADE_COLOR_BLUE*14), + RGB555(SHADE_COLOR_RED*12,SHADE_COLOR_GREEN*12,SHADE_COLOR_BLUE*12), + RGB555(SHADE_COLOR_RED*10,SHADE_COLOR_GREEN*10,SHADE_COLOR_BLUE*10), + RGB555(SHADE_COLOR_RED*8,SHADE_COLOR_GREEN*8,SHADE_COLOR_BLUE*8), + RGB555(SHADE_COLOR_RED*6,SHADE_COLOR_GREEN*6,SHADE_COLOR_BLUE*6), + RGB555(SHADE_COLOR_RED*4,SHADE_COLOR_GREEN*4,SHADE_COLOR_BLUE*4), + RGB555(SHADE_COLOR_RED*2,SHADE_COLOR_GREEN*2,SHADE_COLOR_BLUE*2), + RGB555(SHADE_COLOR_RED*0,SHADE_COLOR_GREEN*0,SHADE_COLOR_BLUE*0) + }; +// green +#undef SHADE_COLOR_RED +#undef SHADE_COLOR_GREEN +#undef SHADE_COLOR_BLUE +#define SHADE_COLOR_RED 0.20 +#define SHADE_COLOR_GREEN 0.90 +#define SHADE_COLOR_BLUE 0.20 + +int16 ws_colour_scheme_green[16]={ + RGB555(SHADE_COLOR_RED*30,SHADE_COLOR_GREEN*30,SHADE_COLOR_BLUE*30), + RGB555(SHADE_COLOR_RED*28,SHADE_COLOR_GREEN*28,SHADE_COLOR_BLUE*28), + RGB555(SHADE_COLOR_RED*26,SHADE_COLOR_GREEN*26,SHADE_COLOR_BLUE*26), + RGB555(SHADE_COLOR_RED*24,SHADE_COLOR_GREEN*24,SHADE_COLOR_BLUE*24), + RGB555(SHADE_COLOR_RED*22,SHADE_COLOR_GREEN*22,SHADE_COLOR_BLUE*22), + RGB555(SHADE_COLOR_RED*20,SHADE_COLOR_GREEN*20,SHADE_COLOR_BLUE*20), + RGB555(SHADE_COLOR_RED*18,SHADE_COLOR_GREEN*18,SHADE_COLOR_BLUE*18), + RGB555(SHADE_COLOR_RED*16,SHADE_COLOR_GREEN*16,SHADE_COLOR_BLUE*16), + RGB555(SHADE_COLOR_RED*14,SHADE_COLOR_GREEN*14,SHADE_COLOR_BLUE*14), + RGB555(SHADE_COLOR_RED*12,SHADE_COLOR_GREEN*12,SHADE_COLOR_BLUE*12), + RGB555(SHADE_COLOR_RED*10,SHADE_COLOR_GREEN*10,SHADE_COLOR_BLUE*10), + RGB555(SHADE_COLOR_RED*8,SHADE_COLOR_GREEN*8,SHADE_COLOR_BLUE*8), + RGB555(SHADE_COLOR_RED*6,SHADE_COLOR_GREEN*6,SHADE_COLOR_BLUE*6), + RGB555(SHADE_COLOR_RED*4,SHADE_COLOR_GREEN*4,SHADE_COLOR_BLUE*4), + RGB555(SHADE_COLOR_RED*2,SHADE_COLOR_GREEN*2,SHADE_COLOR_BLUE*2), + RGB555(SHADE_COLOR_RED*0,SHADE_COLOR_GREEN*0,SHADE_COLOR_BLUE*0) + }; +// amber +#undef SHADE_COLOR_RED +#undef SHADE_COLOR_GREEN +#undef SHADE_COLOR_BLUE +#define SHADE_COLOR_RED 1.00 +#define SHADE_COLOR_GREEN 0.61 +#define SHADE_COLOR_BLUE 0.00 + +int16 ws_colour_scheme_amber[16]={ + RGB555(SHADE_COLOR_RED*30,SHADE_COLOR_GREEN*30,SHADE_COLOR_BLUE*30), + RGB555(SHADE_COLOR_RED*28,SHADE_COLOR_GREEN*28,SHADE_COLOR_BLUE*28), + RGB555(SHADE_COLOR_RED*26,SHADE_COLOR_GREEN*26,SHADE_COLOR_BLUE*26), + RGB555(SHADE_COLOR_RED*24,SHADE_COLOR_GREEN*24,SHADE_COLOR_BLUE*24), + RGB555(SHADE_COLOR_RED*22,SHADE_COLOR_GREEN*22,SHADE_COLOR_BLUE*22), + RGB555(SHADE_COLOR_RED*20,SHADE_COLOR_GREEN*20,SHADE_COLOR_BLUE*20), + RGB555(SHADE_COLOR_RED*18,SHADE_COLOR_GREEN*18,SHADE_COLOR_BLUE*18), + RGB555(SHADE_COLOR_RED*16,SHADE_COLOR_GREEN*16,SHADE_COLOR_BLUE*16), + RGB555(SHADE_COLOR_RED*14,SHADE_COLOR_GREEN*14,SHADE_COLOR_BLUE*14), + RGB555(SHADE_COLOR_RED*12,SHADE_COLOR_GREEN*12,SHADE_COLOR_BLUE*12), + RGB555(SHADE_COLOR_RED*10,SHADE_COLOR_GREEN*10,SHADE_COLOR_BLUE*10), + RGB555(SHADE_COLOR_RED*8,SHADE_COLOR_GREEN*8,SHADE_COLOR_BLUE*8), + RGB555(SHADE_COLOR_RED*6,SHADE_COLOR_GREEN*6,SHADE_COLOR_BLUE*6), + RGB555(SHADE_COLOR_RED*4,SHADE_COLOR_GREEN*4,SHADE_COLOR_BLUE*4), + RGB555(SHADE_COLOR_RED*2,SHADE_COLOR_GREEN*2,SHADE_COLOR_BLUE*2), + RGB555(SHADE_COLOR_RED*0,SHADE_COLOR_GREEN*0,SHADE_COLOR_BLUE*0) + }; + +uint8 *ws_tile_cache; +uint8 *ws_hflipped_tile_cache; + +uint8 *wsc_tile_cache; +uint8 *wsc_hflipped_tile_cache; + +uint8 *ws_modified_tile; +uint8 *wsc_modified_tile; + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_gpu_set_colour_scheme(int scheme) +{ + switch (scheme) + { + case COLOUR_SCHEME_DEFAULT: memcpy(ws_shades,ws_colour_scheme_default,16*sizeof(int16)); break; + case COLOUR_SCHEME_AMBER : memcpy(ws_shades,ws_colour_scheme_amber,16*sizeof(int16)); break; + case COLOUR_SCHEME_GREEN : memcpy(ws_shades,ws_colour_scheme_green,16*sizeof(int16)); break; + } +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_gpu_forceColorSystem(void) +{ + ws_gpu_forceColorSystemBool=1; + ws_gpu_forceMonoSystemBool=0; + ws_gpu_operatingInColor=1; +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_gpu_forceMonoSystem(void) +{ + ws_gpu_forceColorSystemBool=0; + ws_gpu_forceMonoSystemBool=1; + ws_gpu_operatingInColor=0; +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_gpu_init(void) +{ + ws_tile_cache = (uint8*)malloc(512*8*8); + wsc_tile_cache = (uint8*)malloc(1024*8*8); + + ws_hflipped_tile_cache = (uint8*)malloc(512*8*8); + wsc_hflipped_tile_cache = (uint8*)malloc(1024*8*8); + + ws_modified_tile = (uint8*)malloc(512); + wsc_modified_tile = (uint8*)malloc(1024); + + memset(ws_tile_cache,0x00,512*8*8); + memset(wsc_tile_cache,0x00,1024*8*8); + + memset(ws_hflipped_tile_cache,0x00,512*8*8); + memset(wsc_hflipped_tile_cache,0x00,1024*8*8); + + memset(ws_modified_tile,0x01,512); + memset(wsc_modified_tile,0x01,1024); + + ws_gpu_forceColorSystemBool=0; + ws_gpu_forceMonoSystemBool=0; +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_gpu_done(void) +{ + free(ws_tile_cache); + free(wsc_tile_cache); + free(ws_hflipped_tile_cache); + free(wsc_hflipped_tile_cache); + free(ws_modified_tile); + free(wsc_modified_tile); +#ifdef STATISTICS + printf("Statistics:\n"); + printf("\tcache:\n"); + if (ws_4_shades_tiles_cache_update_number) + printf("\t\t4 shades tiles update time : %i\n",ws_4_shades_tiles_cache_update_time/ws_4_shades_tiles_cache_update_number); + if (ws_4_colors_tiles_cache_update_number) + printf("\t\t4 colors tiles update time : %i\n",ws_4_colors_tiles_cache_update_time/ws_4_colors_tiles_cache_update_number); + if (ws_16_colors_packed_tiles_cache_update_number) + printf("\t\t16 colors packed tiles update time : %i\n",ws_16_colors_packed_tiles_cache_update_time/ws_16_colors_packed_tiles_cache_update_number); + if (ws_16_colors_layered_tiles_cache_update_number) + printf("\t\t16 colors layered tiles update time: %i\n",ws_16_colors_layered_tiles_cache_update_time/ws_16_colors_layered_tiles_cache_update_number); + + printf("\tscanline rendering:\n"); + long total= ws_background_color_rendering_time+ws_background_rendering_time+ + ws_foreground_rendering_time+ws_priority_0_sprites_rendering_time+ + ws_priority_1_sprites_rendering_time; + printf("\t\tbackground color : %4i (%3i %%)\n",ws_background_color_rendering_time,(ws_background_color_rendering_time*100)/total); + printf("\t\tbackground : %4i (%3i %%)\n",ws_background_rendering_time,(ws_background_rendering_time*100)/total); + printf("\t\tforeground : %4i (%3i %%)\n",ws_foreground_rendering_time,(ws_foreground_rendering_time*100)/total); + printf("\t\tpriority 0 sprites : %4i (%3i %%)\n",ws_priority_0_sprites_rendering_time,(ws_priority_0_sprites_rendering_time*100)/total); + printf("\t\tpriority 1 sprites : %4i (%3i %%)\n",ws_priority_1_sprites_rendering_time,(ws_priority_1_sprites_rendering_time*100)/total); +#endif +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_gpu_changeVideoMode(uint8 value) +{ + if (ws_videoMode!=(value>>5)) + { + ws_videoMode=value>>5; + if (ws_videoMode==4) + ws_videoMode=2; + + // mark all tiles dirty + memset(wsc_modified_tile,0x01,1024); + memset(ws_modified_tile,0x01,512); + } +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_gpu_reset(void) +{ + memset(wsc_modified_tile,0x01,1024); + memset(ws_modified_tile,0x01,512); + ws_gpu_scanline=0; + ws_gpu_changeVideoMode(2); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_gpu_clearCache(void) +{ + memset(wsc_modified_tile,0x01,1024); + memset(ws_modified_tile,0x01,512); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +uint8 *ws_tileCache_getTileRow(uint32 tileIndex, uint32 line, + uint32 vFlip, uint32 hFlip, uint32 bank) +{ + if (ws_gpu_operatingInColor) + { + if (bank) + tileIndex+=512; + + // need to update tile cache ? + // 4 colors tiles + if ((ws_videoMode==2)&&(ws_modified_tile[tileIndex])) + { +#ifdef STATISTICS + ws_4_colors_tiles_cache_update_time+=-ticker(); +#endif + uint8 *tileInCachePtr = &wsc_tile_cache[tileIndex<<6]; + uint8 *hflippedTileInCachePtr = &wsc_hflipped_tile_cache[tileIndex<<6]; + uint16 *tileInRamPtr = (uint16*)&internalRam[0x2000+(tileIndex<<4)]; + uint16 tileLine; + + for (int line=0;line<8;line++) + { + tileLine=*tileInRamPtr++; + + tileInCachePtr[0]=((tileLine&0x80)>>7)|((tileLine&0x8000)>>14); + hflippedTileInCachePtr[7]=tileInCachePtr[0]; + tileInCachePtr[1]=((tileLine&0x40)>>6)|((tileLine&0x4000)>>13); + hflippedTileInCachePtr[6]=tileInCachePtr[1]; + tileInCachePtr[2]=((tileLine&0x20)>>5)|((tileLine&0x2000)>>12); + hflippedTileInCachePtr[5]=tileInCachePtr[2]; + tileInCachePtr[3]=((tileLine&0x10)>>4)|((tileLine&0x1000)>>11); + hflippedTileInCachePtr[4]=tileInCachePtr[3]; + tileInCachePtr[4]=((tileLine&0x08)>>3)|((tileLine&0x0800)>>10); + hflippedTileInCachePtr[3]=tileInCachePtr[4]; + tileInCachePtr[5]=((tileLine&0x04)>>2)|((tileLine&0x0400)>>9); + hflippedTileInCachePtr[2]=tileInCachePtr[5]; + tileInCachePtr[6]=((tileLine&0x02)>>1)|((tileLine&0x0200)>>8); + hflippedTileInCachePtr[1]=tileInCachePtr[6]; + tileInCachePtr[7]=((tileLine&0x01)>>0)|((tileLine&0x0100)>>7); + hflippedTileInCachePtr[0]=tileInCachePtr[7]; + + tileInCachePtr+=8; + hflippedTileInCachePtr+=8; + } + ws_modified_tile[tileIndex]=0; +#ifdef STATISTICS + ws_4_colors_tiles_cache_update_time+=ticker(); + ws_4_colors_tiles_cache_update_number++; +#endif + } + else + if (wsc_modified_tile[tileIndex]) + { + // 16 colors by tile layered mode + if (ws_videoMode==6) + { +#ifdef STATISTICS + ws_16_colors_layered_tiles_cache_update_time+=-ticker(); +#endif + uint8 *tileInCachePtr = &wsc_tile_cache[tileIndex<<6]; + uint8 *hflippedTileInCachePtr = &wsc_hflipped_tile_cache[tileIndex<<6]; + uint32 *tileInRamPtr = (uint32*)&internalRam[0x4000+(tileIndex<<5)]; + uint32 tileLine; + + for (int line=0;line<8;line++) + { + tileLine=*tileInRamPtr++; + + tileInCachePtr[0]=((tileLine&0x00000080)>>7)|((tileLine&0x00008000)>>14)| + ((tileLine&0x00800000)>>21)|((tileLine&0x80000000)>>28); + hflippedTileInCachePtr[7]=tileInCachePtr[0]; + + tileInCachePtr[1]=((tileLine&0x00000040)>>6)|((tileLine&0x00004000)>>13)| + ((tileLine&0x00400000)>>20)|((tileLine&0x40000000)>>27); + hflippedTileInCachePtr[6]=tileInCachePtr[1]; + + tileInCachePtr[2]=((tileLine&0x00000020)>>5)|((tileLine&0x00002000)>>12)| + ((tileLine&0x00200000)>>19)|((tileLine&0x20000000)>>26); + hflippedTileInCachePtr[5]=tileInCachePtr[2]; + + tileInCachePtr[3]=((tileLine&0x00000010)>>4)|((tileLine&0x00001000)>>11)| + ((tileLine&0x00100000)>>18)|((tileLine&0x10000000)>>25); + hflippedTileInCachePtr[4]=tileInCachePtr[3]; + + tileInCachePtr[4]=((tileLine&0x00000008)>>3)|((tileLine&0x00000800)>>10)| + ((tileLine&0x00080000)>>17)|((tileLine&0x08000000)>>24); + hflippedTileInCachePtr[3]=tileInCachePtr[4]; + + tileInCachePtr[5]=((tileLine&0x00000004)>>2)|((tileLine&0x00000400)>>9)| + ((tileLine&0x00040000)>>16)|((tileLine&0x04000000)>>23); + hflippedTileInCachePtr[2]=tileInCachePtr[5]; + + tileInCachePtr[6]=((tileLine&0x00000002)>>1)|((tileLine&0x00000200)>>8)| + ((tileLine&0x00020000)>>15)|((tileLine&0x02000000)>>22); + hflippedTileInCachePtr[1]=tileInCachePtr[6]; + + tileInCachePtr[7]=((tileLine&0x00000001)>>0)|((tileLine&0x00000100)>>7)| + ((tileLine&0x00010000)>>14)|((tileLine&0x01000000)>>21); + hflippedTileInCachePtr[0]=tileInCachePtr[7]; + + tileInCachePtr+=8; + hflippedTileInCachePtr+=8; + } +#ifdef STATISTICS + ws_16_colors_layered_tiles_cache_update_time+=ticker(); + ws_16_colors_layered_tiles_cache_update_number++; +#endif + } + else + // 16 colors by tile packed mode + if (ws_videoMode==7) + { +#ifdef STATISTICS + ws_16_colors_packed_tiles_cache_update_time+=-ticker(); +#endif + uint8 *tileInCachePtr = &wsc_tile_cache[tileIndex<<6]; + uint8 *hflippedTileInCachePtr = &wsc_hflipped_tile_cache[tileIndex<<6]; + uint32 *tileInRamPtr = (uint32*)&internalRam[0x4000+(tileIndex<<5)]; + uint32 tileLine; + + for (int line=0;line<8;line++) + { + tileLine=*tileInRamPtr++; + + tileInCachePtr[0]=(tileLine>>4)&0x0f; + hflippedTileInCachePtr[7]=tileInCachePtr[0]; + tileInCachePtr[1]=(tileLine>>0)&0x0f; + hflippedTileInCachePtr[6]=tileInCachePtr[1]; + tileInCachePtr[2]=(tileLine>>12)&0x0f; + hflippedTileInCachePtr[5]=tileInCachePtr[2]; + tileInCachePtr[3]=(tileLine>>8)&0x0f; + hflippedTileInCachePtr[4]=tileInCachePtr[3]; + tileInCachePtr[4]=(tileLine>>20)&0x0f; + hflippedTileInCachePtr[3]=tileInCachePtr[4]; + tileInCachePtr[5]=(tileLine>>16)&0x0f; + hflippedTileInCachePtr[2]=tileInCachePtr[5]; + tileInCachePtr[6]=(tileLine>>28)&0x0f; + hflippedTileInCachePtr[1]=tileInCachePtr[6]; + tileInCachePtr[7]=(tileLine>>24)&0x0f; + hflippedTileInCachePtr[0]=tileInCachePtr[7]; + + tileInCachePtr+=8; + hflippedTileInCachePtr+=8; + + } +#ifdef STATISTICS + ws_16_colors_packed_tiles_cache_update_time+=ticker(); + ws_16_colors_packed_tiles_cache_update_number++; +#endif + } + else + { + // unknown mode + } + // tile cache updated + wsc_modified_tile[tileIndex]=0; + } + if (vFlip) + line=7-line; + if (hFlip) + return(&wsc_hflipped_tile_cache[(tileIndex<<6)+(line<<3)]); + else + return(&wsc_tile_cache[(tileIndex<<6)+(line<<3)]); + + } + else + { + // need to update tile cache ? + if (ws_modified_tile[tileIndex]) + { +#ifdef STATISTICS + ws_4_shades_tiles_cache_update_time+=-ticker(); +#endif + uint8 *tileInCachePtr = &ws_tile_cache[tileIndex<<6]; + uint8 *hflippedTileInCachePtr = &ws_hflipped_tile_cache[(tileIndex<<6)+7]; + uint32 *tileInRamPtr = (uint32*)&internalRam[0x2000+(tileIndex<<4)]; + uint32 tileLine; + + for (int line=0;line<4;line++) + { + tileLine=*tileInRamPtr++; + + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x80)>>7)|((tileLine&0x8000)>>14); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x40)>>6)|((tileLine&0x4000)>>13); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x20)>>5)|((tileLine&0x2000)>>12); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x10)>>4)|((tileLine&0x1000)>>11); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x08)>>3)|((tileLine&0x0800)>>10); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x04)>>2)|((tileLine&0x0400)>>9); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x02)>>1)|((tileLine&0x0200)>>8); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x01)>>0)|((tileLine&0x0100)>>7); + hflippedTileInCachePtr+=16; + tileLine>>=16; + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x80)>>7)|((tileLine&0x8000)>>14); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x40)>>6)|((tileLine&0x4000)>>13); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x20)>>5)|((tileLine&0x2000)>>12); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x10)>>4)|((tileLine&0x1000)>>11); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x08)>>3)|((tileLine&0x0800)>>10); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x04)>>2)|((tileLine&0x0400)>>9); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x02)>>1)|((tileLine&0x0200)>>8); + *hflippedTileInCachePtr--=*tileInCachePtr++=((tileLine&0x01)>>0)|((tileLine&0x0100)>>7); + hflippedTileInCachePtr+=16; + } + // tile cache updated + ws_modified_tile[tileIndex]=0; +#ifdef STATISTICS + ws_4_shades_tiles_cache_update_time+=ticker(); + ws_4_shades_tiles_cache_update_number++; +#endif + } + if (vFlip) + line=7-line; + if (hFlip) + return(&ws_hflipped_tile_cache[(tileIndex<<6)+(line<<3)]); + else + return(&ws_tile_cache[(tileIndex<<6)+(line<<3)]); + } + return(NULL); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_drawClippedSpriteLine(int16 *framebuffer, uint16 scanline, + uint32 x, uint32 y, uint32 tileIndex, uint32 paletteIndex, + uint32 vFlip, uint32 hFlip, + uint32 clip_x0, uint32 clip_y0, uint32 clip_x1, uint32 clip_y1) +{ + + if ((scanline(y+7))) + return; + if ((x+7=clip_x1)) + return; + if ((y+7=clip_y1)) + return; + + uint8 *ws_tileRow=ws_tileCache_getTileRow(tileIndex,(scanline-y)&0x07,hFlip,vFlip, 0); + uint16 nbPixels=8; + if (xclip_x1) + nbPixels=(clip_x1-x); + framebuffer+=x; + + if (ws_gpu_operatingInColor) + { + int16 *wsc_paletteAlias=&wsc_palette[paletteIndex<<4]; + while (nbPixels) + { + if (*ws_tileRow) *framebuffer=wsc_paletteAlias[*ws_tileRow]; + framebuffer++; ws_tileRow++; + nbPixels--; + } + } + else + { + int16 *ws_paletteAlias=&ws_palette[paletteIndex<<2]; + if (paletteIndex&0x04) + { + while (nbPixels) + { + if (*ws_tileRow) *framebuffer=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; + framebuffer++; ws_tileRow++; + nbPixels--; + } + } + else + { + while (nbPixels) + { + *framebuffer=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; + framebuffer++; ws_tileRow++; + nbPixels--; + } + } + } +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_gpu_renderScanline(int16 *framebuffer) +{ + + if (ws_gpu_scanline>143) + return; +#ifdef STATISTICS + long startTime=ticker(); +#endif + framebuffer+=(224*ws_gpu_scanline); + + // fill with background color + int16 backgroundColor; + if (ws_gpu_operatingInColor) + backgroundColor=wsc_palette[ws_ioRam[0x01]]; + else + backgroundColor=ws_shades[ws_paletteColors[ws_palette[((ws_ioRam[0x01]&0xf0)>>2)+(ws_ioRam[0x01]&0x03)]]]; + + for (int i=0;i<224;i++) + framebuffer[i]=backgroundColor; +#ifdef STATISTICS + ws_background_color_rendering_time=ticker(); +#endif + // render background layer + if (ws_ioRam[0x00]&0x01) + { + int ws_bgScroll_x=ws_ioRam[0x10]; + int ws_bgScroll_y=ws_ioRam[0x11]; + + // seek to the first tile + ws_bgScroll_y=(ws_bgScroll_y+ws_gpu_scanline)&0xff; + + // note: byte ordering assumptions! + int ws_currentTile=(ws_bgScroll_x>>3); + uint16 *ws_bgScrollRamBase=(uint16*)(internalRam+(((uint32)ws_ioRam[0x07]&0x0f)<<11)+ + ((ws_bgScroll_y&0xfff8)<<3)); + + int lineInTile = ws_bgScroll_y&0x07; + int columnInTile = ws_bgScroll_x&0x07; + + int16 *scanlinePtr=framebuffer; + + if (ws_gpu_operatingInColor) + { + // render the first clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_bgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *wsc_paletteAlias=&wsc_palette[((tileInfo>>9)&0x0f)<<4]; + ws_tileRow+=columnInTile; + for (int i=columnInTile;i<8;i++) + { + if (*ws_tileRow) + *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; + scanlinePtr++; + ws_tileRow++; + } + } + + // render the tiles between them + int nbTiles=28; + if (columnInTile) + nbTiles=27; + + for (int i=0;i>9)&0x0f)<<4]; + + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + } + + // render the last clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_bgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *wsc_paletteAlias=&wsc_palette[((tileInfo>>9)&0x0f)<<4]; + + + for (int i=0;i>9)&0x0f)<<2]; + ws_tileRow+=columnInTile; + + if ((tileInfo>>9)&0x04) + { + for (int i=columnInTile;i<8;i++) + { + if (*ws_tileRow) + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; + scanlinePtr++; + ws_tileRow++; + } + } + else + { + for (int i=columnInTile;i<8;i++) + { + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; + scanlinePtr++; + ws_tileRow++; + } + } + } + int nbTiles=28; + if (columnInTile) + nbTiles=27; + + for (int i=0;i>9)&0x0f)<<2]; + + if ((tileInfo>>9)&0x04) + { + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + } + else + { + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + } + + } + + // render the last clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_bgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *ws_paletteAlias=&ws_palette[((tileInfo>>9)&0x0f)<<2]; + + + if ((tileInfo>>9)&0x04) + { + for (int i=0;iws_ioRam[0x05];i--) + { + uint32 spr=*ws_sprRamBase--; + + if (!(spr&0x2000)) + { + // sprite window on ? + if ((ws_ioRam[0x00]&0x08)&&(spr&0x1000)&&(ws_sprWindow_x0!=ws_sprWindow_x1)) + { + ws_drawClippedSpriteLine(framebuffer,ws_gpu_scanline,(spr&0xff000000)>>24, (spr&0x00ff0000)>>16, + spr&0x1ff,8+((spr&0xe00)>>9),spr&0x4000,spr&0x8000, + ws_sprWindow_x0,ws_sprWindow_y0,ws_sprWindow_x1,ws_sprWindow_y1); + } + else + { + ws_drawClippedSpriteLine(framebuffer,ws_gpu_scanline,(spr&0xff000000)>>24, (spr&0x00ff0000)>>16, + spr&0x1ff,8+((spr&0xe00)>>9),spr&0x4000,spr&0x8000, + 0,0,224,144); + } + } + } + } +#ifdef STATISTICS + ws_priority_0_sprites_rendering_time=ticker(); +#endif + // render foreground layer + if (ws_ioRam[0x00]&0x02) + { + int ws_fgWindow_x0=ws_ioRam[0x08]; + int ws_fgWindow_y0=ws_ioRam[0x09]; + int ws_fgWindow_x1=ws_ioRam[0x0a]; + int ws_fgWindow_y1=ws_ioRam[0x0b]; + int ws_fgScroll_x=ws_ioRam[0x12]; + int ws_fgScroll_y=ws_ioRam[0x13]; + + int windowMode=ws_ioRam[0x00]&0x30; + + // seek to the first tile + ws_fgScroll_y=(ws_fgScroll_y+ws_gpu_scanline)&0xff; + + // note: byte ordering assumptions! + int ws_currentTile=(ws_fgScroll_x>>3); + uint16 *ws_fgScrollRamBase=(uint16*)(internalRam+(((uint32)ws_ioRam[0x07]&0xf0)<<7)+ + ((ws_fgScroll_y&0xfff8)<<3)); + + int lineInTile = ws_fgScroll_y&0x07; + int columnInTile = ws_fgScroll_x&0x07; + + int16 *scanlinePtr=framebuffer; + + + // window disabled + if (!windowMode) + { + if (ws_gpu_operatingInColor) + { + // render the first clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_fgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *wsc_paletteAlias=&wsc_palette[((tileInfo>>9)&0x0f)<<4]; + + ws_tileRow+=columnInTile; + + for (int i=columnInTile;i<8;i++) + { + if (*ws_tileRow) + *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; + scanlinePtr++; + ws_tileRow++; + } + } + + // render the tiles between them + int nbTiles=28; + if (columnInTile) + nbTiles=27; + + for (int i=0;i>9)&0x0f)<<4]; + + + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; + } + + // render the last clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_fgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *wsc_paletteAlias=&wsc_palette[((tileInfo>>9)&0x0f)<<4]; + + + for (int i=0;i>9)&0x0f)<<2]; + ws_tileRow+=columnInTile; + if ((tileInfo>>9)&0x04) + { + for (int i=columnInTile;i<8;i++) + { + if (*ws_tileRow) + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; + scanlinePtr++; + ws_tileRow++; + } + } + else + { + for (int i=columnInTile;i<8;i++) + { + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; + scanlinePtr++; + ws_tileRow++; + } + } + } + int nbTiles=28; + if (columnInTile) + nbTiles=27; + + for (int i=0;i>9)&0x0f)<<2]; + + if ((tileInfo>>9)&0x04) + { + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + if (*ws_tileRow) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + } + else + { + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; + } + } + + // render the last clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_fgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *ws_paletteAlias=&ws_palette[((tileInfo>>9)&0x0f)<<2]; + + + if ((tileInfo>>9)&0x04) + { + for (int i=0;i>9)&0x0f)<<4]; + + ws_tileRow+=columnInTile; + + for (int i=columnInTile;i<8;i++) + { + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) + *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; + column++; + scanlinePtr++; + ws_tileRow++; + } + } + + // render the tiles between them + int nbTiles=28; + if (columnInTile) + nbTiles=27; + + for (int i=0;i>9)&0x0f)<<4]; + + + + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + } + + // render the last clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_fgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *wsc_paletteAlias=&wsc_palette[((tileInfo>>9)&0x0f)<<4]; + + + for (int i=0;i=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) + *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; + column++; + scanlinePtr++; + ws_tileRow++; + } + } + } + else + { + // render the first clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_fgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + + int16 *ws_paletteAlias=&ws_palette[((tileInfo>>9)&0x0f)<<2]; + ws_tileRow+=columnInTile; + + for (int i=columnInTile;i<8;i++) + { + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; + column++; + scanlinePtr++; + ws_tileRow++; + } + } + int nbTiles=28; + if (columnInTile) + nbTiles=27; + + for (int i=0;i>9)&0x0f)<<2]; + + + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&(column>=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + } + + // render the last clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_fgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *ws_paletteAlias=&ws_palette[((tileInfo>>9)&0x0f)<<2]; + + + for (int i=0;i=ws_fgWindow_x0)&&(column<=ws_fgWindow_x1)) + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; + column++; + scanlinePtr++; + ws_tileRow++; + } + } + } + } + else + // foreground layer displayed only outside the window + if (windowMode==0x30) + { + int column=0; + if (ws_gpu_operatingInColor) + { + // render the first clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_fgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *wsc_paletteAlias=&wsc_palette[((tileInfo>>9)&0x0f)<<4]; + + ws_tileRow+=columnInTile; + + for (int i=columnInTile;i<8;i++) + { + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) + *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; + column++; + scanlinePtr++; + ws_tileRow++; + } + } + + // render the tiles between them + int nbTiles=28; + if (columnInTile) + nbTiles=27; + + for (int i=0;i>9)&0x0f)<<4]; + + + + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; scanlinePtr++; ws_tileRow++; column++; + } + + // render the last clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_fgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *wsc_paletteAlias=&wsc_palette[((tileInfo>>9)&0x0f)<<4]; + + + for (int i=0;iws_fgWindow_x1))) + *scanlinePtr=wsc_paletteAlias[*ws_tileRow]; + column++; + scanlinePtr++; + ws_tileRow++; + } + } + } + else + { + // render the first clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_fgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + + int16 *ws_paletteAlias=&ws_palette[((tileInfo>>9)&0x0f)<<2]; + ws_tileRow+=columnInTile; + + for (int i=columnInTile;i<8;i++) + { + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; + column++; + scanlinePtr++; + ws_tileRow++; + } + } + int nbTiles=28; + if (columnInTile) + nbTiles=27; + + for (int i=0;i>9)&0x0f)<<2]; + + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + if ((*ws_tileRow)&&((columnws_fgWindow_x1))) *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; scanlinePtr++; ws_tileRow++; column++; + } + + // render the last clipped tile + if (columnInTile) + { + uint16 tileInfo=ws_fgScrollRamBase[ws_currentTile&0x1f]; + ws_currentTile++; + uint8 *ws_tileRow=ws_tileCache_getTileRow( tileInfo&0x1ff, lineInTile, + tileInfo&0x8000, tileInfo&0x4000, tileInfo&0x2000); + int16 *ws_paletteAlias=&ws_palette[((tileInfo>>9)&0x0f)<<2]; + + + for (int i=0;iws_fgWindow_x1))) + *scanlinePtr=ws_shades[ws_paletteColors[ws_paletteAlias[*ws_tileRow]]]; + column++; + scanlinePtr++; + ws_tileRow++; + } + } + } + } + else + { + // unknown + } + } +#ifdef STATISTICS + ws_foreground_rendering_time=ticker(); +#endif + // render sprites + if (ws_ioRam[0x00]&0x04) + { + int ws_sprWindow_x0=ws_ioRam[0x0c]; + int ws_sprWindow_y0=ws_ioRam[0x0d]; + int ws_sprWindow_x1=ws_ioRam[0x0e]; + int ws_sprWindow_y1=ws_ioRam[0x0f]; + uint32 *ws_sprRamBase=(uint32*)(internalRam+(((uint32)ws_ioRam[0x04])<<9)); + + // seek to first sprite + ws_sprRamBase+=ws_ioRam[0x06]-1; + + for (int i=ws_ioRam[0x06];i>ws_ioRam[0x05];i--) + { + uint32 spr=*ws_sprRamBase--; + + if (spr&0x2000) + { + // sprite window on ? + if ((ws_ioRam[0x00]&0x08)&&(spr&0x1000)&&(ws_sprWindow_x0!=ws_sprWindow_x1)) + { + ws_drawClippedSpriteLine(framebuffer,ws_gpu_scanline,(spr&0xff000000)>>24, (spr&0x00ff0000)>>16, + spr&0x1ff,8+((spr&0xe00)>>9),spr&0x4000,spr&0x8000, + ws_sprWindow_x0,ws_sprWindow_y0,ws_sprWindow_x1,ws_sprWindow_y1); + } + else + { + ws_drawClippedSpriteLine(framebuffer,ws_gpu_scanline,(spr&0xff000000)>>24, (spr&0x00ff0000)>>16, + spr&0x1ff,8+((spr&0xe00)>>9),spr&0x4000,spr&0x8000, + 0,0,224,144); + } + } + } + } +#ifdef STATISTICS + ws_priority_1_sprites_rendering_time=ticker(); + + ws_priority_1_sprites_rendering_time-=ws_foreground_rendering_time; + ws_foreground_rendering_time-=ws_priority_0_sprites_rendering_time; + ws_priority_0_sprites_rendering_time-=ws_background_rendering_time; + ws_background_rendering_time-=ws_background_color_rendering_time; + ws_background_color_rendering_time-=startTime; +#endif +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_gpu_write_byte(DWORD offset, BYTE value) +{ + // ws 4 color tiles + if ((offset>=0x2000)&&(offset<0x4000)) + { + if (internalRam[offset]!=value) + ws_modified_tile[(offset&0x1fff)>>4]=1; + // update the ram + internalRam[offset]=value; + } + if (ws_gpu_operatingInColor) + { + // wsc 16 color tiles bank 0 + if ((offset>=0x4000)&&(offset<0x8000)) + { + if (internalRam[offset]!=value) + wsc_modified_tile[(offset&0x3fff)>>5]=1; + } + else + // wsc 16 color tiles bank 1 + if ((offset>=0x8000)&&(offset<0xC000)) + { + if (internalRam[offset]!=value) + wsc_modified_tile[512+((offset&0x3fff)>>5)]=1; + } + + // update the ram + internalRam[offset]=value; + // palette ram + if (offset>=0xfe00) + { + // RGB444 format + uint16 color=(internalRam[(offset&0xfffe)+1]); + color<<=8; + color|=(internalRam[(offset&0xfffe)]); + + wsc_palette[(offset&0x1ff)>>1]=RGB555(((color>>8)&0x0f)<<1,((color>>4)&0x0f)<<1,(color&0x0f)<<1); + } + } + else + if (offset<0x4000) + internalRam[offset]=value; +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +unsigned int ws_gpu_unknownPort; +void ws_gpu_port_write(DWORD port,BYTE value) +{ + ws_gpu_unknownPort=0; + switch (port) + { + case 0x60: ws_gpu_changeVideoMode(value); + return; + case 0x1C: ws_paletteColors[0]=value&0xf; + ws_paletteColors[1]=(value>>4)&0xf; + return; + case 0x1D: ws_paletteColors[2]=value&0xf; + ws_paletteColors[3]=(value>>4)&0xf; + return; + case 0x1E: ws_paletteColors[4]=value&0xf; + ws_paletteColors[5]=(value>>4)&0xf; + return; + case 0x1F: ws_paletteColors[6]=value&0xf; + ws_paletteColors[7]=(value>>4)&0xf; + return; + default: ws_gpu_unknownPort=1; + } + if ((port>=0x20)&&(port<=0x3f)) + { + ws_gpu_unknownPort=0; + port-=0x20; + int paletteIndex=port>>1; + if (port&0x01) + { + ws_palette[(paletteIndex<<2)+2]=value&0x7; + ws_palette[(paletteIndex<<2)+3]=(value>>4)&0x7; + } + else + { + ws_palette[(paletteIndex<<2)+0]=value&0x7; + ws_palette[(paletteIndex<<2)+1]=(value>>4)&0x7; + } + } +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +BYTE ws_gpu_port_read(BYTE port) +{ + if (port==0xa0) + { + if (ws_gpu_forceColorSystemBool) + return ws_ioRam[0xa0]|2; + else + if (ws_gpu_forceMonoSystemBool) + return ws_ioRam[0xa0]&(~0x02); + else + { + if (ws_gpu_operatingInColor) + return ws_ioRam[0xa0]|2; + else + return ws_ioRam[0xa0]&(~0x02); + } + } + return(ws_ioRam[port]); +} diff --git a/oswan/source/gpu.h b/oswan/source/gpu.h new file mode 100644 index 0000000..4a28b86 --- /dev/null +++ b/oswan/source/gpu.h @@ -0,0 +1,45 @@ +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef __GPU_H__ +#define __GPU_H__ + +#define COLOUR_SCHEME_DEFAULT 0 +#define COLOUR_SCHEME_AMBER 1 +#define COLOUR_SCHEME_GREEN 2 + +extern uint8 ws_gpu_scanline; +extern uint8 ws_gpu_operatingInColor; +extern uint8 ws_videoMode; +extern int16 ws_palette[16*4]; +extern int8 ws_paletteColors[8]; +extern int16 wsc_palette[16*16]; +extern unsigned int ws_gpu_unknownPort; + +extern uint32 vblank_count; + + +void ws_gpu_init(void); +void ws_gpu_done(void); +void ws_gpu_reset(void); +void ws_gpu_renderScanline(int16 *framebuffer); +void ws_gpu_changeVideoMode(uint8 value); +void ws_gpu_write_byte(DWORD offset, BYTE value); +int ws_gpu_port_write(DWORD port,BYTE value); +BYTE ws_gpu_port_read(BYTE port); +void ws_gpu_set_colour_scheme(int scheme); +void ws_gpu_changeVideoMode(uint8 value); +void ws_gpu_forceColorSystem(void); +void ws_gpu_forceMonoSystem(void); +void ws_gpu_clearCache(void); + +#endif + diff --git a/oswan/source/ieeprom.h b/oswan/source/ieeprom.h new file mode 100644 index 0000000..75051f6 --- /dev/null +++ b/oswan/source/ieeprom.h @@ -0,0 +1,100 @@ +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +////////////////////////////////////////////////////////////////////////////// + +uint8 internalEeprom[]= +{ + 0xff,0xff,0xff,0xff,0xff,0xff,192,0xff,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,127,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x00,252,0xff,1,0xff,253,0xff,253,0xff,253,0xff,253, + 0xff,253,0xff,253,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x00,0x00,3,3,0x00,0x00,0x00,64,128,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 135,5,140,9,5,12,139,12,144,0x00,0x00,2, + 0x00,76,165,0x00,128,0x00,0x00,0x00,0xff,127,0xff,127, + 0xff,127,0xff,127,0xff,127,0xff,127,0xff,127,0xff,127, + 0xff,127,0xff,127,0xff,127,0xff,127,0xff,127,0xff,127, + 0xff,127,0xff,127,0xff,127,0xff,127,0xff,127,0xff,127, + 0xff,127,0xff,127,0xff,127,0xff,127,0xff,127,0xff,127, + 0xff,127,0xff,127,0xff,127,0xff,127,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x00,0x00,6,6,6,6,6,0x00,0x00,0x00,0x00,0x00, + 1,128,15,0x00,1,1,1,15,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 'D'-54,'A'-54,'V'-54,'I'-54,'D'-54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,32,1,1,33,1,4,0x00,1, + 0x00,152,60,127,74,1,53,1,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff +}; diff --git a/oswan/source/initialIo.h b/oswan/source/initialIo.h new file mode 100644 index 0000000..5b4f113 --- /dev/null +++ b/oswan/source/initialIo.h @@ -0,0 +1,271 @@ +//////////////////////////////////////////////////////////////////////////////// +// Initial I/O values +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +////////////////////////////////////////////////////////////////////////////// + +uint8 initialIoValue[256]= +{ + 0x00,//0 + 0x00,//1 + 0x9d,//2 + 0xbb,//3 + 0x00,//4 + 0x00,//5 + 0x00,//6 + 0x26,//7 + 0xfe,//8 + 0xde,//9 + 0xf9,//a + 0xfb,//b + 0xdb,//c + 0xd7,//d + 0x7f,//e + 0xf5,//f + 0x00,//10 + 0x00,//11 + 0x00,//12 + 0x00,//13 + 0x01,//14 + 0x00,//15 + 0x9e,//16 + 0x9b,//17 + 0x00,//18 + 0x00,//19 + 0x00,//1a + 0x00,//1b + 0x99,//1c + 0xfd,//1d + 0xb7,//1e + 0xdf,//1f + 0x30,//20 + 0x57,//21 + 0x75,//22 + 0x76,//23 + 0x15,//24 + 0x73,//25 + 0x77,//26 + 0x77,//27 + 0x20,//28 + 0x75,//29 + 0x50,//2a + 0x36,//2b + 0x70,//2c + 0x67,//2d + 0x50,//2e + 0x77,//2f + 0x57,//30 + 0x54,//31 + 0x75,//32 + 0x77,//33 + 0x75,//34 + 0x17,//35 + 0x37,//36 + 0x73,//37 + 0x50,//38 + 0x57,//39 + 0x60,//3a + 0x77,//3b + 0x70,//3c + 0x77,//3d + 0x10,//3e + 0x73,//3f + 0x00,//40 + 0x00,//41 + 0x00,//42 + 0x00,//43 + 0x00,//44 + 0x00,//45 + 0x00,//46 + 0x00,//47 + 0x00,//48 + 0x00,//49 + 0x00,//4a + 0x00,//4b + 0x00,//4c + 0x00,//4d + 0x00,//4e + 0x00,//4f + 0x00,//50 + 0x00,//51 + 0x00,//52 + 0x00,//53 + 0x00,//54 + 0x00,//55 + 0x00,//56 + 0x00,//57 + 0x00,//58 + 0x00,//59 + 0x00,//5a + 0x00,//5b + 0x00,//5c + 0x00,//5d + 0x00,//5e + 0x00,//5f + 0x0a,//60 + 0x00,//61 + 0x00,//62 + 0x00,//63 + 0x00,//64 + 0x00,//65 + 0x00,//66 + 0x00,//67 + 0x00,//68 + 0x00,//69 + 0x00,//6a + 0x0f,//6b + 0x00,//6c + 0x00,//6d + 0x00,//6e + 0x00,//6f + 0x00,//70 + 0x00,//71 + 0x00,//72 + 0x00,//73 + 0x00,//74 + 0x00,//75 + 0x00,//76 + 0x00,//77 + 0x00,//78 + 0x00,//79 + 0x00,//7a + 0x00,//7b + 0x00,//7c + 0x00,//7d + 0x00,//7e + 0x00,//7f + 0x00,//80 + 0x00,//81 + 0x00,//82 + 0x00,//83 + 0x00,//84 + 0x00,//85 + 0x00,//86 + 0x00,//87 + 0x00,//88 + 0x00,//89 + 0x00,//8a + 0x00,//8b + 0x00,//8c + 0x1f,//8d 1d ? + 0x00,//8e + 0x00,//8f + 0x00,//90 + 0x00,//91 + 0x00,//92 + 0x00,//93 + 0x00,//94 + 0x00,//95 + 0x00,//96 + 0x00,//97 + 0x00,//98 + 0x00,//99 + 0x00,//9a + 0x00,//9b + 0x00,//9c + 0x00,//9d + 0x03,//9e + 0x00,//9f + 0x87-2,//a0 + 0x00,//a1 + 0x00,//a2 + 0x00,//a3 + 0x0,//a4 2b + 0x0,//a5 7f + 0x4f,//a6 + 0xff,//a7 cf ? + 0x00,//a8 + 0x00,//a9 + 0x00,//aa + 0x00,//ab + 0x00,//ac + 0x00,//ad + 0x00,//ae + 0x00,//af + 0x00,//b0 + 0xdb,//b1 + 0x00,//b2 + 0x00,//b3 + 0x00,//b4 + 0x40,//b5 + 0x00,//b6 + 0x00,//b7 + 0x00,//b8 + 0x00,//b9 + 0x01,//ba + 0x00,//bb + 0x42,//bc + 0x00,//bd + 0x83,//be + 0x00,//bf + 0x2f,//c0 + 0x3f,//c1 + 0xff,//c2 + 0xff,//c3 + 0x00,//c4 + 0x00,//c5 + 0x00,//c6 + 0x00,//c7 + + 0xd1,//c8? + 0xd1,//c9 + 0xd1,//ca + 0xd1,//cb + 0xd1,//cc + 0xd1,//cd + 0xd1,//ce + 0xd1,//cf + 0xd1,//d0 + 0xd1,//d1 + 0xd1,//d2 + 0xd1,//d3 + 0xd1,//d4 + 0xd1,//d5 + 0xd1,//d6 + 0xd1,//d7 + 0xd1,//d8 + 0xd1,//d9 + 0xd1,//da + 0xd1,//db + 0xd1,//dc + 0xd1,//dd + 0xd1,//de + 0xd1,//df + 0xd1,//e0 + 0xd1,//e1 + 0xd1,//e2 + 0xd1,//e3 + 0xd1,//e4 + 0xd1,//e5 + 0xd1,//e6 + 0xd1,//e7 + 0xd1,//e8 + 0xd1,//e9 + 0xd1,//ea + 0xd1,//eb + 0xd1,//ec + 0xd1,//ed + 0xd1,//ee + 0xd1,//ef + 0xd1,//f0 + 0xd1,//f1 + 0xd1,//f2 + 0xd1,//f3 + 0xd1,//f4 + 0xd1,//f5 + 0xd1,//f6 + 0xd1,//f7 + 0xd1,//f8 + 0xd1,//f9 + 0xd1,//fa + 0xd1,//fb + 0xd1,//fc + 0xd1,//fd + 0xd1,//fe + 0xd1 //ff +}; diff --git a/oswan/source/io.cpp b/oswan/source/io.cpp new file mode 100644 index 0000000..9136b14 --- /dev/null +++ b/oswan/source/io.cpp @@ -0,0 +1,715 @@ +//////////////////////////////////////////////////////////////////////////////// +// I/O ports +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include /* UNIX standard function definitions */ +#include /* Error number definitions */ +#include /* POSIX terminal control definitions */ + +#include "log.h" +#include "rom.h" +#include "./nec/nec.h" +#include "initialIo.h" +#include "ieeprom.h" +#include "gpu.h" +#include "audio.h" + +extern uint8 *externalEeprom; +extern uint32 externalEepromAddressMask; +extern uint32 romAddressMask; + +uint8 *ws_ioRam=NULL; + +uint8 ws_key_start; +uint8 ws_key_left; +uint8 ws_key_right; +uint8 ws_key_up; +uint8 ws_key_down; +uint8 ws_key_button_1; +uint8 ws_key_button_2; +uint8 ws_key_flipped; + +int rtcDataRegisterReadCount=0; + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_io_reset(void) +{ + ws_key_start=0; + ws_key_left=0; + ws_key_right=0; + ws_key_up=0; + ws_key_down=0; + ws_key_button_1=0; + ws_key_button_2=0; + int i; + for (i=0;i<0x100;i++) + ws_ioRam[i]=initialIoValue[i]; + for (i=0;i<0xc9;i++) + cpu_writeport(i,initialIoValue[i]); + + rtcDataRegisterReadCount=0; +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_io_init(void) +{ + if (ws_ioRam==NULL) + ws_ioRam=(uint8*)malloc(0x100); + + ws_io_reset(); + ws_key_flipped=0; +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_io_flipControls(void) +{ + ws_key_flipped=!ws_key_flipped; +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_io_done(void) +{ + if (ws_ioRam==NULL) + free(ws_ioRam); +} + +/* Serial port */ +#define BDR_9600 (0) +#define BDR_38400 (1) +#define SERIAL_PORT "/dev/tty.USA19H141P1.1" +int serialfd = -1; +int serial_have_data = 0; +unsigned char serial_data = 0; +int serial_speed = BDR_9600; +void open_serial() +{ + if (serialfd < 0) + { + serialfd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY); + + //set_baudrate(serial_speed); + serial_have_data = 0; + } +} + +void set_baudrate(int speed) +{ + struct termios options; + if (serialfd < 0) + return; + + tcgetattr(serialfd, &options); + + options.c_cflag &= ~PARENB; + options.c_cflag &= ~CSTOPB; + options.c_cflag &= ~CSIZE; + options.c_cflag |= CS8; + + if (speed == BDR_9600) + { + cfsetispeed(&options, B9600); + } + else + { + cfsetospeed(&options, B38400); + } + + options.c_cflag &= ~CNEW_RTSCTS; + options.c_cflag |= (CLOCAL | CREAD); + + options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + + options.c_oflag &= ~OPOST; + + tcsetattr(serialfd, TCSANOW, &options); + + /* Make sure read is not blocking */ + fcntl(serialfd, F_SETFL, FNDELAY); +} + +void close_serial() +{ + close(serialfd); + serialfd = -1; +} + +void nec_int(DWORD wektor); + +void check_serial_data() +{ + unsigned char buf[10]; + int f; + if (serialfd < 0) + return; + + if (serial_have_data == 0) + { + f = read(serialfd, buf, 1); + if (f > 0) + { + printf("Ho [%d]!\n", f);fflush(stdout); + serial_have_data = 0x01; + serial_data = buf[0]; + } + } + if(serial_have_data > 0) + { + /* Gen an int if enabled */ + if(ws_ioRam[0xB2] & 0x04) + { + ws_ioRam[0xb6] &= ~ 0x04; + printf("INNNNNTTTT!!!!!!!"); + nec_int((ws_ioRam[0xb0]+3)*4); + } + } +} + +unsigned char read_serial() +{ + unsigned char buf[10]; + int f; + if (serialfd < 0) + return 0xFF; + if (serial_have_data > 0) + { + serial_have_data = 0; + return serial_data; + } + f = read(serialfd, buf, 1); + + if (f == 1) + return buf[0]; + + return 0x42; +} + +void write_serial(unsigned char value) +{ + if (serialfd < 0) + return; + write(serialfd, &value, 1); +} + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +BYTE cpu_readport(BYTE port) +{ + int w1,w2; + BYTE retVal; + + if (port >= 0xBA) && (port <= 0xBE) + { + printf("Reading IEEP %02X\n", port); + } + + + switch (port) + { + case 0x4e: + case 0x4f: + case 0x50: + case 0x51: + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8a: + case 0x8b: + case 0x8c: + case 0x8d: + case 0x8e: + case 0x8f: + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + return(ws_audio_port_read(port)); + //case 0xaa: return 0xff; + /*case 0xb3: // ??? + if (ws_ioRam[0xb3]<0x80) + return 0; + + if (ws_ioRam[0xb3]<0xc0) + return 0x84; + + return 0xc4;*/ + case 0xb5: + w1=ws_ioRam[0xb5]; + if(w1&0x40) + { + w2=0x00; + if (ws_key_flipped) + w2=(ws_key_start<<1); + else + w2=(ws_key_start<<1)|(ws_key_button_1<<2)|(ws_key_button_2<<3); + return (uint8)((w1&0xf0)|w2); + } + if(w1&0x20) + { + w2=0x00; + if (ws_key_flipped) + w2=(ws_key_button_1)|(ws_key_button_2<<2); + else + w2=(ws_key_up<<0)|(ws_key_right<<1)|(ws_key_down<<2)|(ws_key_left<<3); + return (uint8)((w1&0xf0)|w2); + } + if(w1&0x10) + { + w2=0x00; + if (ws_key_flipped) + w2=(ws_key_up<<1)|(ws_key_right<<2)|(ws_key_down<<3)|(ws_key_left); + return (uint8)((w1&0xf0)|w2); + } + break; + case 0xbe: // internal eeprom status/command register + // ack eeprom write + if(ws_ioRam[0xbe]&0x20) + return ws_ioRam[0xbe]|2; + + // ack eeprom read + if(ws_ioRam[0xbe]&0x10) + return ws_ioRam[0xbe]|1; + + // else ack both + return ws_ioRam[0xbe]|3; + case 0xba: // eeprom even byte read + w1=((((uint16)ws_ioRam[0xbd])<<8)|((uint16)ws_ioRam[0xbc])); + w1=(w1<<1)&0x3ff; + return internalEeprom[w1]; + case 0xbb: // eeprom odd byte read + w1=((((uint16)ws_ioRam[0xbd])<<8)|((uint16)ws_ioRam[0xbc])); + w1=((w1<<1)+1)&0x3ff; + return internalEeprom[w1]; + case 0xc0 : // ??? + retVal = ((ws_ioRam[0xc0]&0xf)|0x20); + goto exit; + + case 0xc4: // external eeprom even byte read + w1=(((((WORD)ws_ioRam[0xc7])<<8)|((WORD)ws_ioRam[0xc6]))<<1)&(externalEepromAddressMask); + retVal = externalEeprom[w1]; + goto exit; + + case 0xc5: // external eeprom odd byte read + w1=(((((WORD)ws_ioRam[0xc7])<<8)|((WORD)ws_ioRam[0xc6]))<<1)&(externalEepromAddressMask); + retVal = externalEeprom[w1+1]; + goto exit; + + case 0xc8: // external eeprom status/command register + // ack eeprom write + if(ws_ioRam[0xc8]&0x20) + { + retVal = ws_ioRam[0xc8]|2; + goto exit; + } + + // ack eeprom read + if(ws_ioRam[0xc8]&0x10) + { + retVal = ws_ioRam[0xc8]|1; + goto exit; + } + + // else ack both + retVal = ws_ioRam[0xc8]|3; + goto exit; + + case 0xca : // RTC Command and status register + // set ack to always 1 + retVal = (ws_ioRam[0xca]|0x80); + goto exit; + case 0xcb : // RTC data register + + if(ws_ioRam[0xca]==0x15) // get time command + { + struct tm *newtime; + time_t long_time; + time( &long_time ); + newtime = localtime( &long_time ); + + #define BCD(value) ((value/10)<<4)|(value%10) + switch(rtcDataRegisterReadCount) + { + case 0: rtcDataRegisterReadCount++; + retVal = BCD(newtime->tm_year-100); + goto exit; + case 1: rtcDataRegisterReadCount++; + retVal = BCD(newtime->tm_mon); + goto exit; + case 2: rtcDataRegisterReadCount++; + retVal = BCD(newtime->tm_mday); + goto exit; + case 3: rtcDataRegisterReadCount++; + retVal = BCD(newtime->tm_wday); + goto exit; + case 4: rtcDataRegisterReadCount++; + retVal = BCD(newtime->tm_hour); + goto exit; + case 5: rtcDataRegisterReadCount++; + retVal = BCD(newtime->tm_min); + goto exit; + case 6: rtcDataRegisterReadCount=0; + retVal = BCD(newtime->tm_sec); + goto exit; + } + return 0; + } + else + { + // set ack + retVal = (ws_ioRam[0xcb]|0x80); + goto exit; + } + + case 0xD0: + retVal = 0; + goto exit; + + /* Serial port link.. */ + case 0xB1: + retVal = read_serial(); + printf("RS232: Read %02X\n", retVal); + goto exit; + + case 0xB3: + check_serial_data(); + if (ws_ioRam[0xB3] & 0x80) + retVal = (ws_ioRam[0xB3] & ~1) | serial_have_data | 0x04; + else + retVal = 0x00; + printf("<<< 0xD0) printf("ReadIO %02X <= %02X\n", port, retVal); + break; + + } + retVal = ws_gpu_port_read(port); + +exit: + return retVal; +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void cpu_writeport(DWORD port,BYTE value) +{ + unsigned short F0dbg = 0; + int w1,w2; + int unknown_io_port=0; + + if (port >= 0xBA) && (port <= 0xBE) + { + printf("Writing IEEP %02X <= %02X\n", port, value); + } + + if ((ws_ioRam[port]==value) && (port < 0xF0) && ((port < 0xB0) || (port > 0xBF)) ) + return; + + ws_ioRam[port]=value; + + switch (port) + { + /* GPU IOs */ + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + break; + case 0x15: printf("Icons %c %c %c %c %c %c %c %c\n", + (value>>7)&1?'?':' ', + (value>>6)&1?'?':' ', + (value>>5)&1?'3':' ', + (value>>4)&1?'2':' ', + (value>>3)&1?'1':' ', + (value>>2)&1?'H':' ', + (value>>1)&1?'V':' ', + (value>>0)&1?'S':' ' + ); break; + + /* Palettes ? */ + case 0x1C: case 0x25: case 0x2F: case 0x38: + case 0x1D: case 0x26: case 0x30: case 0x39: + case 0x1E: case 0x27: case 0x31: case 0x3A: + case 0x1F: case 0x28: case 0x32: case 0x3B: + case 0x20: case 0x29: case 0x33: case 0x3C: + case 0x21: case 0x2A: case 0x34: case 0x3E: + case 0x22: case 0x2B: case 0x35: case 0x3F: + case 0x23: case 0x2C: case 0x36: + case 0x24: case 0x2E: case 0x37: + break; + + /* DMAs */ + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + break; + + case 0x48: // DMA + + // bit 7 set to start dma transfer + if(value&0x80) + { + int dma_start = (((DWORD)ws_ioRam[0x41])<<8)|(((DWORD)ws_ioRam[0x40]))|(((DWORD)ws_ioRam[0x42])<<16); + int dma_end = (((DWORD)ws_ioRam[0x45])<<8)|(((DWORD)ws_ioRam[0x44]))|(((DWORD)ws_ioRam[0x43])<<16); + int dma_size = (((DWORD)ws_ioRam[0x47])<<8)|(((DWORD)ws_ioRam[0x46])); + for(int ix=0;ix>8); + ws_ioRam[0x40]=(BYTE)(dma_start&0xff); + ws_ioRam[0x45]=(BYTE)(dma_end>>8); + ws_ioRam[0x44]=(BYTE)(dma_end&0xff); + ws_ioRam[0x48]=0; + } + break; + + /* Audio */ + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + ws_audio_port_write(port, value); + break; + + /* DMA Start! */ + case 0x52: break; + + /* GPU (again) */ + case 0x60: + break; + + /* Audio */ + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8a: + case 0x8b: + case 0x8c: + case 0x8d: + case 0x8e: + case 0x8f: + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + ws_audio_port_write(port,value); + break; + + /* Hardeware */ + case 0xA0: + break; + + /*Timers */ + case 0xA2: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + break; + + /* Hardware */ + case 0xB0: break; + case 0xB1: write_serial(value); /*printf("RS232 TX: %02X\n", value);*/ break; + case 0xB2: break; + case 0xB3: printf(">>>>RS232STA: %02X [%c%c%cxx%c%c%c]\n", value, + (value & 0x80)?'E':'d', + (value & 0x40)?'3':'9', + (value & 0x20)?'R':'n', + (value & 0x04)?'E':'f', + (value & 0x02)?'V':'n', + (value & 0x01)?'D':'e' + ); + +/* Serial status: 7 = Enable, 6 = baudrate, 5 = Overrun reset + 2 = Send Buffer empty + 1 = Overrun + 0 = Data Received + */ + serial_speed = ((value&040) == 0x00)?BDR_9600:BDR_38400; + if ((value & 0x80) == 0x80) + { + open_serial(); + set_baudrate(serial_speed); + check_serial_data(); + } + break; + + case 0xB5: + break; + /* buttons */ + case 0xB6: + break; + + /* Internal EEPROM */ + case 0xba: w1=(((((WORD)ws_ioRam[0xbd])<<8)|((WORD)ws_ioRam[0xbc]))); + w1=(w1<<1)&0x3ff; + internalEeprom[w1]=value; + return; + + case 0xbb: w1=(((((WORD)ws_ioRam[0xbd])<<8)|((WORD)ws_ioRam[0xbc]))); + w1=((w1<<1)+1)&0x3ff; + internalEeprom[w1]=value; + return; + case 0xBC: case 0xBD: case 0xBE: break; + + + /* MBC */ + case 0xC0: case 0xC1: case 0xC2: case 0xC3: break; + case 0xc4: w1=(((((WORD)ws_ioRam[0xc7])<<8)|((WORD)ws_ioRam[0xc6]))<<1)&externalEepromAddressMask; + externalEeprom[w1]=value; + return; + + case 0xc5: w1=(((((WORD)ws_ioRam[0xc7])<<8)|((WORD)ws_ioRam[0xc6]))<<1)&externalEepromAddressMask; + externalEeprom[w1+1]=value; + return; + + case 0xC6: case 0xC7: case 0xC8: break; + + case 0xca: if(value==0x15) + rtcDataRegisterReadCount=0; + break; + break; + + case 0xCB: break; + + case 0xF0: break; + case 0xF1: printf("%d\n", (signed short)((value << 8) | ws_ioRam[0xF0])); break; + case 0xF2: printf("%c", value); fflush(stdout); break; + + default: + unknown_io_port=1; + } + if ((ws_gpu_port_write(port,value) == 1) && (unknown_io_port == 1)) + { + fprintf(log_get(),"WriteIO(%02X, %02X);\n",port, value); + } + /*if (port >= 0xC0) + { + fprintf(log_get(),"WriteMBCIO(%02X, %02X);\n",port, value); + }*/ + +// if ((ws_gpu_unknownPort)&&(unknown_io_port)) +// { +// fprintf(log_get(),"io: writing 0x%.2x to unknown port 0x%.2x\n",value,port); +// } +} diff --git a/oswan/source/io.h b/oswan/source/io.h new file mode 100644 index 0000000..02f6515 --- /dev/null +++ b/oswan/source/io.h @@ -0,0 +1,30 @@ +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef __IO_H__ +#define __IO_H__ + +extern uint8 *ws_ioRam; +extern uint8 ws_key_start; +extern uint8 ws_key_left; +extern uint8 ws_key_right; +extern uint8 ws_key_up; +extern uint8 ws_key_down; +extern uint8 ws_key_button_1; +extern uint8 ws_key_button_2; + +void ws_io_init(void); +void ws_io_reset(void); +void ws_io_flipControls(void); +void ws_io_done(void); + +#endif + diff --git a/oswan/source/log.cpp b/oswan/source/log.cpp new file mode 100644 index 0000000..0e344ed --- /dev/null +++ b/oswan/source/log.cpp @@ -0,0 +1,63 @@ +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "log.h" + +FILE *log_stream=NULL; + +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +////////////////////////////////////////////////////////////////////////////// +int log_init(char *path) +{ + //log_stream=fopen(path,"wrt"); + log_stream = stdout; + if (log_stream==NULL) + return(0); + return(1); +} +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +////////////////////////////////////////////////////////////////////////////// +FILE *log_get(void) +{ + return(log_stream); +} +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +////////////////////////////////////////////////////////////////////////////// +void log_done(void) +{ + fclose(log_stream); +} diff --git a/oswan/source/log.h b/oswan/source/log.h new file mode 100644 index 0000000..b439ccc --- /dev/null +++ b/oswan/source/log.h @@ -0,0 +1,20 @@ +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef __LOG_H__ +#define __LOG_H__ + +int log_init(char *path); +FILE *log_get(void); +void log_done(void); + +#endif + diff --git a/oswan/source/memory.cpp b/oswan/source/memory.cpp new file mode 100644 index 0000000..2be5f32 --- /dev/null +++ b/oswan/source/memory.cpp @@ -0,0 +1,308 @@ +//////////////////////////////////////////////////////////////////////////////// +// Memory +//////////////////////////////////////////////////////////////////////////////// +// Notes: need to optimize cpu_writemem20 +// +// +// +// +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include "log.h" +#include "rom.h" +#include "./nec/nec.h" +#include "io.h" +#include "gpu.h" +#include "audio.h" + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +#define IO_ROM_BANK_BASE_SELECTOR 0xC0 + + +uint8 *ws_rom; +uint8 *ws_staticRam; +uint8 *internalRam; +uint8 *externalEeprom; + +extern uint8 *ws_ioRam; + +uint16 ws_rom_checksum; + +uint32 sramAddressMask; +uint32 externalEepromAddressMask; +uint32 romAddressMask; +uint32 romSize; + +int ws_sram_dirty = 0; + +extern nec_Regs I; + +void dump_memory() +{ + int i; + FILE *fp; + printf("Dumping memory....\n"); + fp = fopen("iram.bin", "wb"); + fwrite(internalRam, 1, 0x10000, fp); + fclose(fp); + + fp = fopen("sram.bin", "wb"); + fwrite(ws_staticRam, 1, 0x10000, fp); + fclose(fp); + + fp = fopen("rom.bin", "wb"); + fwrite(ws_rom, 1, romSize, fp); + fclose(fp); + + fp = fopen("memorydump.bin", "wb"); + fwrite(internalRam, 1, 0x10000, fp); + /* page 1 */ + fwrite(&(ws_staticRam[sramAddressMask]), 1, 0x10000, fp); + fwrite(&(ws_rom[((ws_ioRam[IO_ROM_BANK_BASE_SELECTOR+2]&((romSize>>16)-1))<<16)]), 1, 0x10000, fp); + fwrite(&(ws_rom[((ws_ioRam[IO_ROM_BANK_BASE_SELECTOR+3]&((romSize>>16)-1))<<16)]), 1, 0x10000, fp); + for(i = 4; i < 0x10; i++) + { + int romBank=(256-(((ws_ioRam[IO_ROM_BANK_BASE_SELECTOR]&0xf)<<4)|(i&0xf))); + fwrite(&(ws_rom[(unsigned)(romSize-(romBank<<16))]), 1, 0x10000, fp); + } + fclose(fp); + + fp = fopen("registers.bin", "wb"); + fwrite(ws_ioRam, 1, 256, fp); + fclose(fp); + + fp = fopen("cpuregs.bin", "wb"); + /* CS */ + fwrite(&I.sregs[CS], 1, 2, fp); + /* IP */ + fwrite(&I.ip, 1, 2, fp); + fclose(fp); +} + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void cpu_writemem20(DWORD addr,BYTE value) +{ + uint32 offset=addr&0xffff; + uint32 bank=addr>>16; + + // 0 - RAM - 16 KB (WS) / 64 KB (WSC) internal RAM + if (!bank) + { + ws_gpu_write_byte(offset,value); + ws_audio_write_byte(offset,value); + } + else + // 1 - SRAM (cart) + if (bank==1) + { + ws_staticRam[offset&sramAddressMask]=value; + ws_sram_dirty = 1; + } + + // other banks are read-only +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +BYTE cpu_readmem20(DWORD addr) +{ + uint32 offset=addr&0xffff; + uint32 bank=addr>>16; + + switch (bank) + { + case 0: // 0 - RAM - 16 KB (WS) / 64 KB (WSC) internal RAM + if (ws_gpu_operatingInColor) + return(internalRam[offset]); + else + if (offset<0x4000) + return(internalRam[offset]); + return(0x90); + + case 1: // 1 - SRAM (cart) + return ws_staticRam[offset&sramAddressMask]; + case 2: + case 3: return ws_rom[offset+((ws_ioRam[IO_ROM_BANK_BASE_SELECTOR+bank]&((romSize>>16)-1))<<16)]; + default: + int romBank=(256-(((ws_ioRam[IO_ROM_BANK_BASE_SELECTOR]&0xf)<<4)|(bank&0xf))); + return ws_rom[(unsigned)(offset+romSize-(romBank<<16))]; + } + return(0xff); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_memory_init(uint8 *rom, uint32 wsRomSize) +{ + ws_romHeaderStruct *ws_romHeader; + + ws_rom=rom; + romSize=wsRomSize; + ws_romHeader=ws_rom_getHeader(ws_rom,romSize); + ws_rom_checksum=ws_romHeader->checksum; + internalRam=(uint8*)malloc(0x10000); + ws_staticRam=(uint8*)malloc(0x10000); + externalEeprom=(uint8*)malloc(131072);//ws_rom_eepromSize(ws_rom,romSize)); + sramAddressMask=ws_rom_sramSize(ws_rom,romSize)-1; + externalEepromAddressMask=ws_rom_eepromSize(ws_rom,romSize)-1; + romAddressMask=romSize-1; +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_memory_reset(void) +{ + memset(internalRam,0,0x10000); + //memset(ws_staticRam,0,0x10000); // should the sram really be cleared? ... +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_memory_done(void) +{ + free(ws_rom); + free(ws_staticRam); + free(internalRam); + free(externalEeprom); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +uint8 *memory_getRom(void) +{ + return(ws_rom); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +uint32 memory_getRomSize(void) +{ + return(romSize); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +uint16 memory_getRomCrc(void) +{ + return(ws_rom_checksum); +} + + +void ws_sram_load(char *path) +{ + FILE *f; + size_t read; + + f = fopen(path, "r"); + if (NULL == f) + { + memset(ws_staticRam, 0, 0x10000); + return; + } + + read = fread(ws_staticRam, 1, 0x8000, f); + //fprintf(log_get(), "read 0x%x (of 0x%x?) bytes of save ram from %s\n", read, ws_rom_sramSize(ws_rom, romSize), path); + fclose(f); +} + +void ws_sram_save(char *path) +{ + FILE *f; + size_t wrote; + + f = fopen(path, "wb"); + if (NULL == f) + { + fprintf(log_get(), "error opening %s for writing save ram. (%s)\n", path, strerror(errno)); + return; + } + + wrote = fwrite(ws_staticRam, 1, 0x8000, f); + fflush(f); + //fprintf(log_get(), "wrote 0x%x bytes of save ram to %s\n", wrote, path); + fclose(f); +} + diff --git a/oswan/source/memory.h b/oswan/source/memory.h new file mode 100644 index 0000000..0e9c6ac --- /dev/null +++ b/oswan/source/memory.h @@ -0,0 +1,34 @@ +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef __MEMORY_H__ +#define __MEMORY_H__ + +extern uint8 *ws_staticRam; +extern uint8 *internalRam; +extern uint8 *externalEeprom; + +void ws_memory_init(uint8 *rom, uint32 romSize); +void ws_memory_reset(void); +uint8 *memory_getRom(void); +uint32 memory_getRomSize(void); +uint16 memory_getRomCrc(void); +void ws_memory_done(void); +void memory_load(int fp); +void memory_save(int fp); + +void ws_sram_load(char *path); +void ws_sram_save(char *path); + +void dump_memory(); + +#endif + diff --git a/oswan/source/nec/nec.cpp b/oswan/source/nec/nec.cpp new file mode 100644 index 0000000..8d8babe --- /dev/null +++ b/oswan/source/nec/nec.cpp @@ -0,0 +1,921 @@ +/**************************************************************************** + + NEC V30MZ(V20/V30/V33) emulator + + Small changes made by toshi (Cycle count macros changed , "THROUGH" macro added) + + Small changes made by dox@space.pl (Corrected bug in NEG instruction , different AUX flag handling in some opcodes) + + (Re)Written June-September 2000 by Bryan McPhail (mish@tendril.co.uk) based + on code by Oliver Bergmann (Raul_Bloodworth@hotmail.com) who based code + on the i286 emulator by Fabrice Frances which had initial work based on + David Hedley's pcemu(!). + + This new core features 99% accurate cycle counts for each processor, + there are still some complex situations where cycle counts are wrong, + typically where a few instructions have differing counts for odd/even + source and odd/even destination memory operands. + + Flag settings are also correct for the NEC processors rather than the + I86 versions. + + Nb: This emulation should be faster than previous NEC cores, but + because the old cycle count values were far too high in many cases + the processor has to do more 'work' than before, so the overall effect + may be a slower core. + +****************************************************************************/ + + +#include +#include + +/* +#define UINT8 unsigned char +#define UINT16 unsigned short +#define UINT32 unsigned int +#define INT8 signed char +#define INT16 signed short +#define INT32 signed int +*/ + +#include "source/types.h" + +#include "nec.h" +#include "necintrf.h" + +/***************************************************************************/ +/* cpu state */ +/***************************************************************************/ + +int nec_ICount; + +nec_Regs I; + +static UINT32 cpu_type; +static UINT32 prefix_base; /* base address of the latest prefix segment */ +char seg_prefix; /* prefix segment indicator */ + + +/* The interrupt number of a pending external interrupt pending NMI is 2. */ +/* For INTR interrupts, the level is caught on the bus during an INTA cycle */ + + +#include "necinstr.h" +#include "necea.h" +#include "necmodrm.h" + +static int no_interrupt; + +static UINT8 parity_table[256]; + +/***************************************************************************/ + +void nec_reset (void *param) +{ + unsigned int i,j,c; + BREGS reg_name[8]={ AL, CL, DL, BL, AH, CH, DH, BH }; + + + memset( &I, 0, sizeof(I) ); + + no_interrupt=0; + I.sregs[CS] = 0xffff; + + + for (i = 0;i < 256; i++) + { + for (j = i, c = 0; j > 0; j >>= 1) + if (j & 1) c++; + parity_table[i] = !(c & 1); + } + + I.ZeroVal = I.ParityVal = 1; + SetMD(1); /* set the mode-flag = native mode */ + + for (i = 0; i < 256; i++) + { + Mod_RM.reg.b[i] = reg_name[(i & 0x38) >> 3]; + Mod_RM.reg.w[i] = (WREGS) ( (i & 0x38) >> 3) ; + } + + for (i = 0xc0; i < 0x100; i++) + { + Mod_RM.RM.w[i] = (WREGS)( i & 7 ); + Mod_RM.RM.b[i] = (BREGS)reg_name[i & 7]; + } +} + +void nec_exit (void) +{ + +} + + + + +void nec_int(DWORD wektor) +{ + + DWORD dest_seg, dest_off; + + if(I.IF) + { + i_pushf(); + I.TF = I.IF = 0; + dest_off = ReadWord(wektor); + dest_seg = ReadWord(wektor+2); + PUSH(I.sregs[CS]); + PUSH(I.ip); + I.ip = (WORD)dest_off; + I.sregs[CS] = (WORD)dest_seg; + } +} + +static void nec_interrupt(unsigned int_num, /*BOOLEAN*/ int md_flag) +{ + UINT32 dest_seg, dest_off; + + if (int_num == -1) + return; + + i_pushf(); + I.TF = I.IF = 0; + + + dest_off = ReadWord((int_num)*4); + dest_seg = ReadWord((int_num)*4+2); + + PUSH(I.sregs[CS]); + PUSH(I.ip); + I.ip = (WORD)dest_off; + I.sregs[CS] = (WORD)dest_seg; + +} + + +/****************************************************************************/ +/* OPCODES */ +/****************************************************************************/ + +#define OP(num,func_name) static void func_name(void) + + +OP( 0x00, i_add_br8 ) { DEF_br8; ADDB; PutbackRMByte(ModRM,dst); CLKM(3,1); } +OP( 0x01, i_add_wr16 ) { DEF_wr16; ADDW; PutbackRMWord(ModRM,dst); CLKM(3,1); } +OP( 0x02, i_add_r8b ) { DEF_r8b; ADDB; RegByte(ModRM)=dst; CLKM(2,1); } +OP( 0x03, i_add_r16w ) { DEF_r16w; ADDW; RegWord(ModRM)=dst; CLKM(2,1); } +OP( 0x04, i_add_ald8 ) { DEF_ald8; ADDB; I.regs.b[AL]=dst; CLK(1); } +OP( 0x05, i_add_axd16) { DEF_axd16; ADDW; I.regs.w[AW]=dst; CLK(1); } +OP( 0x06, i_push_es ) { PUSH(I.sregs[ES]); CLK(2); } +OP( 0x07, i_pop_es ) { POP(I.sregs[ES]); CLK(3); } + +OP( 0x08, i_or_br8 ) { DEF_br8; ORB; PutbackRMByte(ModRM,dst); CLKM(3,1); } +OP( 0x09, i_or_wr16 ) { DEF_wr16; ORW; PutbackRMWord(ModRM,dst); CLKM(3,1); } +OP( 0x0a, i_or_r8b ) { DEF_r8b; ORB; RegByte(ModRM)=dst; CLKM(2,1); } +OP( 0x0b, i_or_r16w ) { DEF_r16w; ORW; RegWord(ModRM)=dst; CLKM(2,1); } +OP( 0x0c, i_or_ald8 ) { DEF_ald8; ORB; I.regs.b[AL]=dst; CLK(1); } +OP( 0x0d, i_or_axd16 ) { DEF_axd16; ORW; I.regs.w[AW]=dst; CLK(1); } +OP( 0x0e, i_push_cs ) { PUSH(I.sregs[CS]); CLK(2); } +OP( 0x0f, i_pre_nec ) { UINT32 ModRM, tmp, tmp2; /* pop cs at V30MZ? */ + switch (FETCH) { + case 0x10 : BITOP_BYTE; CLKS(3,3,4); tmp2 = I.regs.b[CL] & 0x7; I.ZeroVal = (tmp & (1<>8)&0xf); tmp &= 0xff; PutbackRMByte(ModRM,tmp); CLKM(9,15); break; + case 0x2a : ModRM = FETCH; tmp = GetRMByte(ModRM); tmp2 = (I.regs.b[AL] & 0xf)<<4; I.regs.b[AL] = (I.regs.b[AL] & 0xf0) | (tmp&0xf); tmp = tmp2 | (tmp>>4); PutbackRMByte(ModRM,tmp); CLKM(13,19); break; + case 0x31 : ModRM = FETCH; ModRM=0; break; + case 0x33 : ModRM = FETCH; ModRM=0; break; + case 0x92 : CLK(2); break; /* V25/35 FINT */ + case 0xe0 : ModRM = FETCH; ModRM=0; break; + case 0xf0 : ModRM = FETCH; ModRM=0; break; + case 0xff : ModRM = FETCH; ModRM=0; break; + default: break; + } +} + +OP( 0x10, i_adc_br8 ) { DEF_br8; src+=CF; ADDB; PutbackRMByte(ModRM,dst); CLKM(3,1); } +OP( 0x11, i_adc_wr16 ) { DEF_wr16; src+=CF; ADDW; PutbackRMWord(ModRM,dst); CLKM(3,1); } +OP( 0x12, i_adc_r8b ) { DEF_r8b; src+=CF; ADDB; RegByte(ModRM)=dst; CLKM(2,1); } +OP( 0x13, i_adc_r16w ) { DEF_r16w; src+=CF; ADDW; RegWord(ModRM)=dst; CLKM(2,1); } +OP( 0x14, i_adc_ald8 ) { DEF_ald8; src+=CF; ADDB; I.regs.b[AL]=dst; CLK(1); } +OP( 0x15, i_adc_axd16) { DEF_axd16; src+=CF; ADDW; I.regs.w[AW]=dst; CLK(1); } +OP( 0x16, i_push_ss ) { PUSH(I.sregs[SS]); CLK(2); } +OP( 0x17, i_pop_ss ) { POP(I.sregs[SS]); CLK(3); no_interrupt=1; } + +OP( 0x18, i_sbb_br8 ) { DEF_br8; src+=CF; SUBB; PutbackRMByte(ModRM,dst); CLKM(3,1); } +OP( 0x19, i_sbb_wr16 ) { DEF_wr16; src+=CF; SUBW; PutbackRMWord(ModRM,dst); CLKM(3,1); } +OP( 0x1a, i_sbb_r8b ) { DEF_r8b; src+=CF; SUBB; RegByte(ModRM)=dst; CLKM(2,1); } +OP( 0x1b, i_sbb_r16w ) { DEF_r16w; src+=CF; SUBW; RegWord(ModRM)=dst; CLKM(2,1); } +OP( 0x1c, i_sbb_ald8 ) { DEF_ald8; src+=CF; SUBB; I.regs.b[AL]=dst; CLK(1); } +OP( 0x1d, i_sbb_axd16) { DEF_axd16; src+=CF; SUBW; I.regs.w[AW]=dst; CLK(1); } +OP( 0x1e, i_push_ds ) { PUSH(I.sregs[DS]); CLK(2); } +OP( 0x1f, i_pop_ds ) { POP(I.sregs[DS]); CLK(3); } + +OP( 0x20, i_and_br8 ) { DEF_br8; ANDB; PutbackRMByte(ModRM,dst); CLKM(3,1); } +OP( 0x21, i_and_wr16 ) { DEF_wr16; ANDW; PutbackRMWord(ModRM,dst); CLKM(3,1); } +OP( 0x22, i_and_r8b ) { DEF_r8b; ANDB; RegByte(ModRM)=dst; CLKM(2,1); } +OP( 0x23, i_and_r16w ) { DEF_r16w; ANDW; RegWord(ModRM)=dst; CLKM(2,1); } +OP( 0x24, i_and_ald8 ) { DEF_ald8; ANDB; I.regs.b[AL]=dst; CLK(1); } +OP( 0x25, i_and_axd16) { DEF_axd16; ANDW; I.regs.w[AW]=dst; CLK(1); } +OP( 0x26, i_es ) { seg_prefix=TRUE; prefix_base=I.sregs[ES]<<4; CLK(1); nec_instruction[FETCHOP](); seg_prefix=FALSE; } +OP( 0x27, i_daa ) { ADJ4(6,0x60); CLK(10); } + +OP( 0x28, i_sub_br8 ) { DEF_br8; SUBB; PutbackRMByte(ModRM,dst); CLKM(3,1); } +OP( 0x29, i_sub_wr16 ) { DEF_wr16; SUBW; PutbackRMWord(ModRM,dst); CLKM(3,1); } +OP( 0x2a, i_sub_r8b ) { DEF_r8b; SUBB; RegByte(ModRM)=dst; CLKM(2,1); } +OP( 0x2b, i_sub_r16w ) { DEF_r16w; SUBW; RegWord(ModRM)=dst; CLKM(2,1); } +OP( 0x2c, i_sub_ald8 ) { DEF_ald8; SUBB; I.regs.b[AL]=dst; CLK(1); } +OP( 0x2d, i_sub_axd16) { DEF_axd16; SUBW; I.regs.w[AW]=dst; CLK(1); } +OP( 0x2e, i_cs ) { seg_prefix=TRUE; prefix_base=I.sregs[CS]<<4; CLK(1); nec_instruction[FETCHOP](); seg_prefix=FALSE; } +OP( 0x2f, i_das ) { ADJ4(-6,-0x60); CLK(10); } + +OP( 0x30, i_xor_br8 ) { DEF_br8; XORB; PutbackRMByte(ModRM,dst); CLKM(3,1); } +OP( 0x31, i_xor_wr16 ) { DEF_wr16; XORW; PutbackRMWord(ModRM,dst); CLKM(3,1); } +OP( 0x32, i_xor_r8b ) { DEF_r8b; XORB; RegByte(ModRM)=dst; CLKM(2,1); } +OP( 0x33, i_xor_r16w ) { DEF_r16w; XORW; RegWord(ModRM)=dst; CLKM(2,1); } +OP( 0x34, i_xor_ald8 ) { DEF_ald8; XORB; I.regs.b[AL]=dst; CLK(1); } +OP( 0x35, i_xor_axd16) { DEF_axd16; XORW; I.regs.w[AW]=dst; CLK(1); } +OP( 0x36, i_ss ) { seg_prefix=TRUE; prefix_base=I.sregs[SS]<<4; CLK(1); nec_instruction[FETCHOP](); seg_prefix=FALSE; } +OP( 0x37, i_aaa ) { ADJB(6,1); CLK(9); } + +OP( 0x38, i_cmp_br8 ) { DEF_br8; SUBB; CLKM(2,1); } +OP( 0x39, i_cmp_wr16 ) { DEF_wr16; SUBW; CLKM(2,1); } +OP( 0x3a, i_cmp_r8b ) { DEF_r8b; SUBB; CLKM(2,1); } +OP( 0x3b, i_cmp_r16w ) { DEF_r16w; SUBW; CLKM(2,1); } +OP( 0x3c, i_cmp_ald8 ) { DEF_ald8; SUBB; CLK(1); } +OP( 0x3d, i_cmp_axd16) { DEF_axd16; SUBW; CLK(1); } +OP( 0x3e, i_ds ) { seg_prefix=TRUE; prefix_base=I.sregs[DS]<<4; CLK(1); nec_instruction[FETCHOP](); seg_prefix=FALSE; } +OP( 0x3f, i_aas ) { ADJB(-6,-1); CLK(9); } + +OP( 0x40, i_inc_ax ) { IncWordReg(AW); CLK(1); } +OP( 0x41, i_inc_cx ) { IncWordReg(CW); CLK(1); } +OP( 0x42, i_inc_dx ) { IncWordReg(DW); CLK(1); } +OP( 0x43, i_inc_bx ) { IncWordReg(BW); CLK(1); } +OP( 0x44, i_inc_sp ) { IncWordReg(SP); CLK(1); } +OP( 0x45, i_inc_bp ) { IncWordReg(BP); CLK(1); } +OP( 0x46, i_inc_si ) { IncWordReg(IX); CLK(1); } +OP( 0x47, i_inc_di ) { IncWordReg(IY); CLK(1); } + +OP( 0x48, i_dec_ax ) { DecWordReg(AW); CLK(1); } +OP( 0x49, i_dec_cx ) { DecWordReg(CW); CLK(1); } +OP( 0x4a, i_dec_dx ) { DecWordReg(DW); CLK(1); } +OP( 0x4b, i_dec_bx ) { DecWordReg(BW); CLK(1); } +OP( 0x4c, i_dec_sp ) { DecWordReg(SP); CLK(1); } +OP( 0x4d, i_dec_bp ) { DecWordReg(BP); CLK(1); } +OP( 0x4e, i_dec_si ) { DecWordReg(IX); CLK(1); } +OP( 0x4f, i_dec_di ) { DecWordReg(IY); CLK(1); } + +OP( 0x50, i_push_ax ) { PUSH(I.regs.w[AW]); CLK(1); } +OP( 0x51, i_push_cx ) { PUSH(I.regs.w[CW]); CLK(1); } +OP( 0x52, i_push_dx ) { PUSH(I.regs.w[DW]); CLK(1); } +OP( 0x53, i_push_bx ) { PUSH(I.regs.w[BW]); CLK(1); } +OP( 0x54, i_push_sp ) { PUSH(I.regs.w[SP]); CLK(1); } +OP( 0x55, i_push_bp ) { PUSH(I.regs.w[BP]); CLK(1); } +OP( 0x56, i_push_si ) { PUSH(I.regs.w[IX]); CLK(1); } +OP( 0x57, i_push_di ) { PUSH(I.regs.w[IY]); CLK(1); } + +OP( 0x58, i_pop_ax ) { POP(I.regs.w[AW]); CLK(1); } +OP( 0x59, i_pop_cx ) { POP(I.regs.w[CW]); CLK(1); } +OP( 0x5a, i_pop_dx ) { POP(I.regs.w[DW]); CLK(1); } +OP( 0x5b, i_pop_bx ) { POP(I.regs.w[BW]); CLK(1); } +OP( 0x5c, i_pop_sp ) { POP(I.regs.w[SP]); CLK(1); } +OP( 0x5d, i_pop_bp ) { POP(I.regs.w[BP]); CLK(1); } +OP( 0x5e, i_pop_si ) { POP(I.regs.w[IX]); CLK(1); } +OP( 0x5f, i_pop_di ) { POP(I.regs.w[IY]); CLK(1); } + +OP( 0x60, i_pusha ) { + unsigned tmp=I.regs.w[SP]; + PUSH(I.regs.w[AW]); + PUSH(I.regs.w[CW]); + PUSH(I.regs.w[DW]); + PUSH(I.regs.w[BW]); + PUSH(tmp); + PUSH(I.regs.w[BP]); + PUSH(I.regs.w[IX]); + PUSH(I.regs.w[IY]); + CLK(9); +} +OP( 0x61, i_popa ) { + unsigned tmp; + POP(I.regs.w[IY]); + POP(I.regs.w[IX]); + POP(I.regs.w[BP]); + POP(tmp); + POP(I.regs.w[BW]); + POP(I.regs.w[DW]); + POP(I.regs.w[CW]); + POP(I.regs.w[AW]); + CLK(8); +} +OP( 0x62, i_chkind ) { + UINT32 low,high,tmp; + GetModRM; + low = GetRMWord(ModRM); + high= GetnextRMWord; + tmp= RegWord(ModRM); + if (tmphigh) { + nec_interrupt(5,0); + CLK(7); + } + CLK(13); +} + +/* OP 0x64 - 0x67 is nop at V30MZ */ +OP( 0x64, i_repnc ) { UINT32 next = FETCHOP; UINT16 c = I.regs.w[CW]; + switch(next) { /* Segments */ + case 0x26: seg_prefix=TRUE; prefix_base=I.sregs[ES]<<4; next = FETCHOP; CLK(2); break; + case 0x2e: seg_prefix=TRUE; prefix_base=I.sregs[CS]<<4; next = FETCHOP; CLK(2); break; + case 0x36: seg_prefix=TRUE; prefix_base=I.sregs[SS]<<4; next = FETCHOP; CLK(2); break; + case 0x3e: seg_prefix=TRUE; prefix_base=I.sregs[DS]<<4; next = FETCHOP; CLK(2); break; + } + + switch(next) { + case 0x6c: CLK(2); if (c) do { i_insb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break; + case 0x6d: CLK(2); if (c) do { i_insw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break; + case 0x6e: CLK(2); if (c) do { i_outsb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break; + case 0x6f: CLK(2); if (c) do { i_outsw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break; + case 0xa4: CLK(2); if (c) do { i_movsb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break; + case 0xa5: CLK(2); if (c) do { i_movsw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break; + case 0xa6: CLK(2); if (c) do { i_cmpsb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break; + case 0xa7: CLK(2); if (c) do { i_cmpsw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break; + case 0xaa: CLK(2); if (c) do { i_stosb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break; + case 0xab: CLK(2); if (c) do { i_stosw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break; + case 0xac: CLK(2); if (c) do { i_lodsb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break; + case 0xad: CLK(2); if (c) do { i_lodsw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break; + case 0xae: CLK(2); if (c) do { i_scasb(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break; + case 0xaf: CLK(2); if (c) do { i_scasw(); c--; } while (c>0 && !CF); I.regs.w[CW]=c; break; + default: nec_instruction[next](); + } + seg_prefix=FALSE; +} + +OP( 0x65, i_repc ) { UINT32 next = FETCHOP; UINT16 c = I.regs.w[CW]; + switch(next) { /* Segments */ + case 0x26: seg_prefix=TRUE; prefix_base=I.sregs[ES]<<4; next = FETCHOP; CLK(2); break; + case 0x2e: seg_prefix=TRUE; prefix_base=I.sregs[CS]<<4; next = FETCHOP; CLK(2); break; + case 0x36: seg_prefix=TRUE; prefix_base=I.sregs[SS]<<4; next = FETCHOP; CLK(2); break; + case 0x3e: seg_prefix=TRUE; prefix_base=I.sregs[DS]<<4; next = FETCHOP; CLK(2); break; + } + + switch(next) { + case 0x6c: CLK(2); if (c) do { i_insb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break; + case 0x6d: CLK(2); if (c) do { i_insw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break; + case 0x6e: CLK(2); if (c) do { i_outsb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break; + case 0x6f: CLK(2); if (c) do { i_outsw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break; + case 0xa4: CLK(2); if (c) do { i_movsb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break; + case 0xa5: CLK(2); if (c) do { i_movsw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break; + case 0xa6: CLK(2); if (c) do { i_cmpsb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break; + case 0xa7: CLK(2); if (c) do { i_cmpsw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break; + case 0xaa: CLK(2); if (c) do { i_stosb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break; + case 0xab: CLK(2); if (c) do { i_stosw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break; + case 0xac: CLK(2); if (c) do { i_lodsb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break; + case 0xad: CLK(2); if (c) do { i_lodsw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break; + case 0xae: CLK(2); if (c) do { i_scasb(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break; + case 0xaf: CLK(2); if (c) do { i_scasw(); c--; } while (c>0 && CF); I.regs.w[CW]=c; break; + default: nec_instruction[next](); + } + seg_prefix=FALSE; +} + +OP( 0x68, i_push_d16 ) { UINT32 tmp; FETCHWORD(tmp); PUSH(tmp); CLK(1); } +OP( 0x69, i_imul_d16 ) { UINT32 tmp; DEF_r16w; FETCHWORD(tmp); dst = (INT32)((INT16)src)*(INT32)((INT16)tmp); I.CarryVal = I.OverVal = (((INT32)dst) >> 15 != 0) && (((INT32)dst) >> 15 != -1); RegWord(ModRM)=(WORD)dst; CLKM(4,3);} +OP( 0x6a, i_push_d8 ) { UINT32 tmp = (WORD)((INT16)((INT8)FETCH)); PUSH(tmp); CLK(1); } +OP( 0x6b, i_imul_d8 ) { UINT32 src2; DEF_r16w; src2= (WORD)((INT16)((INT8)FETCH)); dst = (INT32)((INT16)src)*(INT32)((INT16)src2); I.CarryVal = I.OverVal = (((INT32)dst) >> 15 != 0) && (((INT32)dst) >> 15 != -1); RegWord(ModRM)=(WORD)dst; CLKM(4,3); } +OP( 0x6c, i_insb ) { PutMemB(ES,I.regs.w[IY],read_port(I.regs.w[DW])); I.regs.w[IY]+= -2 * I.DF + 1; CLK(6); } +OP( 0x6d, i_insw ) { PutMemB(ES,I.regs.w[IY],read_port(I.regs.w[DW])); PutMemB(ES,(I.regs.w[IY]+1)&0xffff,read_port((I.regs.w[DW]+1)&0xffff)); I.regs.w[IY]+= -4 * I.DF + 2; CLK(6); } +OP( 0x6e, i_outsb ) { write_port(I.regs.w[DW],GetMemB(DS,I.regs.w[IX])); I.regs.w[IX]+= -2 * I.DF + 1; CLK(7); } +OP( 0x6f, i_outsw ) { write_port(I.regs.w[DW],GetMemB(DS,I.regs.w[IX])); write_port((I.regs.w[DW]+1)&0xffff,GetMemB(DS,(I.regs.w[IX]+1)&0xffff)); I.regs.w[IX]+= -4 * I.DF + 2; CLK(7); } + +OP( 0x70, i_jo ) { JMP( OF); CLK(1); } +OP( 0x71, i_jno ) { JMP(!OF); CLK(1); } +OP( 0x72, i_jc ) { JMP( CF); CLK(1); } +OP( 0x73, i_jnc ) { JMP(!CF); CLK(1); } +OP( 0x74, i_jz ) { JMP( ZF); CLK(1); } +OP( 0x75, i_jnz ) { JMP(!ZF); CLK(1); } +OP( 0x76, i_jce ) { JMP(CF || ZF); CLK(1); } +OP( 0x77, i_jnce ) { JMP(!(CF || ZF)); CLK(1); } +OP( 0x78, i_js ) { JMP( SF); CLK(1); } +OP( 0x79, i_jns ) { JMP(!SF); CLK(1); } +OP( 0x7a, i_jp ) { JMP( PF); CLK(1); } +OP( 0x7b, i_jnp ) { JMP(!PF); CLK(1); } +OP( 0x7c, i_jl ) { JMP((SF!=OF)&&(!ZF)); CLK(1); } +OP( 0x7d, i_jnl ) { JMP((ZF)||(SF==OF)); CLK(1); } +OP( 0x7e, i_jle ) { JMP((ZF)||(SF!=OF)); CLK(1); } +OP( 0x7f, i_jnle ) { JMP((SF==OF)&&(!ZF)); CLK(1); } + +OP( 0x80, i_80pre ) { UINT32 dst, src; GetModRM; dst = GetRMByte(ModRM); src = FETCH; + CLKM(3,1) + switch (ModRM & 0x38) { + case 0x00: ADDB; PutbackRMByte(ModRM,dst); break; + case 0x08: ORB; PutbackRMByte(ModRM,dst); break; + case 0x10: src+=CF; ADDB; PutbackRMByte(ModRM,dst); break; + case 0x18: src+=CF; SUBB; PutbackRMByte(ModRM,dst); break; + case 0x20: ANDB; PutbackRMByte(ModRM,dst); break; + case 0x28: SUBB; PutbackRMByte(ModRM,dst); break; + case 0x30: XORB; PutbackRMByte(ModRM,dst); break; + case 0x38: SUBB; break; /* CMP */ + } +} + +OP( 0x81, i_81pre ) { UINT32 dst, src; GetModRM; dst = GetRMWord(ModRM); src = FETCH; src+= (FETCH << 8); + CLKM(3,1) + switch (ModRM & 0x38) { + case 0x00: ADDW; PutbackRMWord(ModRM,dst); break; + case 0x08: ORW; PutbackRMWord(ModRM,dst); break; + case 0x10: src+=CF; ADDW; PutbackRMWord(ModRM,dst); break; + case 0x18: src+=CF; SUBW; PutbackRMWord(ModRM,dst); break; + case 0x20: ANDW; PutbackRMWord(ModRM,dst); break; + case 0x28: SUBW; PutbackRMWord(ModRM,dst); break; + case 0x30: XORW; PutbackRMWord(ModRM,dst); break; + case 0x38: SUBW; break; /* CMP */ + } +} + +OP( 0x82, i_82pre ) { UINT32 dst, src; GetModRM; dst = GetRMByte(ModRM); src = (BYTE)((INT8)FETCH); + CLKM(3,1) + switch (ModRM & 0x38) { + case 0x00: ADDB; PutbackRMByte(ModRM,dst); break; + case 0x08: ORB; PutbackRMByte(ModRM,dst); break; + case 0x10: src+=CF; ADDB; PutbackRMByte(ModRM,dst); break; + case 0x18: src+=CF; SUBB; PutbackRMByte(ModRM,dst); break; + case 0x20: ANDB; PutbackRMByte(ModRM,dst); break; + case 0x28: SUBB; PutbackRMByte(ModRM,dst); break; + case 0x30: XORB; PutbackRMByte(ModRM,dst); break; + case 0x38: SUBB; break; /* CMP */ + } +} + +OP( 0x83, i_83pre ) { UINT32 dst, src; GetModRM; dst = GetRMWord(ModRM); src = (WORD)((INT16)((INT8)FETCH)); + CLKM(3,1) + switch (ModRM & 0x38) { + case 0x00: ADDW; PutbackRMWord(ModRM,dst); break; + case 0x08: ORW; PutbackRMWord(ModRM,dst); break; + case 0x10: src+=CF; ADDW; PutbackRMWord(ModRM,dst); break; + case 0x18: src+=CF; SUBW; PutbackRMWord(ModRM,dst); break; + case 0x20: ANDW; PutbackRMWord(ModRM,dst); break; + case 0x28: SUBW; PutbackRMWord(ModRM,dst); break; + case 0x30: XORW; PutbackRMWord(ModRM,dst); break; + case 0x38: SUBW; break; /* CMP */ + } +} + +OP( 0x84, i_test_br8 ) { DEF_br8; ANDB; CLKM(2,1); } +OP( 0x85, i_test_wr16 ) { DEF_wr16; ANDW; CLKM(2,1); } +OP( 0x86, i_xchg_br8 ) { DEF_br8; RegByte(ModRM)=dst; PutbackRMByte(ModRM,src); CLKM(5,3); } +OP( 0x87, i_xchg_wr16 ) { DEF_wr16; RegWord(ModRM)=dst; PutbackRMWord(ModRM,src); CLKM(5,3); } + +OP( 0x88, i_mov_br8 ) { UINT8 src; GetModRM; src = RegByte(ModRM); PutRMByte(ModRM,src); CLKM(1,1); } +OP( 0x89, i_mov_wr16 ) { UINT16 src; GetModRM; src = RegWord(ModRM); PutRMWord(ModRM,src); CLKM(1,1); } +OP( 0x8a, i_mov_r8b ) { UINT8 src; GetModRM; src = GetRMByte(ModRM); RegByte(ModRM)=src; CLKM(1,1); } +OP( 0x8b, i_mov_r16w ) { UINT16 src; GetModRM; src = GetRMWord(ModRM); RegWord(ModRM)=src; CLKM(1,1); } +OP( 0x8c, i_mov_wsreg ) { GetModRM; PutRMWord(ModRM,I.sregs[(ModRM & 0x38) >> 3]); CLKM(1,1); } +OP( 0x8d, i_lea ) { UINT16 ModRM = FETCH; (void)(*GetEA[ModRM])(); RegWord(ModRM)=EO; CLK(1); } +OP( 0x8e, i_mov_sregw ) { UINT16 src; GetModRM; src = GetRMWord(ModRM); CLKM(3,2); + switch (ModRM & 0x38) { + case 0x00: I.sregs[ES] = src; break; /* mov es,ew */ + case 0x08: I.sregs[CS] = src; break; /* mov cs,ew */ + case 0x10: I.sregs[SS] = src; break; /* mov ss,ew */ + case 0x18: I.sregs[DS] = src; break; /* mov ds,ew */ + default: ; + } + no_interrupt=1; +} +OP( 0x8f, i_popw ) { UINT16 tmp; GetModRM; POP(tmp); PutRMWord(ModRM,tmp); CLKM(3,1); } +OP( 0x90, i_nop ) { CLK(1); + /* Cycle skip for idle loops (0: NOP 1: JMP 0) */ + if (no_interrupt==0 && nec_ICount>0 && (PEEKOP((I.sregs[CS]<<4)+I.ip))==0xeb && (PEEK((I.sregs[CS]<<4)+I.ip+1))==0xfd) + nec_ICount%=15; +} +OP( 0x91, i_xchg_axcx ) { XchgAWReg(CW); CLK(3); } +OP( 0x92, i_xchg_axdx ) { XchgAWReg(DW); CLK(3); } +OP( 0x93, i_xchg_axbx ) { XchgAWReg(BW); CLK(3); } +OP( 0x94, i_xchg_axsp ) { XchgAWReg(SP); CLK(3); } +OP( 0x95, i_xchg_axbp ) { XchgAWReg(BP); CLK(3); } +OP( 0x96, i_xchg_axsi ) { XchgAWReg(IX); CLK(3); } +OP( 0x97, i_xchg_axdi ) { XchgAWReg(IY); CLK(3); } + +OP( 0x98, i_cbw ) { I.regs.b[AH] = (I.regs.b[AL] & 0x80) ? 0xff : 0; CLK(1); } +OP( 0x99, i_cwd ) { I.regs.w[DW] = (I.regs.b[AH] & 0x80) ? 0xffff : 0; CLK(1); } +OP( 0x9a, i_call_far ) { UINT32 tmp, tmp2; FETCHWORD(tmp); FETCHWORD(tmp2); PUSH(I.sregs[CS]); PUSH(I.ip); I.ip = (WORD)tmp; I.sregs[CS] = (WORD)tmp2; CLK(10); } +OP( 0x9b, i_wait ) { ; } +OP( 0x9c, i_pushf ) { PUSH( CompressFlags() ); CLK(2); } +OP( 0x9d, i_popf ) { UINT32 tmp; POP(tmp); ExpandFlags(tmp); CLK(3);} +OP( 0x9e, i_sahf ) { UINT32 tmp = (CompressFlags() & 0xff00) | (I.regs.b[AH] & 0xd5); ExpandFlags(tmp); CLK(4); } +OP( 0x9f, i_lahf ) { I.regs.b[AH] = CompressFlags() & 0xff; CLK(2); } + +OP( 0xa0, i_mov_aldisp ) { UINT32 addr; FETCHWORD(addr); I.regs.b[AL] = GetMemB(DS, addr); CLK(1); } +OP( 0xa1, i_mov_axdisp ) { UINT32 addr; FETCHWORD(addr); I.regs.b[AL] = GetMemB(DS, addr); I.regs.b[AH] = GetMemB(DS, (addr+1)&0xffff); CLK(1); } +OP( 0xa2, i_mov_dispal ) { UINT32 addr; FETCHWORD(addr); PutMemB(DS, addr, I.regs.b[AL]); CLK(1); } +OP( 0xa3, i_mov_dispax ) { UINT32 addr; FETCHWORD(addr); PutMemB(DS, addr, I.regs.b[AL]); PutMemB(DS, (addr+1)&0xffff, I.regs.b[AH]); CLK(1); } +OP( 0xa4, i_movsb ) { UINT32 tmp = GetMemB(DS,I.regs.w[IX]); PutMemB(ES,I.regs.w[IY], tmp); I.regs.w[IY] += -2 * I.DF + 1; I.regs.w[IX] += -2 * I.DF + 1; CLK(5); } +OP( 0xa5, i_movsw ) { UINT32 tmp = GetMemW(DS,I.regs.w[IX]); PutMemW(ES,I.regs.w[IY], tmp); I.regs.w[IY] += -4 * I.DF + 2; I.regs.w[IX] += -4 * I.DF + 2; CLK(5); } +OP( 0xa6, i_cmpsb ) { UINT32 src = GetMemB(ES, I.regs.w[IY]); UINT32 dst = GetMemB(DS, I.regs.w[IX]); SUBB; I.regs.w[IY] += -2 * I.DF + 1; I.regs.w[IX] += -2 * I.DF + 1; CLK(6); } +OP( 0xa7, i_cmpsw ) { UINT32 src = GetMemW(ES, I.regs.w[IY]); UINT32 dst = GetMemW(DS, I.regs.w[IX]); SUBW; I.regs.w[IY] += -4 * I.DF + 2; I.regs.w[IX] += -4 * I.DF + 2; CLK(6); } + +OP( 0xa8, i_test_ald8 ) { DEF_ald8; ANDB; CLK(1); } +OP( 0xa9, i_test_axd16 ) { DEF_axd16; ANDW; CLK(1); } +OP( 0xaa, i_stosb ) { PutMemB(ES,I.regs.w[IY],I.regs.b[AL]); I.regs.w[IY] += -2 * I.DF + 1; CLK(3); } +OP( 0xab, i_stosw ) { PutMemW(ES,I.regs.w[IY],I.regs.w[AW]); I.regs.w[IY] += -4 * I.DF + 2; CLK(3); } +OP( 0xac, i_lodsb ) { I.regs.b[AL] = GetMemB(DS,I.regs.w[IX]); I.regs.w[IX] += -2 * I.DF + 1; CLK(3); } +OP( 0xad, i_lodsw ) { I.regs.w[AW] = GetMemW(DS,I.regs.w[IX]); I.regs.w[IX] += -4 * I.DF + 2; CLK(3); } +OP( 0xae, i_scasb ) { UINT32 src = GetMemB(ES, I.regs.w[IY]); UINT32 dst = I.regs.b[AL]; SUBB; I.regs.w[IY] += -2 * I.DF + 1; CLK(4); } +OP( 0xaf, i_scasw ) { UINT32 src = GetMemW(ES, I.regs.w[IY]); UINT32 dst = I.regs.w[AW]; SUBW; I.regs.w[IY] += -4 * I.DF + 2; CLK(4); } + +OP( 0xb0, i_mov_ald8 ) { I.regs.b[AL] = FETCH; CLK(1); } +OP( 0xb1, i_mov_cld8 ) { I.regs.b[CL] = FETCH; CLK(1); } +OP( 0xb2, i_mov_dld8 ) { I.regs.b[DL] = FETCH; CLK(1); } +OP( 0xb3, i_mov_bld8 ) { I.regs.b[BL] = FETCH; CLK(1); } +OP( 0xb4, i_mov_ahd8 ) { I.regs.b[AH] = FETCH; CLK(1); } +OP( 0xb5, i_mov_chd8 ) { I.regs.b[CH] = FETCH; CLK(1); } +OP( 0xb6, i_mov_dhd8 ) { I.regs.b[DH] = FETCH; CLK(1); } +OP( 0xb7, i_mov_bhd8 ) { I.regs.b[BH] = FETCH; CLK(1); } + +OP( 0xb8, i_mov_axd16 ) { I.regs.b[AL] = FETCH; I.regs.b[AH] = FETCH; CLK(1); } +OP( 0xb9, i_mov_cxd16 ) { I.regs.b[CL] = FETCH; I.regs.b[CH] = FETCH; CLK(1); } +OP( 0xba, i_mov_dxd16 ) { I.regs.b[DL] = FETCH; I.regs.b[DH] = FETCH; CLK(1); } +OP( 0xbb, i_mov_bxd16 ) { I.regs.b[BL] = FETCH; I.regs.b[BH] = FETCH; CLK(1); } +OP( 0xbc, i_mov_spd16 ) { I.regs.b[SPL] = FETCH; I.regs.b[SPH] = FETCH; CLK(1); } +OP( 0xbd, i_mov_bpd16 ) { I.regs.b[BPL] = FETCH; I.regs.b[BPH] = FETCH; CLK(1); } +OP( 0xbe, i_mov_sid16 ) { I.regs.b[IXL] = FETCH; I.regs.b[IXH] = FETCH; CLK(1); } +OP( 0xbf, i_mov_did16 ) { I.regs.b[IYL] = FETCH; I.regs.b[IYH] = FETCH; CLK(1); } + +OP( 0xc0, i_rotshft_bd8 ) { + UINT32 src, dst; UINT8 c; + GetModRM; src = (unsigned)GetRMByte(ModRM); dst=src; + c=FETCH; + c&=0x1f; + CLKM(5,3); + if (c) switch (ModRM & 0x38) { + case 0x00: do { ROL_BYTE; c--; } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break; + case 0x08: do { ROR_BYTE; c--; } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break; + case 0x10: do { ROLC_BYTE; c--; } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break; + case 0x18: do { RORC_BYTE; c--; } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break; + case 0x20: SHL_BYTE(c); I.AuxVal = 1; break;// + case 0x28: SHR_BYTE(c); I.AuxVal = 1; break;// + case 0x30: break; + case 0x38: SHRA_BYTE(c); break; + } +} + +OP( 0xc1, i_rotshft_wd8 ) { + UINT32 src, dst; UINT8 c; + GetModRM; src = (unsigned)GetRMWord(ModRM); dst=src; + c=FETCH; + c&=0x1f; + CLKM(5,3); + if (c) switch (ModRM & 0x38) { + case 0x00: do { ROL_WORD; c--; } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break; + case 0x08: do { ROR_WORD; c--; } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break; + case 0x10: do { ROLC_WORD; c--; } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break; + case 0x18: do { RORC_WORD; c--; } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break; + case 0x20: SHL_WORD(c); I.AuxVal = 1; break; + case 0x28: SHR_WORD(c); I.AuxVal = 1; break; + case 0x30: break; + case 0x38: SHRA_WORD(c); break; + } +} + +OP( 0xc2, i_ret_d16 ) { UINT32 count = FETCH; count += FETCH << 8; POP(I.ip); I.regs.w[SP]+=count; CLK(6); } +OP( 0xc3, i_ret ) { POP(I.ip); CLK(6); } +OP( 0xc4, i_les_dw ) { GetModRM; WORD tmp = GetRMWord(ModRM); RegWord(ModRM)=tmp; I.sregs[ES] = GetnextRMWord; CLK(6); } +OP( 0xc5, i_lds_dw ) { GetModRM; WORD tmp = GetRMWord(ModRM); RegWord(ModRM)=tmp; I.sregs[DS] = GetnextRMWord; CLK(6); } +OP( 0xc6, i_mov_bd8 ) { GetModRM; PutImmRMByte(ModRM); CLK(1); } +OP( 0xc7, i_mov_wd16 ) { GetModRM; PutImmRMWord(ModRM); CLK(1); } + +OP( 0xc8, i_enter ) { + UINT32 nb = FETCH; + UINT32 i,level; + + CLK(19); + nb += FETCH << 8; + level = FETCH; + PUSH(I.regs.w[BP]); + I.regs.w[BP]=I.regs.w[SP]; + I.regs.w[SP] -= nb; + for (i=1;i0); PutbackRMByte(ModRM,(BYTE)dst); break; + case 0x08: do { ROR_BYTE; c--; CLK(1); } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break; + case 0x10: do { ROLC_BYTE; c--; CLK(1); } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break; + case 0x18: do { RORC_BYTE; c--; CLK(1); } while (c>0); PutbackRMByte(ModRM,(BYTE)dst); break; + case 0x20: SHL_BYTE(c); I.AuxVal = 1; break; + case 0x28: SHR_BYTE(c); I.AuxVal = 1;break; + case 0x30: break; + case 0x38: SHRA_BYTE(c); break; + } +} + +OP( 0xd3, i_rotshft_wcl ) { + UINT32 src, dst; UINT8 c; GetModRM; src = (UINT32)GetRMWord(ModRM); dst=src; + c=I.regs.b[CL]; + c&=0x1f; + CLKM(5,3); + if (c) switch (ModRM & 0x38) { + case 0x00: do { ROL_WORD; c--; CLK(1); } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break; + case 0x08: do { ROR_WORD; c--; CLK(1); } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break; + case 0x10: do { ROLC_WORD; c--; CLK(1); } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break; + case 0x18: do { RORC_WORD; c--; CLK(1); } while (c>0); PutbackRMWord(ModRM,(WORD)dst); break; + case 0x20: SHL_WORD(c); I.AuxVal = 1; break; + case 0x28: SHR_WORD(c); I.AuxVal = 1; break; + case 0x30: break; + case 0x38: SHRA_WORD(c); break; + } +} + +OP( 0xd4, i_aam ) { UINT32 mult=FETCH; mult=0; I.regs.b[AH] = I.regs.b[AL] / 10; I.regs.b[AL] %= 10; SetSZPF_Word(I.regs.w[AW]); CLK(17); } +OP( 0xd5, i_aad ) { UINT32 mult=FETCH; mult=0; I.regs.b[AL] = I.regs.b[AH] * 10 + I.regs.b[AL]; I.regs.b[AH] = 0; SetSZPF_Byte(I.regs.b[AL]); CLK(6); } +OP( 0xd6, i_setalc ) { I.regs.b[AL] = (CF)?0xff:0x00; CLK(3); } /* nop at V30MZ? */ +OP( 0xd7, i_trans ) { UINT32 dest = (I.regs.w[BW]+I.regs.b[AL])&0xffff; I.regs.b[AL] = GetMemB(DS, dest); CLK(5); } +OP( 0xd8, i_fpo ) { GetModRM; CLK(3); } /* nop at V30MZ? */ + +OP( 0xe0, i_loopne ) { INT8 disp = (INT8)FETCH; I.regs.w[CW]--; if (!ZF && I.regs.w[CW]) { I.ip = (WORD)(I.ip+disp); CLK(6); } else CLK(3); } +OP( 0xe1, i_loope ) { INT8 disp = (INT8)FETCH; I.regs.w[CW]--; if ( ZF && I.regs.w[CW]) { I.ip = (WORD)(I.ip+disp); CLK(6); } else CLK(3); } +OP( 0xe2, i_loop ) { INT8 disp = (INT8)FETCH; I.regs.w[CW]--; if (I.regs.w[CW]) { I.ip = (WORD)(I.ip+disp); CLK(5); } else CLK(2); } +OP( 0xe3, i_jcxz ) { INT8 disp = (INT8)FETCH; if (I.regs.w[CW] == 0) { I.ip = (WORD)(I.ip+disp); CLK(4); } else CLK(1); } +OP( 0xe4, i_inal ) { UINT8 port = FETCH; I.regs.b[AL] = read_port(port); CLK(6); } +OP( 0xe5, i_inax ) { UINT8 port = FETCH; I.regs.b[AL] = read_port(port); I.regs.b[AH] = read_port(port+1); CLK(6); } +OP( 0xe6, i_outal ) { UINT8 port = FETCH; write_port(port, I.regs.b[AL]); CLK(6); } +OP( 0xe7, i_outax ) { UINT8 port = FETCH; write_port(port, I.regs.b[AL]); write_port(port+1, I.regs.b[AH]); CLK(6); } + +OP( 0xe8, i_call_d16 ) { UINT32 tmp; FETCHWORD(tmp); PUSH(I.ip); I.ip = (WORD)(I.ip+(INT16)tmp); CLK(5); } +OP( 0xe9, i_jmp_d16 ) { UINT32 tmp; FETCHWORD(tmp); I.ip = (WORD)(I.ip+(INT16)tmp); CLK(4); } +OP( 0xea, i_jmp_far ) { UINT32 tmp,tmp1; FETCHWORD(tmp); FETCHWORD(tmp1); I.sregs[CS] = (WORD)tmp1; I.ip = (WORD)tmp; CLK(7); } +OP( 0xeb, i_jmp_d8 ) { int tmp = (int)((INT8)FETCH); CLK(4); + if (tmp==-2 && no_interrupt==0 && nec_ICount>0) nec_ICount%=12; /* cycle skip */ + I.ip = (WORD)(I.ip+tmp); +} +OP( 0xec, i_inaldx ) { I.regs.b[AL] = read_port(I.regs.w[DW]); CLK(6);} +OP( 0xed, i_inaxdx ) { UINT32 port = I.regs.w[DW]; I.regs.b[AL] = read_port(port); I.regs.b[AH] = read_port(port+1); CLK(6); } +OP( 0xee, i_outdxal ) { write_port(I.regs.w[DW], I.regs.b[AL]); CLK(6); } +OP( 0xef, i_outdxax ) { UINT32 port = I.regs.w[DW]; write_port(port, I.regs.b[AL]); write_port(port+1, I.regs.b[AH]); CLK(6); } + +OP( 0xf0, i_lock ) { no_interrupt=1; CLK(1); } +#define THROUGH \ + if(nec_ICount<0){ \ + if(seg_prefix) \ + I.ip-=(UINT16)3; \ + else \ + I.ip-=(UINT16)2; \ + break;} + +OP( 0xf2, i_repne ) { UINT32 next = FETCHOP; UINT16 c = I.regs.w[CW]; + switch(next) { /* Segments */ + case 0x26: seg_prefix=TRUE; prefix_base=I.sregs[ES]<<4; next = FETCHOP; CLK(2); break; + case 0x2e: seg_prefix=TRUE; prefix_base=I.sregs[CS]<<4; next = FETCHOP; CLK(2); break; + case 0x36: seg_prefix=TRUE; prefix_base=I.sregs[SS]<<4; next = FETCHOP; CLK(2); break; + case 0x3e: seg_prefix=TRUE; prefix_base=I.sregs[DS]<<4; next = FETCHOP; CLK(2); break; + } + + switch(next) { + case 0x6c: CLK(2); if (c) do { i_insb(); c--; } while (c>0); I.regs.w[CW]=c; break; + case 0x6d: CLK(2); if (c) do { i_insw(); c--; } while (c>0); I.regs.w[CW]=c; break; + case 0x6e: CLK(2); if (c) do { i_outsb(); c--; } while (c>0); I.regs.w[CW]=c; break; + case 0x6f: CLK(2); if (c) do { i_outsw(); c--; } while (c>0); I.regs.w[CW]=c; break; + case 0xa4: CLK(2); if (c) do { i_movsb(); c--; } while (c>0); I.regs.w[CW]=c; break; + case 0xa5: CLK(2); if (c) do { i_movsw(); c--; } while (c>0); I.regs.w[CW]=c; break; + case 0xa6: CLK(5); if (c) do { THROUGH; i_cmpsb(); c--; CLK(3); } while (c>0 && ZF==0); I.regs.w[CW]=c; break; + case 0xa7: CLK(5); if (c) do { THROUGH; i_cmpsw(); c--; CLK(3); } while (c>0 && ZF==0); I.regs.w[CW]=c; break; + case 0xaa: CLK(2); if (c) do { i_stosb(); c--; } while (c>0); I.regs.w[CW]=c; break; + case 0xab: CLK(2); if (c) do { i_stosw(); c--; } while (c>0); I.regs.w[CW]=c; break; + case 0xac: CLK(2); if (c) do { i_lodsb(); c--; } while (c>0); I.regs.w[CW]=c; break; + case 0xad: CLK(2); if (c) do { i_lodsw(); c--; } while (c>0); I.regs.w[CW]=c; break; + case 0xae: CLK(5); if (c) do { THROUGH; i_scasb(); c--; CLK(5); } while (c>0 && ZF==0); I.regs.w[CW]=c; break; + case 0xaf: CLK(5); if (c) do { THROUGH; i_scasw(); c--; CLK(5); } while (c>0 && ZF==0); I.regs.w[CW]=c; break; + default: nec_instruction[next](); + } + seg_prefix=FALSE; +} +OP( 0xf3, i_repe ) { UINT32 next = FETCHOP; UINT16 c = I.regs.w[CW]; + switch(next) { /* Segments */ + case 0x26: seg_prefix=TRUE; prefix_base=I.sregs[ES]<<4; next = FETCHOP; CLK(2); break; + case 0x2e: seg_prefix=TRUE; prefix_base=I.sregs[CS]<<4; next = FETCHOP; CLK(2); break; + case 0x36: seg_prefix=TRUE; prefix_base=I.sregs[SS]<<4; next = FETCHOP; CLK(2); break; + case 0x3e: seg_prefix=TRUE; prefix_base=I.sregs[DS]<<4; next = FETCHOP; CLK(2); break; + } + + switch(next) { + case 0x6c: CLK(5); if (c) do { THROUGH; i_insb(); c--; CLK( 0); } while (c>0); I.regs.w[CW]=c; break; + case 0x6d: CLK(5); if (c) do { THROUGH; i_insw(); c--; CLK( 0); } while (c>0); I.regs.w[CW]=c; break; + case 0x6e: CLK(5); if (c) do { THROUGH; i_outsb(); c--; CLK(-1); } while (c>0); I.regs.w[CW]=c; break; + case 0x6f: CLK(5); if (c) do { THROUGH; i_outsw(); c--; CLK(-1); } while (c>0); I.regs.w[CW]=c; break; + case 0xa4: CLK(5); if (c) do { THROUGH; i_movsb(); c--; CLK( 2); } while (c>0); I.regs.w[CW]=c; break; + case 0xa5: CLK(5); if (c) do { THROUGH; i_movsw(); c--; CLK( 2); } while (c>0); I.regs.w[CW]=c; break; + case 0xa6: CLK(5); if (c) do { THROUGH; i_cmpsb(); c--; CLK( 4); } while (c>0 && ZF==1); I.regs.w[CW]=c; break; + case 0xa7: CLK(5); if (c) do { THROUGH; i_cmpsw(); c--; CLK( 4); } while (c>0 && ZF==1); I.regs.w[CW]=c; break; + case 0xaa: CLK(5); if (c) do { THROUGH; i_stosb(); c--; CLK( 3); } while (c>0); I.regs.w[CW]=c; break; + case 0xab: CLK(5); if (c) do { THROUGH; i_stosw(); c--; CLK( 3); } while (c>0); I.regs.w[CW]=c; break; + case 0xac: CLK(5); if (c) do { THROUGH; i_lodsb(); c--; CLK( 3); } while (c>0); I.regs.w[CW]=c; break; + case 0xad: CLK(5); if (c) do { THROUGH; i_lodsw(); c--; CLK( 3); } while (c>0); I.regs.w[CW]=c; break; + case 0xae: CLK(5); if (c) do { THROUGH; i_scasb(); c--; CLK( 4); } while (c>0 && ZF==1); I.regs.w[CW]=c; break; + case 0xaf: CLK(5); if (c) do { THROUGH; i_scasw(); c--; CLK( 4); } while (c>0 && ZF==1); I.regs.w[CW]=c; break; + default: nec_instruction[next](); + } + seg_prefix=FALSE; +} +OP( 0xf4, i_hlt ) { nec_ICount=0; } + + + + + +OP( 0xf5, i_cmc ) { I.CarryVal = !CF; CLK(4); } +OP( 0xf6, i_f6pre ) { UINT32 tmp; UINT32 uresult,uresult2; INT32 result,result2; + GetModRM; tmp = GetRMByte(ModRM); + switch (ModRM & 0x38) { + case 0x00: tmp &= FETCH; I.CarryVal = I.OverVal = I.AuxVal=0; SetSZPF_Byte(tmp); CLKM(2,1); break; /* TEST */ + case 0x08: break; + case 0x10: PutbackRMByte(ModRM,~tmp); CLKM(3,1); break; /* NOT */ + + case 0x18: I.CarryVal=(tmp!=0);tmp=(~tmp)+1; SetSZPF_Byte(tmp); PutbackRMByte(ModRM,tmp&0xff); CLKM(3,1); break; /* NEG */ + case 0x20: uresult = I.regs.b[AL]*tmp; I.regs.w[AW]=(WORD)uresult; I.CarryVal=I.OverVal=(I.regs.b[AH]!=0); CLKM(4,3); break; /* MULU */ + case 0x28: result = (INT16)((INT8)I.regs.b[AL])*(INT16)((INT8)tmp); I.regs.w[AW]=(WORD)result; I.CarryVal=I.OverVal=(I.regs.b[AH]!=0); CLKM(4,3); break; /* MUL */ + case 0x30: if (tmp) { DIVUB; } else nec_interrupt(0,0); CLKM(16,15); break; + case 0x38: if (tmp) { DIVB; } else nec_interrupt(0,0); CLKM(18,17); break; + } +} + +OP( 0xf7, i_f7pre ) { UINT32 tmp,tmp2; UINT32 uresult,uresult2; INT32 result,result2; + GetModRM; tmp = GetRMWord(ModRM); + switch (ModRM & 0x38) { + case 0x00: FETCHWORD(tmp2); tmp &= tmp2; I.CarryVal = I.OverVal = I.AuxVal=0; SetSZPF_Word(tmp); CLKM(2,1); break; /* TEST */ + case 0x08: break; + case 0x10: PutbackRMWord(ModRM,~tmp); CLKM(3,1); break; /* NOT */ + case 0x18: I.CarryVal=(tmp!=0); tmp=(~tmp)+1; SetSZPF_Word(tmp); PutbackRMWord(ModRM,tmp&0xffff); CLKM(3,1); break; /* NEG */ + case 0x20: uresult = I.regs.w[AW]*tmp; I.regs.w[AW]=uresult&0xffff; I.regs.w[DW]=((UINT32)uresult)>>16; I.CarryVal=I.OverVal=(I.regs.w[DW]!=0); CLKM(4,3); break; /* MULU */ + case 0x28: result = (INT32)((INT16)I.regs.w[AW])*(INT32)((INT16)tmp); I.regs.w[AW]=result&0xffff; I.regs.w[DW]=result>>16; I.CarryVal=I.OverVal=(I.regs.w[DW]!=0); CLKM(4,3); break; /* MUL */ + case 0x30: if (tmp) { DIVUW; } else nec_interrupt(0,0); CLKM(24,23); break; + case 0x38: if (tmp) { DIVW; } else nec_interrupt(0,0); CLKM(25,24); break; + } +} + +OP( 0xf8, i_clc ) { I.CarryVal = 0; CLK(4); } +OP( 0xf9, i_stc ) { I.CarryVal = 1; CLK(4); } +OP( 0xfa, i_di ) { SetIF(0); CLK(4); } +OP( 0xfb, i_ei ) { SetIF(1); CLK(4); } +OP( 0xfc, i_cld ) { SetDF(0); CLK(4); } +OP( 0xfd, i_std ) { SetDF(1); CLK(4); } +OP( 0xfe, i_fepre ) { UINT32 tmp, tmp1; GetModRM; tmp=GetRMByte(ModRM); + switch(ModRM & 0x38) { + case 0x00: tmp1 = tmp+1; I.OverVal = (tmp==0x7f); SetAF(tmp1,tmp,1); SetSZPF_Byte(tmp1); PutbackRMByte(ModRM,(BYTE)tmp1); CLKM(3,1); break; /* INC */ + case 0x08: tmp1 = tmp-1; I.OverVal = (tmp==0x80); SetAF(tmp1,tmp,1); SetSZPF_Byte(tmp1); PutbackRMByte(ModRM,(BYTE)tmp1); CLKM(3,1); break; /* DEC */ + } +} +OP( 0xff, i_ffpre ) { UINT32 tmp, tmp1; GetModRM; tmp=GetRMWord(ModRM); + switch(ModRM & 0x38) { + case 0x00: tmp1 = tmp+1; I.OverVal = (tmp==0x7fff); SetAF(tmp1,tmp,1); SetSZPF_Word(tmp1); PutbackRMWord(ModRM,(WORD)tmp1); CLKM(3,1); break; /* INC */ + case 0x08: tmp1 = tmp-1; I.OverVal = (tmp==0x8000); SetAF(tmp1,tmp,1); SetSZPF_Word(tmp1); PutbackRMWord(ModRM,(WORD)tmp1); CLKM(3,1); break; /* DEC */ + case 0x10: PUSH(I.ip); I.ip = (WORD)tmp; CLKM(6,5); break; /* CALL */ + case 0x18: tmp1 = I.sregs[CS]; I.sregs[CS] = GetnextRMWord; PUSH(tmp1); PUSH(I.ip); I.ip = tmp; CLKM(12,1); break; /* CALL FAR */ + case 0x20: I.ip = tmp; CLKM(5,4); break; /* JMP */ + case 0x28: I.ip = tmp; I.sregs[CS] = GetnextRMWord; CLKM(10,1); break; /* JMP FAR */ + case 0x30: PUSH(tmp); CLKM(2,1); break; + default: ; + } +} + +static void i_invalid(void) +{ + CLK(10); +} + +/*****************************************************************************/ + + +unsigned nec_get_reg(int regnum) +{ + switch( regnum ) + { + case NEC_IP: return I.ip; + case NEC_SP: return I.regs.w[SP]; + case NEC_FLAGS: return CompressFlags(); + case NEC_AW: return I.regs.w[AW]; + case NEC_CW: return I.regs.w[CW]; + case NEC_DW: return I.regs.w[DW]; + case NEC_BW: return I.regs.w[BW]; + case NEC_BP: return I.regs.w[BP]; + case NEC_IX: return I.regs.w[IX]; + case NEC_IY: return I.regs.w[IY]; + case NEC_ES: return I.sregs[ES]; + case NEC_CS: return I.sregs[CS]; + case NEC_SS: return I.sregs[SS]; + case NEC_DS: return I.sregs[DS]; + case NEC_VECTOR: return I.int_vector; + case NEC_PENDING: return I.pending_irq; + case NEC_NMI_STATE: return I.nmi_state; + case NEC_IRQ_STATE: return I.irq_state; + } + return 0; +} + +void nec_set_irq_line(int irqline, int state); + +void nec_set_reg(int regnum, unsigned val) +{ + switch( regnum ) + { + case NEC_IP: I.ip = val; break; + case NEC_SP: I.regs.w[SP] = val; break; + case NEC_FLAGS: ExpandFlags(val); break; + case NEC_AW: I.regs.w[AW] = val; break; + case NEC_CW: I.regs.w[CW] = val; break; + case NEC_DW: I.regs.w[DW] = val; break; + case NEC_BW: I.regs.w[BW] = val; break; + case NEC_BP: I.regs.w[BP] = val; break; + case NEC_IX: I.regs.w[IX] = val; break; + case NEC_IY: I.regs.w[IY] = val; break; + case NEC_ES: I.sregs[ES] = val; break; + case NEC_CS: I.sregs[CS] = val; break; + case NEC_SS: I.sregs[SS] = val; break; + case NEC_DS: I.sregs[DS] = val; break; + case NEC_VECTOR: I.int_vector = val; break; + } +} + + +int nec_execute(int cycles) +{ + + + nec_ICount=cycles; +// cpu_type=V30; + + while(nec_ICount>0) { + + nec_instruction[FETCHOP](); +// nec_ICount++; + } + + return cycles - nec_ICount; +} + diff --git a/oswan/source/nec/nec.h b/oswan/source/nec/nec.h new file mode 100644 index 0000000..f81e6f4 --- /dev/null +++ b/oswan/source/nec/nec.h @@ -0,0 +1,390 @@ +BYTE cpu_readport(BYTE); +void cpu_writeport(DWORD,BYTE); +#define cpu_readop cpu_readmem20 +#define cpu_readop_arg cpu_readmem20 +void cpu_writemem20(DWORD,BYTE); +BYTE cpu_readmem20(DWORD); + +typedef enum { ES, CS, SS, DS } SREGS; +typedef enum { AW, CW, DW, BW, SP, BP, IX, IY } WREGS; +typedef enum { AL,AH,CL,CH,DL,DH,BL,BH,SPL,SPH,BPL,BPH,IXL,IXH,IYL,IYH } BREGS; + +#pragma pack(1) +typedef union +{ /* eight general registers */ + UINT16 w[8]; /* viewed as 16 bits registers */ + UINT8 b[16]; /* or as 8 bit registers */ +} necbasicregs; +typedef struct +{ + necbasicregs regs; + UINT16 sregs[4]; + + UINT16 ip; + + INT32 SignVal; + UINT32 AuxVal, OverVal, ZeroVal, CarryVal, ParityVal; /* 0 or non-0 valued flags */ + UINT8 TF, IF, DF, MF; /* 0 or 1 valued flags */ /* OB[19.07.99] added Mode Flag V30 */ + UINT32 int_vector; + UINT32 pending_irq; + UINT32 nmi_state; + UINT32 irq_state; + int (*irq_callback)(int irqline); +} nec_Regs; +#pragma pack() + +#define NEC_NMI_INT_VECTOR 2 + +/* Cpu types, steps of 8 to help the cycle count calculation */ +#define V33 0 +#define V30 8 +#define V20 16 + +#ifndef FALSE +#define FALSE 0 +#define TRUE 1 +#endif + +/* parameter x = result, y = source 1, z = source 2 */ + +#define SetTF(x) (I.TF = (x)) +#define SetIF(x) (I.IF = (x)) +#define SetDF(x) (I.DF = (x)) +#define SetMD(x) (I.MF = (x)) /* OB [19.07.99] Mode Flag V30 */ + +#define SetCFB(x) (I.CarryVal = (x) & 0x100) +#define SetCFW(x) (I.CarryVal = (x) & 0x10000) + +#define SetAF(x,y,z) (I.AuxVal = ((x) ^ ((y) ^ (z))) & 0x10) + + + + +#define SetSF(x) (I.SignVal = (x)) +#define SetZF(x) (I.ZeroVal = (x)) +#define SetPF(x) (I.ParityVal = (x)) + +#define SetSZPF_Byte(x) (I.SignVal=I.ZeroVal=I.ParityVal=(INT8)(x)) +#define SetSZPF_Word(x) (I.SignVal=I.ZeroVal=I.ParityVal=(INT16)(x)) + +#define SetOFW_Add(x,y,z) (I.OverVal = ((x) ^ (y)) & ((x) ^ (z)) & 0x8000) +#define SetOFB_Add(x,y,z) (I.OverVal = ((x) ^ (y)) & ((x) ^ (z)) & 0x80) +#define SetOFW_Sub(x,y,z) (I.OverVal = ((z) ^ (y)) & ((z) ^ (x)) & 0x8000) +#define SetOFB_Sub(x,y,z) (I.OverVal = ((z) ^ (y)) & ((z) ^ (x)) & 0x80) + +#define ADDB { UINT32 res=dst+src; SetCFB(res); SetOFB_Add(res,src,dst); SetAF(res,src,dst); SetSZPF_Byte(res); dst=(BYTE)res; } +#define ADDW { UINT32 res=dst+src; SetCFW(res); SetOFW_Add(res,src,dst); SetAF(res,src,dst); SetSZPF_Word(res); dst=(WORD)res; } + +#define SUBB { UINT32 res=dst-src; SetCFB(res); SetOFB_Sub(res,src,dst); SetAF(res,src,dst); SetSZPF_Byte(res); dst=(BYTE)res; } +#define SUBW { UINT32 res=dst-src; SetCFW(res); SetOFW_Sub(res,src,dst); SetAF(res,src,dst); SetSZPF_Word(res); dst=(WORD)res; } + +#define ORB dst|=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Byte(dst) +#define ORW dst|=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Word(dst) + +#define ANDB dst&=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Byte(dst) +#define ANDW dst&=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Word(dst) + +#define XORB dst^=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Byte(dst) +#define XORW dst^=src; I.CarryVal=I.OverVal=I.AuxVal=0; SetSZPF_Word(dst) + +#define CF (I.CarryVal!=0) +#define SF (I.SignVal<0) +#define ZF (I.ZeroVal==0) +#define PF parity_table[(BYTE)I.ParityVal] +#define AF (I.AuxVal!=0) +#define OF (I.OverVal!=0) +#define MD (I.MF!=0) + +/************************************************************************/ + +#define SegBase(Seg) (I.sregs[Seg] << 4) + +#define DefaultBase(Seg) ((seg_prefix && (Seg==DS || Seg==SS)) ? prefix_base : I.sregs[Seg] << 4) + +#define GetMemB(Seg,Off) (/*nec_ICount-=((Off)&1)?1:0,*/ (UINT8)cpu_readmem20((DefaultBase(Seg)+(Off)))) +#define GetMemW(Seg,Off) (/*nec_ICount-=((Off)&1)?1:0,*/ (UINT16) cpu_readmem20((DefaultBase(Seg)+(Off))) + (cpu_readmem20((DefaultBase(Seg)+((Off)+1)))<<8) ) + +#define PutMemB(Seg,Off,x) { /*nec_ICount-=((Off)&1)?1:0*/; cpu_writemem20((DefaultBase(Seg)+(Off)),(x)); } +#define PutMemW(Seg,Off,x) { /*nec_ICount-=((Off)&1)?1:0*/; PutMemB(Seg,Off,(x)&0xff); PutMemB(Seg,(Off)+1,(BYTE)((x)>>8)); } + +/* Todo: Remove these later - plus readword could overflow */ +#define ReadByte(ea) (/*nec_ICount-=((ea)&1)?1:0,*/ (BYTE)cpu_readmem20((ea))) +#define ReadWord(ea) (/*nec_ICount-=((ea)&1)?1:0,*/ cpu_readmem20((ea))+(cpu_readmem20(((ea)+1))<<8)) +#define WriteByte(ea,val) { /*nec_ICount-=((ea)&1)?1:0*/; cpu_writemem20((ea),val); } +#define WriteWord(ea,val) { /*nec_ICount-=((ea)&1)?1:0*/; cpu_writemem20((ea),(BYTE)(val)); cpu_writemem20(((ea)+1),(val)>>8); } + +#define read_port(port) cpu_readport(port) +#define write_port(port,val) cpu_writeport(port,val) + +#define FETCH (cpu_readop_arg((I.sregs[CS]<<4)+I.ip++)) +#define FETCHOP (cpu_readop((I.sregs[CS]<<4)+I.ip++)) +#define FETCHWORD(var) { var=cpu_readop_arg((((I.sregs[CS]<<4)+I.ip)))+(cpu_readop_arg((((I.sregs[CS]<<4)+I.ip+1)))<<8); I.ip+=2; } +#define PUSH(val) { I.regs.w[SP]-=2; WriteWord((((I.sregs[SS]<<4)+I.regs.w[SP])),val); } +#define POP(var) { var = ReadWord((((I.sregs[SS]<<4)+I.regs.w[SP]))); I.regs.w[SP]+=2; } +#define PEEK(addr) ((BYTE)cpu_readop_arg(addr)) +#define PEEKOP(addr) ((BYTE)cpu_readop(addr)) + +#define GetModRM UINT32 ModRM=cpu_readop_arg((I.sregs[CS]<<4)+I.ip++) + +/* Cycle count macros: + CLK - cycle count is the same on all processors + CLKS - cycle count differs between processors, list all counts + CLKW - cycle count for word read/write differs for odd/even source/destination address + CLKM - cycle count for reg/mem instructions + CLKR - cycle count for reg/mem instructions with different counts for odd/even addresses + + + Prefetch & buswait time is not emulated. + Extra cycles for PUSH'ing or POP'ing registers to odd addresses is not emulated. + +#define CLK(all) nec_ICount-=all +#define CLKS(v20,v30,v33) { const UINT32 ccount=(v20<<16)|(v30<<8)|v33; nec_ICount-=(ccount>>cpu_type)&0x7f; } +#define CLKW(v20o,v30o,v33o,v20e,v30e,v33e) { const UINT32 ocount=(v20o<<16)|(v30o<<8)|v33o, ecount=(v20e<<16)|(v30e<<8)|v33e; nec_ICount-=(I.ip&1)?((ocount>>cpu_type)&0x7f):((ecount>>cpu_type)&0x7f); } +#define CLKM(v20,v30,v33,v20m,v30m,v33m) { const UINT32 ccount=(v20<<16)|(v30<<8)|v33, mcount=(v20m<<16)|(v30m<<8)|v33m; nec_ICount-=( ModRM >=0xc0 )?((ccount>>cpu_type)&0x7f):((mcount>>cpu_type)&0x7f); } +#define CLKR(v20o,v30o,v33o,v20e,v30e,v33e,vall) { const UINT32 ocount=(v20o<<16)|(v30o<<8)|v33o, ecount=(v20e<<16)|(v30e<<8)|v33e; if (ModRM >=0xc0) nec_ICount-=vall; else nec_ICount-=(I.ip&1)?((ocount>>cpu_type)&0x7f):((ecount>>cpu_type)&0x7f); } +*/ +#define CLKS(v20,v30,v33) { const UINT32 ccount=(v20<<16)|(v30<<8)|v33; nec_ICount-=(ccount>>cpu_type)&0x7f; } + +#define CLK(all) nec_ICount-=all +#define CLKW(v30MZo,v30MZe) { nec_ICount-=(I.ip&1)?v30MZo:v30MZe; } +#define CLKM(v30MZm,v30MZ) { nec_ICount-=( ModRM >=0xc0 )?v30MZ:v30MZm; } +#define CLKR(v30MZo,v30MZe,vall) { if (ModRM >=0xc0) nec_ICount-=vall; else nec_ICount-=(I.ip&1)?v30MZo:v30MZe; } + +#define CompressFlags() (WORD)(CF | (PF << 2) | (AF << 4) | (ZF << 6) \ + | (SF << 7) | (I.TF << 8) | (I.IF << 9) \ + | (I.DF << 10) | (OF << 11)) + + +#define ExpandFlags(f) \ +{ \ + I.CarryVal = (f) & 1; \ + I.ParityVal = !((f) & 4); \ + I.AuxVal = (f) & 16; \ + I.ZeroVal = !((f) & 64); \ + I.SignVal = (f) & 128 ? -1 : 0; \ + I.TF = ((f) & 256) == 256; \ + I.IF = ((f) & 512) == 512; \ + I.DF = ((f) & 1024) == 1024; \ + I.OverVal = (f) & 2048; \ + I.MF = ((f) & 0x8000) == 0x8000; \ +} + + + +#define IncWordReg(Reg) \ + unsigned tmp = (unsigned)I.regs.w[Reg]; \ + unsigned tmp1 = tmp+1; \ + I.OverVal = (tmp == 0x7fff); \ + SetAF(tmp1,tmp,1); \ + SetSZPF_Word(tmp1); \ + I.regs.w[Reg]=tmp1 + + + +#define DecWordReg(Reg) \ + unsigned tmp = (unsigned)I.regs.w[Reg]; \ + unsigned tmp1 = tmp-1; \ + I.OverVal = (tmp == 0x8000); \ + SetAF(tmp1,tmp,1); \ + SetSZPF_Word(tmp1); \ + I.regs.w[Reg]=tmp1 + +#define JMP(flag) \ + int tmp = (int)((INT8)FETCH); \ + if (flag) \ + { \ + I.ip = (WORD)(I.ip+tmp); \ + nec_ICount-=3; \ + return; \ + } + +#define ADJ4(param1,param2) \ + if (AF || ((I.regs.b[AL] & 0xf) > 9)) \ + { \ + int tmp; \ + I.regs.b[AL] = tmp = I.regs.b[AL] + param1; \ + I.AuxVal = 1; \ + } \ + if (CF || (I.regs.b[AL] > 0x9f)) \ + { \ + I.regs.b[AL] += param2; \ + I.CarryVal = 1; \ + } \ + SetSZPF_Byte(I.regs.b[AL]) + +#define ADJB(param1,param2) \ + if (AF || ((I.regs.b[AL] & 0xf) > 9)) \ + { \ + I.regs.b[AL] += param1; \ + I.regs.b[AH] += param2; \ + I.AuxVal = 1; \ + I.CarryVal = 1; \ + } \ + else \ + { \ + I.AuxVal = 0; \ + I.CarryVal = 0; \ + } \ + I.regs.b[AL] &= 0x0F + +#define BITOP_BYTE \ + ModRM = FETCH; \ + if (ModRM >= 0xc0) { \ + tmp=I.regs.b[Mod_RM.RM.b[ModRM]]; \ + } \ + else { \ + (*GetEA[ModRM])(); \ + tmp=ReadByte(EA); \ + } + +#define BITOP_WORD \ + ModRM = FETCH; \ + if (ModRM >= 0xc0) { \ + tmp=I.regs.w[Mod_RM.RM.w[ModRM]]; \ + } \ + else { \ + (*GetEA[ModRM])(); \ + tmp=ReadWord(EA); \ + } + +#define BIT_NOT \ + if (tmp & (1<> 1)+(CF<<7) +#define ROR_WORD I.CarryVal = dst & 0x1; dst = (dst >> 1)+(CF<<15) +#define ROLC_BYTE dst = (dst << 1) + CF; SetCFB(dst) +#define ROLC_WORD dst = (dst << 1) + CF; SetCFW(dst) +#define RORC_BYTE dst = (CF<<8)+dst; I.CarryVal = dst & 0x01; dst >>= 1 +#define RORC_WORD dst = (CF<<16)+dst; I.CarryVal = dst & 0x01; dst >>= 1 +#define SHL_BYTE(c) dst <<= c; SetCFB(dst); SetSZPF_Byte(dst); PutbackRMByte(ModRM,(BYTE)dst) +#define SHL_WORD(c) dst <<= c; SetCFW(dst); SetSZPF_Word(dst); PutbackRMWord(ModRM,(WORD)dst) +#define SHR_BYTE(c) dst >>= c-1; I.CarryVal = dst & 0x1; dst >>= 1; SetSZPF_Byte(dst); PutbackRMByte(ModRM,(BYTE)dst) +#define SHR_WORD(c) dst >>= c-1; I.CarryVal = dst & 0x1; dst >>= 1; SetSZPF_Word(dst); PutbackRMWord(ModRM,(WORD)dst) +#define SHRA_BYTE(c) dst = ((INT8)dst) >> (c-1); I.CarryVal = dst & 0x1; dst = ((INT8)((BYTE)dst)) >> 1; SetSZPF_Byte(dst); PutbackRMByte(ModRM,(BYTE)dst) +#define SHRA_WORD(c) dst = ((INT16)dst) >> (c-1); I.CarryVal = dst & 0x1; dst = ((INT16)((WORD)dst)) >> 1; SetSZPF_Word(dst); PutbackRMWord(ModRM,(WORD)dst) + +#define DIVUB \ + uresult = I.regs.w[AW]; \ + uresult2 = uresult % tmp; \ + if ((uresult /= tmp) > 0xff) { \ + nec_interrupt(0,0); break; \ + } else { \ + I.regs.b[AL] = uresult; \ + I.regs.b[AH] = uresult2; \ + } + +#define DIVB \ + result = (INT16)I.regs.w[AW]; \ + result2 = result % (INT16)((INT8)tmp); \ + if ((result /= (INT16)((INT8)tmp)) > 0xff) { \ + nec_interrupt(0,0); break; \ + } else { \ + I.regs.b[AL] = result; \ + I.regs.b[AH] = result2; \ + } + +#define DIVUW \ + uresult = (((UINT32)I.regs.w[DW]) << 16) | I.regs.w[AW];\ + uresult2 = uresult % tmp; \ + if ((uresult /= tmp) > 0xffff) { \ + nec_interrupt(0,0); break; \ + } else { \ + I.regs.w[AW]=uresult; \ + I.regs.w[DW]=uresult2; \ + } + +#define DIVW \ + result = ((UINT32)I.regs.w[DW] << 16) + I.regs.w[AW]; \ + result2 = result % (INT32)((INT16)tmp); \ + if ((result /= (INT32)((INT16)tmp)) > 0xffff) { \ + nec_interrupt(0,0); break; \ + } else { \ + I.regs.w[AW]=result; \ + I.regs.w[DW]=result2; \ + } + +#define ADD4S { \ + int i,v1,v2,result; \ + int count = (I.regs.b[CL]+1)/2; \ + unsigned di = I.regs.w[IY]; \ + unsigned si = I.regs.w[IX]; \ + I.ZeroVal = I.CarryVal = 0; \ + for (i=0;i>4)*10 + (tmp&0xf); \ + v2 = (tmp2>>4)*10 + (tmp2&0xf); \ + result = v1+v2+I.CarryVal; \ + I.CarryVal = result > 99 ? 1 : 0; \ + result = result % 100; \ + v1 = ((result/10)<<4) | (result % 10); \ + PutMemB(ES, di,v1); \ + if (v1) I.ZeroVal = 1; \ + si++; \ + di++; \ + } \ +} + +#define SUB4S { \ + int count = (I.regs.b[CL]+1)/2; \ + int i,v1,v2,result; \ + unsigned di = I.regs.w[IY]; \ + unsigned si = I.regs.w[IX]; \ + I.ZeroVal = I.CarryVal = 0; \ + for (i=0;i>4)*10 + (tmp&0xf); \ + v2 = (tmp2>>4)*10 + (tmp2&0xf); \ + if (v1 < (v2+I.CarryVal)) { \ + v1+=100; \ + result = v1-(v2+I.CarryVal); \ + I.CarryVal = 1; \ + } else { \ + result = v1-(v2+I.CarryVal); \ + I.CarryVal = 0; \ + } \ + v1 = ((result/10)<<4) | (result % 10); \ + PutMemB(ES, di,v1); \ + if (v1) I.ZeroVal = 1; \ + si++; \ + di++; \ + } \ +} + +#define CMP4S { \ + int count = (I.regs.b[CL]+1)/2; \ + int i,v1,v2,result; \ + unsigned di = I.regs.w[IY]; \ + unsigned si = I.regs.w[IX]; \ + I.ZeroVal = I.CarryVal = 0; \ + for (i=0;i>4)*10 + (tmp&0xf); \ + v2 = (tmp2>>4)*10 + (tmp2&0xf); \ + if (v1 < (v2+I.CarryVal)) { \ + v1+=100; \ + result = v1-(v2+I.CarryVal); \ + I.CarryVal = 1; \ + } else { \ + result = v1-(v2+I.CarryVal); \ + I.CarryVal = 0; \ + } \ + v1 = ((result/10)<<4) | (result % 10); \ + if (v1) I.ZeroVal = 1; \ + si++; \ + di++; \ + } \ +} diff --git a/oswan/source/nec/necea.h b/oswan/source/nec/necea.h new file mode 100644 index 0000000..12fb93f --- /dev/null +++ b/oswan/source/nec/necea.h @@ -0,0 +1,60 @@ + +static UINT32 EA; +static UINT16 EO; +static UINT16 E16; + +static unsigned EA_000(void) { EO=I.regs.w[BW]+I.regs.w[IX]; EA=DefaultBase(DS)+EO; return EA; } +static unsigned EA_001(void) { EO=I.regs.w[BW]+I.regs.w[IY]; EA=DefaultBase(DS)+EO; return EA; } +static unsigned EA_002(void) { EO=I.regs.w[BP]+I.regs.w[IX]; EA=DefaultBase(SS)+EO; return EA; } +static unsigned EA_003(void) { EO=I.regs.w[BP]+I.regs.w[IY]; EA=DefaultBase(SS)+EO; return EA; } +static unsigned EA_004(void) { EO=I.regs.w[IX]; EA=DefaultBase(DS)+EO; return EA; } +static unsigned EA_005(void) { EO=I.regs.w[IY]; EA=DefaultBase(DS)+EO; return EA; } +static unsigned EA_006(void) { EO=FETCH; EO+=FETCH<<8; EA=DefaultBase(DS)+EO; return EA; } +static unsigned EA_007(void) { EO=I.regs.w[BW]; EA=DefaultBase(DS)+EO; return EA; } + +static unsigned EA_100(void) { EO=(I.regs.w[BW]+I.regs.w[IX]+(INT8)FETCH); EA=DefaultBase(DS)+EO; return EA; } +static unsigned EA_101(void) { EO=(I.regs.w[BW]+I.regs.w[IY]+(INT8)FETCH); EA=DefaultBase(DS)+EO; return EA; } +static unsigned EA_102(void) { EO=(I.regs.w[BP]+I.regs.w[IX]+(INT8)FETCH); EA=DefaultBase(SS)+EO; return EA; } +static unsigned EA_103(void) { EO=(I.regs.w[BP]+I.regs.w[IY]+(INT8)FETCH); EA=DefaultBase(SS)+EO; return EA; } +static unsigned EA_104(void) { EO=(I.regs.w[IX]+(INT8)FETCH); EA=DefaultBase(DS)+EO; return EA; } +static unsigned EA_105(void) { EO=(I.regs.w[IY]+(INT8)FETCH); EA=DefaultBase(DS)+EO; return EA; } +static unsigned EA_106(void) { EO=(I.regs.w[BP]+(INT8)FETCH); EA=DefaultBase(SS)+EO; return EA; } +static unsigned EA_107(void) { EO=(I.regs.w[BW]+(INT8)FETCH); EA=DefaultBase(DS)+EO; return EA; } + +static unsigned EA_200(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BW]+I.regs.w[IX]+(INT16)E16; EA=DefaultBase(DS)+EO; return EA; } +static unsigned EA_201(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BW]+I.regs.w[IY]+(INT16)E16; EA=DefaultBase(DS)+EO; return EA; } +static unsigned EA_202(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BP]+I.regs.w[IX]+(INT16)E16; EA=DefaultBase(SS)+EO; return EA; } +static unsigned EA_203(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BP]+I.regs.w[IY]+(INT16)E16; EA=DefaultBase(SS)+EO; return EA; } +static unsigned EA_204(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[IX]+(INT16)E16; EA=DefaultBase(DS)+EO; return EA; } +static unsigned EA_205(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[IY]+(INT16)E16; EA=DefaultBase(DS)+EO; return EA; } +static unsigned EA_206(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BP]+(INT16)E16; EA=DefaultBase(SS)+EO; return EA; } +static unsigned EA_207(void) { E16=FETCH; E16+=FETCH<<8; EO=I.regs.w[BW]+(INT16)E16; EA=DefaultBase(DS)+EO; return EA; } + +static unsigned (*GetEA[192])(void)={ + EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007, + EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007, + EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007, + EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007, + EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007, + EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007, + EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007, + EA_000, EA_001, EA_002, EA_003, EA_004, EA_005, EA_006, EA_007, + + EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107, + EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107, + EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107, + EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107, + EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107, + EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107, + EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107, + EA_100, EA_101, EA_102, EA_103, EA_104, EA_105, EA_106, EA_107, + + EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207, + EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207, + EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207, + EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207, + EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207, + EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207, + EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207, + EA_200, EA_201, EA_202, EA_203, EA_204, EA_205, EA_206, EA_207 +}; diff --git a/oswan/source/nec/necinstr.h b/oswan/source/nec/necinstr.h new file mode 100644 index 0000000..7a7e31e --- /dev/null +++ b/oswan/source/nec/necinstr.h @@ -0,0 +1,507 @@ +static void i_add_br8(void); +static void i_add_wr16(void); +static void i_add_r8b(void); +static void i_add_r16w(void); +static void i_add_ald8(void); +static void i_add_axd16(void); +static void i_push_es(void); +static void i_pop_es(void); +static void i_or_br8(void); +static void i_or_r8b(void); +static void i_or_wr16(void); +static void i_or_r16w(void); +static void i_or_ald8(void); +static void i_or_axd16(void); +static void i_push_cs(void); +static void i_pre_nec(void); +static void i_adc_br8(void); +static void i_adc_wr16(void); +static void i_adc_r8b(void); +static void i_adc_r16w(void); +static void i_adc_ald8(void); +static void i_adc_axd16(void); +static void i_push_ss(void); +static void i_pop_ss(void); +static void i_sbb_br8(void); +static void i_sbb_wr16(void); +static void i_sbb_r8b(void); +static void i_sbb_r16w(void); +static void i_sbb_ald8(void); +static void i_sbb_axd16(void); +static void i_push_ds(void); +static void i_pop_ds(void); +static void i_and_br8(void); +static void i_and_r8b(void); +static void i_and_wr16(void); +static void i_and_r16w(void); +static void i_and_ald8(void); +static void i_and_axd16(void); +static void i_es(void); +static void i_daa(void); +static void i_sub_br8(void); +static void i_sub_wr16(void); +static void i_sub_r8b(void); +static void i_sub_r16w(void); +static void i_sub_ald8(void); +static void i_sub_axd16(void); +static void i_cs(void); +static void i_das(void); +static void i_xor_br8(void); +static void i_xor_r8b(void); +static void i_xor_wr16(void); +static void i_xor_r16w(void); +static void i_xor_ald8(void); +static void i_xor_axd16(void); +static void i_ss(void); +static void i_aaa(void); +static void i_cmp_br8(void); +static void i_cmp_wr16(void); +static void i_cmp_r8b(void); +static void i_cmp_r16w(void); +static void i_cmp_ald8(void); +static void i_cmp_axd16(void); +static void i_ds(void); +static void i_aas(void); +static void i_inc_ax(void); +static void i_inc_cx(void); +static void i_inc_dx(void); +static void i_inc_bx(void); +static void i_inc_sp(void); +static void i_inc_bp(void); +static void i_inc_si(void); +static void i_inc_di(void); +static void i_dec_ax(void); +static void i_dec_cx(void); +static void i_dec_dx(void); +static void i_dec_bx(void); +static void i_dec_sp(void); +static void i_dec_bp(void); +static void i_dec_si(void); +static void i_dec_di(void); +static void i_push_ax(void); +static void i_push_cx(void); +static void i_push_dx(void); +static void i_push_bx(void); +static void i_push_sp(void); +static void i_push_bp(void); +static void i_push_si(void); +static void i_push_di(void); +static void i_pop_ax(void); +static void i_pop_cx(void); +static void i_pop_dx(void); +static void i_pop_bx(void); +static void i_pop_sp(void); +static void i_pop_bp(void); +static void i_pop_si(void); +static void i_pop_di(void); +static void i_pusha(void); +static void i_popa(void); +static void i_chkind(void); +static void i_repnc(void); +static void i_repc(void); +static void i_push_d16(void); +static void i_imul_d16(void); +static void i_push_d8(void); +static void i_imul_d8(void); +static void i_insb(void); +static void i_insw(void); +static void i_outsb(void); +static void i_outsw(void); +static void i_jo(void); +static void i_jno(void); +static void i_jc(void); +static void i_jnc(void); +static void i_jz(void); +static void i_jnz(void); +static void i_jce(void); +static void i_jnce(void); +static void i_js(void); +static void i_jns(void); +static void i_jp(void); +static void i_jnp(void); +static void i_jl(void); +static void i_jnl(void); +static void i_jle(void); +static void i_jnle(void); +static void i_80pre(void); +static void i_82pre(void); +static void i_81pre(void); +static void i_83pre(void); +static void i_test_br8(void); +static void i_test_wr16(void); +static void i_xchg_br8(void); +static void i_xchg_wr16(void); +static void i_mov_br8(void); +static void i_mov_r8b(void); +static void i_mov_wr16(void); +static void i_mov_r16w(void); +static void i_mov_wsreg(void); +static void i_lea(void); +static void i_mov_sregw(void); +static void i_invalid(void); +static void i_popw(void); +static void i_nop(void); +static void i_xchg_axcx(void); +static void i_xchg_axdx(void); +static void i_xchg_axbx(void); +static void i_xchg_axsp(void); +static void i_xchg_axbp(void); +static void i_xchg_axsi(void); +static void i_xchg_axdi(void); +static void i_cbw(void); +static void i_cwd(void); +static void i_call_far(void); +static void i_pushf(void); +static void i_popf(void); +static void i_sahf(void); +static void i_lahf(void); +static void i_mov_aldisp(void); +static void i_mov_axdisp(void); +static void i_mov_dispal(void); +static void i_mov_dispax(void); +static void i_movsb(void); +static void i_movsw(void); +static void i_cmpsb(void); +static void i_cmpsw(void); +static void i_test_ald8(void); +static void i_test_axd16(void); +static void i_stosb(void); +static void i_stosw(void); +static void i_lodsb(void); +static void i_lodsw(void); +static void i_scasb(void); +static void i_scasw(void); +static void i_mov_ald8(void); +static void i_mov_cld8(void); +static void i_mov_dld8(void); +static void i_mov_bld8(void); +static void i_mov_ahd8(void); +static void i_mov_chd8(void); +static void i_mov_dhd8(void); +static void i_mov_bhd8(void); +static void i_mov_axd16(void); +static void i_mov_cxd16(void); +static void i_mov_dxd16(void); +static void i_mov_bxd16(void); +static void i_mov_spd16(void); +static void i_mov_bpd16(void); +static void i_mov_sid16(void); +static void i_mov_did16(void); +static void i_rotshft_bd8(void); +static void i_rotshft_wd8(void); +static void i_ret_d16(void); +static void i_ret(void); +static void i_les_dw(void); +static void i_lds_dw(void); +static void i_mov_bd8(void); +static void i_mov_wd16(void); +static void i_enter(void); +static void i_leave(void); +static void i_retf_d16(void); +static void i_retf(void); +static void i_int3(void); +static void i_int(void); +static void i_into(void); +static void i_iret(void); +static void i_rotshft_b(void); +static void i_rotshft_w(void); +static void i_rotshft_bcl(void); +static void i_rotshft_wcl(void); +static void i_aam(void); +static void i_aad(void); +static void i_setalc(void); +static void i_trans(void); +static void i_fpo(void); +static void i_loopne(void); +static void i_loope(void); +static void i_loop(void); +static void i_jcxz(void); +static void i_inal(void); +static void i_inax(void); +static void i_outal(void); +static void i_outax(void); +static void i_call_d16(void); +static void i_jmp_d16(void); +static void i_jmp_far(void); +static void i_jmp_d8(void); +static void i_inaldx(void); +static void i_inaxdx(void); +static void i_outdxal(void); +static void i_outdxax(void); +static void i_lock(void); +static void i_repne(void); +static void i_repe(void); +static void i_hlt(void); +static void i_cmc(void); +static void i_f6pre(void); +static void i_f7pre(void); +static void i_clc(void); +static void i_stc(void); +static void i_di(void); +static void i_ei(void); +static void i_cld(void); +static void i_std(void); +static void i_fepre(void); +static void i_ffpre(void); + +static void i_wait(void); + +void (*nec_instruction[256])(void) = +{ + i_add_br8, /* 0x00 */ + i_add_wr16, /* 0x01 */ + i_add_r8b, /* 0x02 */ + i_add_r16w, /* 0x03 */ + i_add_ald8, /* 0x04 */ + i_add_axd16, /* 0x05 */ + i_push_es, /* 0x06 */ + i_pop_es, /* 0x07 */ + i_or_br8, /* 0x08 */ + i_or_wr16, /* 0x09 */ + i_or_r8b, /* 0x0a */ + i_or_r16w, /* 0x0b */ + i_or_ald8, /* 0x0c */ + i_or_axd16, /* 0x0d */ + i_push_cs, /* 0x0e */ + i_pre_nec /* 0x0f */, + i_adc_br8, /* 0x10 */ + i_adc_wr16, /* 0x11 */ + i_adc_r8b, /* 0x12 */ + i_adc_r16w, /* 0x13 */ + i_adc_ald8, /* 0x14 */ + i_adc_axd16, /* 0x15 */ + i_push_ss, /* 0x16 */ + i_pop_ss, /* 0x17 */ + i_sbb_br8, /* 0x18 */ + i_sbb_wr16, /* 0x19 */ + i_sbb_r8b, /* 0x1a */ + i_sbb_r16w, /* 0x1b */ + i_sbb_ald8, /* 0x1c */ + i_sbb_axd16, /* 0x1d */ + i_push_ds, /* 0x1e */ + i_pop_ds, /* 0x1f */ + i_and_br8, /* 0x20 */ + i_and_wr16, /* 0x21 */ + i_and_r8b, /* 0x22 */ + i_and_r16w, /* 0x23 */ + i_and_ald8, /* 0x24 */ + i_and_axd16, /* 0x25 */ + i_es, /* 0x26 */ + i_daa, /* 0x27 */ + i_sub_br8, /* 0x28 */ + i_sub_wr16, /* 0x29 */ + i_sub_r8b, /* 0x2a */ + i_sub_r16w, /* 0x2b */ + i_sub_ald8, /* 0x2c */ + i_sub_axd16, /* 0x2d */ + i_cs, /* 0x2e */ + i_das, /* 0x2f */ + i_xor_br8, /* 0x30 */ + i_xor_wr16, /* 0x31 */ + i_xor_r8b, /* 0x32 */ + i_xor_r16w, /* 0x33 */ + i_xor_ald8, /* 0x34 */ + i_xor_axd16, /* 0x35 */ + i_ss, /* 0x36 */ + i_aaa, /* 0x37 */ + i_cmp_br8, /* 0x38 */ + i_cmp_wr16, /* 0x39 */ + i_cmp_r8b, /* 0x3a */ + i_cmp_r16w, /* 0x3b */ + i_cmp_ald8, /* 0x3c */ + i_cmp_axd16, /* 0x3d */ + i_ds, /* 0x3e */ + i_aas, /* 0x3f */ + i_inc_ax, /* 0x40 */ + i_inc_cx, /* 0x41 */ + i_inc_dx, /* 0x42 */ + i_inc_bx, /* 0x43 */ + i_inc_sp, /* 0x44 */ + i_inc_bp, /* 0x45 */ + i_inc_si, /* 0x46 */ + i_inc_di, /* 0x47 */ + i_dec_ax, /* 0x48 */ + i_dec_cx, /* 0x49 */ + i_dec_dx, /* 0x4a */ + i_dec_bx, /* 0x4b */ + i_dec_sp, /* 0x4c */ + i_dec_bp, /* 0x4d */ + i_dec_si, /* 0x4e */ + i_dec_di, /* 0x4f */ + i_push_ax, /* 0x50 */ + i_push_cx, /* 0x51 */ + i_push_dx, /* 0x52 */ + i_push_bx, /* 0x53 */ + i_push_sp, /* 0x54 */ + i_push_bp, /* 0x55 */ + i_push_si, /* 0x56 */ + i_push_di, /* 0x57 */ + i_pop_ax, /* 0x58 */ + i_pop_cx, /* 0x59 */ + i_pop_dx, /* 0x5a */ + i_pop_bx, /* 0x5b */ + i_pop_sp, /* 0x5c */ + i_pop_bp, /* 0x5d */ + i_pop_si, /* 0x5e */ + i_pop_di, /* 0x5f */ + i_pusha, /* 0x60 */ + i_popa, /* 0x61 */ + i_chkind, /* 0x62 */ + i_invalid, /* 0x63 */ + i_repnc, /* 0x64 */ + i_repc, /* 0x65 */ + i_invalid, /* 0x66 */ + i_invalid, /* 0x67 */ + i_push_d16, /* 0x68 */ + i_imul_d16, /* 0x69 */ + i_push_d8, /* 0x6a */ + i_imul_d8, /* 0x6b */ + i_insb, /* 0x6c */ + i_insw, /* 0x6d */ + i_outsb, /* 0x6e */ + i_outsw, /* 0x6f */ + i_jo, /* 0x70 */ + i_jno, /* 0x71 */ + i_jc, /* 0x72 */ + i_jnc, /* 0x73 */ + i_jz, /* 0x74 */ + i_jnz, /* 0x75 */ + i_jce, /* 0x76 */ + i_jnce, /* 0x77 */ + i_js, /* 0x78 */ + i_jns, /* 0x79 */ + i_jp, /* 0x7a */ + i_jnp, /* 0x7b */ + i_jl, /* 0x7c */ + i_jnl, /* 0x7d */ + i_jle, /* 0x7e */ + i_jnle, /* 0x7f */ + i_80pre, /* 0x80 */ + i_81pre, /* 0x81 */ + i_82pre, /* 0x82 */ + i_83pre, /* 0x83 */ + i_test_br8, /* 0x84 */ + i_test_wr16, /* 0x85 */ + i_xchg_br8, /* 0x86 */ + i_xchg_wr16, /* 0x87 */ + i_mov_br8, /* 0x88 */ + i_mov_wr16, /* 0x89 */ + i_mov_r8b, /* 0x8a */ + i_mov_r16w, /* 0x8b */ + i_mov_wsreg, /* 0x8c */ + i_lea, /* 0x8d */ + i_mov_sregw, /* 0x8e */ + i_popw, /* 0x8f */ + i_nop, /* 0x90 */ + i_xchg_axcx, /* 0x91 */ + i_xchg_axdx, /* 0x92 */ + i_xchg_axbx, /* 0x93 */ + i_xchg_axsp, /* 0x94 */ + i_xchg_axbp, /* 0x95 */ + i_xchg_axsi, /* 0x97 */ + i_xchg_axdi, /* 0x97 */ + i_cbw, /* 0x98 */ + i_cwd, /* 0x99 */ + i_call_far, /* 0x9a */ + i_wait, /* 0x9b */ + i_pushf, /* 0x9c */ + i_popf, /* 0x9d */ + i_sahf, /* 0x9e */ + i_lahf, /* 0x9f */ + i_mov_aldisp, /* 0xa0 */ + i_mov_axdisp, /* 0xa1 */ + i_mov_dispal, /* 0xa2 */ + i_mov_dispax, /* 0xa3 */ + i_movsb, /* 0xa4 */ + i_movsw, /* 0xa5 */ + i_cmpsb, /* 0xa6 */ + i_cmpsw, /* 0xa7 */ + i_test_ald8, /* 0xa8 */ + i_test_axd16, /* 0xa9 */ + i_stosb, /* 0xaa */ + i_stosw, /* 0xab */ + i_lodsb, /* 0xac */ + i_lodsw, /* 0xad */ + i_scasb, /* 0xae */ + i_scasw, /* 0xaf */ + i_mov_ald8, /* 0xb0 */ + i_mov_cld8, /* 0xb1 */ + i_mov_dld8, /* 0xb2 */ + i_mov_bld8, /* 0xb3 */ + i_mov_ahd8, /* 0xb4 */ + i_mov_chd8, /* 0xb5 */ + i_mov_dhd8, /* 0xb6 */ + i_mov_bhd8, /* 0xb7 */ + i_mov_axd16, /* 0xb8 */ + i_mov_cxd16, /* 0xb9 */ + i_mov_dxd16, /* 0xba */ + i_mov_bxd16, /* 0xbb */ + i_mov_spd16, /* 0xbc */ + i_mov_bpd16, /* 0xbd */ + i_mov_sid16, /* 0xbe */ + i_mov_did16, /* 0xbf */ + i_rotshft_bd8, /* 0xc0 */ + i_rotshft_wd8, /* 0xc1 */ + i_ret_d16, /* 0xc2 */ + i_ret, /* 0xc3 */ + i_les_dw, /* 0xc4 */ + i_lds_dw, /* 0xc5 */ + i_mov_bd8, /* 0xc6 */ + i_mov_wd16, /* 0xc7 */ + i_enter, /* 0xc8 */ + i_leave, /* 0xc9 */ + i_retf_d16, /* 0xca */ + i_retf, /* 0xcb */ + i_int3, /* 0xcc */ + i_int, /* 0xcd */ + i_into, /* 0xce */ + i_iret, /* 0xcf */ + i_rotshft_b, /* 0xd0 */ + i_rotshft_w, /* 0xd1 */ + i_rotshft_bcl, /* 0xd2 */ + i_rotshft_wcl, /* 0xd3 */ + i_aam, /* 0xd4 */ + i_aad, /* 0xd5 */ + i_setalc, + i_trans, /* 0xd7 */ + i_fpo, /* 0xd8 */ + i_fpo, /* 0xd9 */ + i_fpo, /* 0xda */ + i_fpo, /* 0xdb */ + i_fpo, /* 0xdc */ + i_fpo, /* 0xdd */ + i_fpo, /* 0xde */ + i_fpo, /* 0xdf */ + i_loopne, /* 0xe0 */ + i_loope, /* 0xe1 */ + i_loop, /* 0xe2 */ + i_jcxz, /* 0xe3 */ + i_inal, /* 0xe4 */ + i_inax, /* 0xe5 */ + i_outal, /* 0xe6 */ + i_outax, /* 0xe7 */ + i_call_d16, /* 0xe8 */ + i_jmp_d16, /* 0xe9 */ + i_jmp_far, /* 0xea */ + i_jmp_d8, /* 0xeb */ + i_inaldx, /* 0xec */ + i_inaxdx, /* 0xed */ + i_outdxal, /* 0xee */ + i_outdxax, /* 0xef */ + i_lock, /* 0xf0 */ + i_invalid, /* 0xf1 */ + i_repne, /* 0xf2 */ + i_repe, /* 0xf3 */ + i_hlt, /* 0xf4 */ + i_cmc, /* 0xf5 */ + i_f6pre, /* 0xf6 */ + i_f7pre, /* 0xf7 */ + i_clc, /* 0xf8 */ + i_stc, /* 0xf9 */ + i_di, /* 0xfa */ + i_ei, /* 0xfb */ + i_cld, /* 0xfc */ + i_std, /* 0xfd */ + i_fepre, /* 0xfe */ + i_ffpre /* 0xff */ +}; diff --git a/oswan/source/nec/necintrf.h b/oswan/source/nec/necintrf.h new file mode 100644 index 0000000..0849b9d --- /dev/null +++ b/oswan/source/nec/necintrf.h @@ -0,0 +1,67 @@ +/* ASG 971222 -- rewrote this interface */ +#ifndef __NEC_H_ +#define __NEC_H_ + + + +enum { + NEC_IP=1, NEC_AW, NEC_CW, NEC_DW, NEC_BW, NEC_SP, NEC_BP, NEC_IX, NEC_IY, + NEC_FLAGS, NEC_ES, NEC_CS, NEC_SS, NEC_DS, + NEC_VECTOR, NEC_PENDING, NEC_NMI_STATE, NEC_IRQ_STATE }; + +/* Public variables */ +extern int nec_ICount; + +/* Public functions */ + +/* +#define v20_ICount nec_ICount +extern void v20_init(void); +extern void v20_reset(void *param); +extern void v20_exit(void); +extern int v20_execute(int cycles); +extern unsigned v20_get_context(void *dst); +extern void v20_set_context(void *src); +extern unsigned v20_get_reg(int regnum); +extern void v20_set_reg(int regnum, unsigned val); +extern void v20_set_irq_line(int irqline, int state); +extern void v20_set_irq_callback(int (*callback)(int irqline)); +extern const char *v20_info(void *context, int regnum); +extern unsigned v20_dasm(char *buffer, unsigned pc); + +#define v30_ICount nec_ICount +extern void v30_init(void); +extern void v30_reset(void *param); +extern void v30_exit(void); +extern int v30_execute(int cycles); +extern unsigned v30_get_context(void *dst); +extern void v30_set_context(void *src); +extern unsigned v30_get_reg(int regnum); +extern void v30_set_reg(int regnum, unsigned val); +extern void v30_set_irq_line(int irqline, int state); +extern void v30_set_irq_callback(int (*callback)(int irqline)); +extern const char *v30_info(void *context, int regnum); +extern unsigned v30_dasm(char *buffer, unsigned pc); + +#define v33_ICount nec_ICount +extern void v33_init(void); +extern void v33_reset(void *param); +extern void v33_exit(void); +extern int v33_execute(int cycles); +extern unsigned v33_get_context(void *dst); +extern void v33_set_context(void *src); +extern unsigned v33_get_reg(int regnum); +extern void v33_set_reg(int regnum, unsigned val); +extern void v33_set_irq_line(int irqline, int state); +extern void v33_set_irq_callback(int (*callback)(int irqline)); +extern const char *v33_info(void *context, int regnum); +extern unsigned v33_dasm(char *buffer, unsigned pc); +*/ + +void nec_set_reg(int,unsigned); +int nec_execute(int cycles); +unsigned nec_get_reg(int regnum); +void nec_reset (void *param); +void nec_int(DWORD wektor); + +#endif diff --git a/oswan/source/nec/necmodrm.h b/oswan/source/nec/necmodrm.h new file mode 100644 index 0000000..41870b5 --- /dev/null +++ b/oswan/source/nec/necmodrm.h @@ -0,0 +1,104 @@ +static struct { + struct { + WREGS w[256]; + BREGS b[256]; + } reg; + struct { + WREGS w[256]; + BREGS b[256]; + } RM; +} Mod_RM; + +#define RegWord(ModRM) I.regs.w[Mod_RM.reg.w[ModRM]] +#define RegByte(ModRM) I.regs.b[Mod_RM.reg.b[ModRM]] + +#define GetRMWord(ModRM) \ + ((ModRM) >= 0xc0 ? I.regs.w[Mod_RM.RM.w[ModRM]] : ( (*GetEA[ModRM])(), ReadWord( EA ) )) + +#define PutbackRMWord(ModRM,val) \ +{ \ + if (ModRM >= 0xc0) I.regs.w[Mod_RM.RM.w[ModRM]]=val; \ + else WriteWord(EA,val); \ +} + +#define GetnextRMWord ReadWord((EA&0xf0000)|((EA+2)&0xffff)) + +#define PutRMWord(ModRM,val) \ +{ \ + if (ModRM >= 0xc0) \ + I.regs.w[Mod_RM.RM.w[ModRM]]=val; \ + else { \ + (*GetEA[ModRM])(); \ + WriteWord( EA ,val); \ + } \ +} + +#define PutImmRMWord(ModRM) \ +{ \ + WORD val; \ + if (ModRM >= 0xc0) \ + FETCHWORD(I.regs.w[Mod_RM.RM.w[ModRM]]) \ + else { \ + (*GetEA[ModRM])(); \ + FETCHWORD(val) \ + WriteWord( EA , val); \ + } \ +} + +#define GetRMByte(ModRM) \ + ((ModRM) >= 0xc0 ? I.regs.b[Mod_RM.RM.b[ModRM]] : ReadByte( (*GetEA[ModRM])() )) + +#define PutRMByte(ModRM,val) \ +{ \ + if (ModRM >= 0xc0) \ + I.regs.b[Mod_RM.RM.b[ModRM]]=val; \ + else \ + WriteByte( (*GetEA[ModRM])() ,val); \ +} + +#define PutImmRMByte(ModRM) \ +{ \ + if (ModRM >= 0xc0) \ + I.regs.b[Mod_RM.RM.b[ModRM]]=FETCH; \ + else { \ + (*GetEA[ModRM])(); \ + WriteByte( EA , FETCH ); \ + } \ +} + +#define PutbackRMByte(ModRM,val) \ +{ \ + if (ModRM >= 0xc0) \ + I.regs.b[Mod_RM.RM.b[ModRM]]=val; \ + else \ + WriteByte(EA,val); \ +} + +#define DEF_br8 \ + UINT32 ModRM = FETCH,src,dst; \ + src = RegByte(ModRM); \ + dst = GetRMByte(ModRM) + +#define DEF_wr16 \ + UINT32 ModRM = FETCH,src,dst; \ + src = RegWord(ModRM); \ + dst = GetRMWord(ModRM) + +#define DEF_r8b \ + UINT32 ModRM = FETCH,src,dst; \ + dst = RegByte(ModRM); \ + src = GetRMByte(ModRM) + +#define DEF_r16w \ + UINT32 ModRM = FETCH,src,dst; \ + dst = RegWord(ModRM); \ + src = GetRMWord(ModRM) + +#define DEF_ald8 \ + UINT32 src = FETCH; \ + UINT32 dst = I.regs.b[AL] + +#define DEF_axd16 \ + UINT32 src = FETCH; \ + UINT32 dst = I.regs.w[AW]; \ + src += (FETCH << 8) diff --git a/oswan/source/rom.cpp b/oswan/source/rom.cpp new file mode 100644 index 0000000..4e641ee --- /dev/null +++ b/oswan/source/rom.cpp @@ -0,0 +1,153 @@ +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include "types.h" +#include "log.h" +#include "rom.h" + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +uint8 *ws_rom_load(char *path, uint32 *romSize) +{ + uint8 *rom=NULL; + Uint32 filepos; + FILE *fp=fopen(path,"rb"); + if (fp==NULL) + return(NULL); + + fseek(fp,0,SEEK_END); + //fgetpos(fp,&filepos); + filepos = ftell(fp); + *romSize=(uint32)filepos; + fseek(fp,0,SEEK_SET); + rom=(uint8*)malloc(*romSize); + fread(rom,1,*romSize,fp); + fclose(fp); + return(rom); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_rom_dumpInfo(uint8 *wsrom, uint32 romSize) +{ + ws_romHeaderStruct *romHeader=ws_rom_getHeader(wsrom,romSize); + + fprintf(log_get(),"rom: developper Id 0x%.2x\n",romHeader->developperId); + fprintf(log_get(),"rom: cart Id 0x%.2x\n",romHeader->cartId); + fprintf(log_get(),"rom: minimum system %s\n",(romHeader->minimumSupportSystem==WS_SYSTEM_MONO)?"Wonderswan mono":"Wonderswan color"); + fprintf(log_get(),"rom: size %i Mbits\n",(romSize>>20)<<3); + fprintf(log_get(),"rom: eeprom "); + switch (romHeader->eepromSize&0xf) + { + case WS_EEPROM_SIZE_NONE: { fprintf(log_get(),"none\n"); break; } + case WS_EEPROM_SIZE_64k: { fprintf(log_get(),"64 kb\n"); break; } + case WS_EEPROM_SIZE_256k: { fprintf(log_get(),"256 kb\n"); break; } + } + fprintf(log_get(),"rom: sram "); + switch (romHeader->eepromSize&0xf0) + { + case WS_SRAM_SIZE_NONE: { fprintf(log_get(),"none\n"); break; } + case WS_SRAM_SIZE_1k: { fprintf(log_get(),"1 kb\n"); break; } + case WS_SRAM_SIZE_16k: { fprintf(log_get(),"16 kb\n"); break; } + case WS_SRAM_SIZE_8k: { fprintf(log_get(),"8 kn\n"); break; } + } + + fprintf(log_get(),"rom: rtc %s\n",(romHeader->realtimeClock)?"Yes":"None"); + fprintf(log_get(),"checksum 0x%.4x\n",romHeader->checksum); + +} + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +ws_romHeaderStruct *ws_rom_getHeader(uint8 *wsrom, uint32 wsromSize) +{ + ws_romHeaderStruct *wsromHeader=(ws_romHeaderStruct *)malloc(sizeof(ws_romHeaderStruct)); + + memcpy(wsromHeader,wsrom+(wsromSize-10),10); + return(wsromHeader); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +uint32 ws_rom_sramSize(uint8 *wsrom, uint32 wsromSize) +{ + ws_romHeaderStruct *romHeader=ws_rom_getHeader(wsrom,wsromSize); + switch (romHeader->eepromSize&0xf0) + { + case WS_SRAM_SIZE_NONE: return(0); + case WS_SRAM_SIZE_1k: return(0x400); + case WS_SRAM_SIZE_16k: return(0x4000); + case WS_SRAM_SIZE_8k: return(0x2000); + } + return(0); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +uint32 ws_rom_eepromSize(uint8 *wsrom, uint32 wsromSize) +{ + ws_romHeaderStruct *romHeader=ws_rom_getHeader(wsrom,wsromSize); + switch (romHeader->eepromSize&0xf) + { + case WS_EEPROM_SIZE_NONE: return(0); + case WS_EEPROM_SIZE_64k: return(0x10000); + case WS_EEPROM_SIZE_256k: return(0x40000); + } + return(0); +} + diff --git a/oswan/source/rom.h b/oswan/source/rom.h new file mode 100644 index 0000000..7f9b601 --- /dev/null +++ b/oswan/source/rom.h @@ -0,0 +1,60 @@ +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef __ROM_H__ +#define __ROM_H__ + +#include "types.h" + +#define WS_SYSTEM_MONO 0 +#define WS_SYSTEM_COLOR 1 + +#define WS_ROM_SIZE_2MBIT 1 +#define WS_ROM_SIZE_4MBIT 2 +#define WS_ROM_SIZE_8MBIT 3 +#define WS_ROM_SIZE_16MBIT 4 +#define WS_ROM_SIZE_24MBIT 5 +#define WS_ROM_SIZE_32MBIT 6 +#define WS_ROM_SIZE_48MBIT 7 +#define WS_ROM_SIZE_64MBIT 8 +#define WS_ROM_SIZE_128MBIT 9 + +#define WS_EEPROM_SIZE_NONE 0 +#define WS_SRAM_SIZE_NONE 0 +#define WS_EEPROM_SIZE_64k 1 +#define WS_EEPROM_SIZE_256k 2 +#define WS_SRAM_SIZE_1k 10 +#define WS_SRAM_SIZE_16k 20 +#define WS_SRAM_SIZE_8k 50 + + +typedef struct ws_romHeaderStruct +{ + uint8 developperId; + uint8 minimumSupportSystem; + uint8 cartId; + uint8 romSize; + uint8 eepromSize; + uint8 additionnalCapabilities; + uint8 realtimeClock; + uint16 checksum; +} ws_romHeaderStruct; + + +uint8 *ws_rom_load(char *path, uint32 *romSize); +void ws_rom_dumpInfo(uint8 *wsrom, uint32 wsromSize); +ws_romHeaderStruct *ws_rom_getHeader(uint8 *wsrom, uint32 wsromSize); +uint32 ws_rom_sramSize(uint8 *wsrom, uint32 wsromSize); +uint32 ws_rom_eepromSize(uint8 *wsrom, uint32 wsromSize); + + +#endif + diff --git a/oswan/source/temp/key.h b/oswan/source/temp/key.h new file mode 100644 index 0000000..05dc99a --- /dev/null +++ b/oswan/source/temp/key.h @@ -0,0 +1,98 @@ + static int testJoystick=1; + if (testJoystick==1) + { + testJoystick=0; + fprintf(log_get(),"%i joysticks were found.\n\n", SDL_NumJoysticks() ); + fprintf(log_get(),"The names of the joysticks are:\n"); + for(int tti=0; tti < SDL_NumJoysticks(); tti++ ) + fprintf(log_get()," %s\n", SDL_JoystickName(tti)); + SDL_JoystickEventState(SDL_ENABLE); + joystick = SDL_JoystickOpen(0); + } + else + { + if (joystick!=NULL) + { + SDL_JoystickClose(0); + SDL_JoystickEventState(SDL_ENABLE); + joystick = SDL_JoystickOpen(0); + } + } + + while ( SDL_PollEvent(&app_input_event) ) + { + if ( app_input_event.type == SDL_QUIT ) + { + ws_key_esc = 1; + } + } + if (joystick) + { + if (SDL_JoystickGetButton(joystick,0)) + ws_key_start=1; + else + ws_key_start=0; + if (SDL_JoystickGetButton(joystick,1)) + ws_key_button_1=1; + else + ws_key_button_1=0; + if (SDL_JoystickGetButton(joystick,2)) + ws_key_button_2=1; + else + ws_key_button_2=0; + + + if (SDL_JoystickGetAxis(joystick,0)<-7000) + ws_key_left=1; + else + ws_key_left=0; + if (SDL_JoystickGetAxis(joystick,0)>7000) + ws_key_right=1; + else + ws_key_right=0; + + if (SDL_JoystickGetAxis(joystick,1)<-7000) + ws_key_up=1; + else + ws_key_up=0; + if (SDL_JoystickGetAxis(joystick,1)>7000) + ws_key_down=1; + else + ws_key_down=0; + } + else + { + ws_key_start=0; + ws_key_left=0; + ws_key_right=0; + ws_key_up=0; + ws_key_down=0; + ws_key_button_1=0; + ws_key_button_2=0; + } + uint8 *keystate = SDL_GetKeyState(NULL); + if ( keystate[SDLK_d]) + { + dump_memory(); + } + if ( keystate[SDLK_ESCAPE] ) + ws_key_esc = 1; + if ( keystate[SDLK_UP] ) + ws_key_up=1; + if ( keystate[SDLK_DOWN] ) + ws_key_down=1; + if ( keystate[SDLK_RIGHT] ) + ws_key_right=1; + if ( keystate[SDLK_LEFT] ) + ws_key_left=1; + if (keystate[SDLK_RETURN]) + ws_key_start=1; + if (keystate[SDLK_c]) + ws_key_button_1=1; + if (keystate[SDLK_x]) + ws_key_button_2=1; + if (keystate[SDLK_p]) + ws_cyclesByLine+=10; + if (keystate[SDLK_o]) + ws_cyclesByLine-=10; + diff --git a/oswan/source/ticker b/oswan/source/ticker new file mode 100644 index 0000000..afb3e7f Binary files /dev/null and b/oswan/source/ticker differ diff --git a/oswan/source/ticker.asm b/oswan/source/ticker.asm new file mode 100644 index 0000000..7b88cc0 --- /dev/null +++ b/oswan/source/ticker.asm @@ -0,0 +1,42 @@ +bits 32 +section .data +bits 32 + +times ($$-$)&7 db 0 +section .text +bits 32 + +global rdtscCapableCpu_ +global _rdtscCapableCpu +global _ticker +global ticker_ + +_ticker: +ticker_: + push edx + rdtsc + shr eax,8 + shl edx,24 + and edx,0xff000000 + or eax,edx + pop edx + ret + +rdtscCapableCpu_: +_rdtscCapableCpu: + push ebx + push ecx + push edx + mov eax,1 + xor ebx,ebx + xor ecx,ecx + xor edx,edx + cpuid + test edx,0x10 + setne al + and eax,1 + pop edx + pop ecx + pop ebx + ret +end diff --git a/oswan/source/ticker.h b/oswan/source/ticker.h new file mode 100644 index 0000000..e222eee --- /dev/null +++ b/oswan/source/ticker.h @@ -0,0 +1,5 @@ +extern "C" +{ +long ticker(); +}; + diff --git a/oswan/source/types.h b/oswan/source/types.h new file mode 100644 index 0000000..0733040 --- /dev/null +++ b/oswan/source/types.h @@ -0,0 +1,44 @@ +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +////////////////////////////////////////////////////////////////////////////// + +// this file is a travesty. [SU]int(8|16|32) should be used instead. + +#ifndef __TYPES_H__ +#define __TYPES_H__ + +#include "SDL.h" + +#define UINT8 Uint8 +#define UINT16 Uint16 +#define INT8 Sint8 +#define INT16 Sint16 +#define INT32 Sint32 +#define UINT32 Uint32 + +#define uint8 UINT8 +#define uint16 UINT16 +#define uint32 UINT32 +#define int8 INT8 +#define int16 INT16 +#define int32 INT32 + +#define u8 uint8 +#define u16 uint16 +#define u32 uint32 +#define s8 int8 +#define s16 int16 +#define s32 int32 + +#define BYTE Uint8 +#define WORD Uint16 +#define DWORD Uint32 + +#endif diff --git a/oswan/source/ws.cpp b/oswan/source/ws.cpp new file mode 100644 index 0000000..ec7637b --- /dev/null +++ b/oswan/source/ws.cpp @@ -0,0 +1,461 @@ +//////////////////////////////////////////////////////////////////////////////// +// Wonderswan emulator +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// 07.04.2002: speed problems partially fixed +// 13.04.2002: Set cycles by line to 256 (according to toshi) +// this seems to work well in most situations with +// the new nec v30 cpu core +// +// +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include "log.h" +#include "rom.h" +#include "./nec/nec.h" +#include "./nec/necintrf.h" +#include "memory.h" +#include "gpu.h" +#include "io.h" +#include "audio.h" +#include "ws.h" + +#ifndef O_BINARY +// silly windows systems with their CR/LF screwiness... +#define O_BINARY 0 +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// + +uint32 ws_cycles; +uint32 ws_skip; +uint32 ws_cyclesByLine=0; +uint32 vblank_count=0; + +char *ws_sram_path = NULL; +extern int ws_sram_dirty; + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_patchRom(void) +{ + + uint8 *rom=memory_getRom(); + uint32 romSize=memory_getRomSize(); + + fprintf(log_get(),"developper Id: 0x%.2x\nGame Id: 0x%.2x\n",rom[romSize-10],rom[romSize-8]); + + if((rom[romSize-10]==0x01)&&(rom[romSize-8]==0x27)) // Detective Conan + { + // WS cpu is using cache/pipeline or + // there's protected ROM bank where + // pointing CS + + rom[0xfffe8]=0xea; + rom[0xfffe9]=0x00; + rom[0xfffea]=0x00; + rom[0xfffeb]=0x00; + rom[0xfffec]=0x20; + + } + + if (!ws_cyclesByLine) ws_cyclesByLine=256; +} + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +int ws_init(char *rompath) +{ + uint8 *rom; + uint32 romSize; + + if ((rom=ws_rom_load(rompath,&romSize))==NULL) + { + printf("Error: cannot load %s\n",rompath); + return(0); + } + + if (rompath[strlen(rompath)-1]=='c') + ws_gpu_operatingInColor=1; + else + ws_gpu_operatingInColor=0; + + ws_memory_init(rom,romSize); + ws_patchRom(); + ws_sram_load(ws_sram_path); + ws_io_init(); + ws_audio_init(); + ws_gpu_init(); + if (ws_rotated()) + ws_io_flipControls(); + return(1); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_reset(void) +{ + ws_memory_reset(); + ws_io_reset(); + ws_audio_reset(); + ws_gpu_reset(); + nec_reset(NULL); + nec_set_reg(NEC_SP,0x2000); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +int ws_executeLine(int16 *framebuffer, int renderLine) +{ + int drawWholeScreen=0; + + ws_audio_process(); + + // update scanline register + ws_ioRam[2]=ws_gpu_scanline; + + ws_cycles=nec_execute((ws_cyclesByLine>>1)+(rand()&7)); + ws_cycles+=nec_execute((ws_cyclesByLine>>1)+(rand()&7)); + + if(ws_cycles>=ws_cyclesByLine+ws_cyclesByLine) + ws_skip=ws_cycles/ws_cyclesByLine; + else + ws_skip=1; + ws_cycles%=ws_cyclesByLine; + + for(uint32 uI=0;uI158) + { + ws_gpu_scanline=0; + { + if((ws_ioRam[0xb2]&32))/*VBLANK END INT*/ + { + if(ws_ioRam[0xa7]!=0x35)/*Beatmania Fix*/ + { + ws_ioRam[0xb6]&=~32; + nec_int((ws_ioRam[0xb0]+5)*4); + } + } + } + } + ws_ioRam[2]=ws_gpu_scanline; + if(drawWholeScreen) + { + + if(ws_ioRam[0xb2]&64) /*VBLANK INT*/ + { + ws_ioRam[0xb6]&=~64; + nec_int((ws_ioRam[0xb0]+6)*4); + } + vblank_count++; + } + if(ws_ioRam[0xa4]&&(ws_ioRam[0xb2]&128)) /*HBLANK INT*/ + { + + if(!ws_ioRam[0xa5]) + ws_ioRam[0xa5]=ws_ioRam[0xa4]; + if(ws_ioRam[0xa5]) + ws_ioRam[0xa5]--; + if((!ws_ioRam[0xa5])&&(ws_ioRam[0xb2]&128)) + { + + ws_ioRam[0xb6]&=~128; + nec_int((ws_ioRam[0xb0]+7)*4); + + } + } + if((ws_ioRam[0x2]==ws_ioRam[0x3])&&(ws_ioRam[0xb2]&16)) /*SCANLINE INT*/ + { + ws_ioRam[0xb6]&=~16; + nec_int((ws_ioRam[0xb0]+4)*4); + } + + if (drawWholeScreen && ws_sram_dirty) + { + ws_sram_save(ws_sram_path); + ws_sram_dirty = 0; + } + return(drawWholeScreen); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_done(void) +{ + ws_memory_done(); + ws_io_done(); + ws_audio_done(); + ws_gpu_done(); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_set_colour_scheme(int scheme) +{ + ws_gpu_set_colour_scheme(scheme); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +void ws_set_system(int system) +{ + if (system==WS_SYSTEM_COLOR) + ws_gpu_forceColorSystem(); + else + if (system==WS_SYSTEM_MONO) + ws_gpu_forceMonoSystem(); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +#define MacroLoadNecRegisterFromFile(F,R) \ + read(fp,&value,sizeof(value)); \ + nec_set_reg(R,value); + +int ws_loadState(char *statepath) +{ + fprintf(log_get(),"loading %s\n",statepath); + uint16 crc=memory_getRomCrc(); + uint16 newCrc; + unsigned value; + uint8 ws_newVideoMode; + + int fp = open(statepath,O_BINARY|O_RDONLY); + if (fp == -1) + return(0); + read(fp, &newCrc, 2); + if (newCrc!=crc) + { + return(-1); + } + MacroLoadNecRegisterFromFile(fp,NEC_IP); + MacroLoadNecRegisterFromFile(fp,NEC_AW); + MacroLoadNecRegisterFromFile(fp,NEC_BW); + MacroLoadNecRegisterFromFile(fp,NEC_CW); + MacroLoadNecRegisterFromFile(fp,NEC_DW); + MacroLoadNecRegisterFromFile(fp,NEC_CS); + MacroLoadNecRegisterFromFile(fp,NEC_DS); + MacroLoadNecRegisterFromFile(fp,NEC_ES); + MacroLoadNecRegisterFromFile(fp,NEC_SS); + MacroLoadNecRegisterFromFile(fp,NEC_IX); + MacroLoadNecRegisterFromFile(fp,NEC_IY); + MacroLoadNecRegisterFromFile(fp,NEC_BP); + MacroLoadNecRegisterFromFile(fp,NEC_SP); + MacroLoadNecRegisterFromFile(fp,NEC_FLAGS); + MacroLoadNecRegisterFromFile(fp,NEC_VECTOR); + MacroLoadNecRegisterFromFile(fp,NEC_PENDING); + MacroLoadNecRegisterFromFile(fp,NEC_NMI_STATE); + MacroLoadNecRegisterFromFile(fp,NEC_IRQ_STATE); + + read(fp,internalRam,65536); + read(fp,ws_staticRam,65536); + read(fp,ws_ioRam,256); + read(fp,ws_paletteColors,8); + read(fp,ws_palette,16*4*2); + read(fp,wsc_palette,16*16*2); + read(fp,&ws_newVideoMode,1); + read(fp,&ws_gpu_scanline,1); + read(fp,externalEeprom,131072); + + ws_audio_readState(fp); + close(fp); + + // force a video mode change to make all tiles dirty + ws_gpu_clearCache(); + return(1); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +#define MacroStoreNecRegisterToFile(F,R) \ + value=nec_get_reg(R); \ + write(fp,&value,sizeof(value)); + +int ws_saveState(char *statepath) +{ + uint16 crc=memory_getRomCrc(); + unsigned value; + char *newPath; + fprintf(log_get(),"saving %s\n",statepath); + + newPath=new char[1024]; + if (strlen(statepath)<4) + sprintf(newPath,"%s.wss",statepath); + else + { + int len=strlen(statepath); + if ((statepath[len-1]!='s')&&(statepath[len-1]!='S')) + sprintf(newPath,"%s.wss",statepath); + else + if ((statepath[len-2]!='s')&&(statepath[len-2]!='S')) + sprintf(newPath,"%s.wss",statepath); + else + if ((statepath[len-3]!='w')&&(statepath[len-3]!='w')) + sprintf(newPath,"%s.wss",statepath); + else + if (statepath[len-4]!='.') + sprintf(newPath,"%s.wss",statepath); + else + sprintf(newPath,"%s",statepath); + } + int fp=open(newPath,O_BINARY|O_RDWR|O_CREAT); + delete newPath; + if (fp==-1) + return(0); + write(fp,&crc,2); + MacroStoreNecRegisterToFile(fp,NEC_IP); + MacroStoreNecRegisterToFile(fp,NEC_AW); + MacroStoreNecRegisterToFile(fp,NEC_BW); + MacroStoreNecRegisterToFile(fp,NEC_CW); + MacroStoreNecRegisterToFile(fp,NEC_DW); + MacroStoreNecRegisterToFile(fp,NEC_CS); + MacroStoreNecRegisterToFile(fp,NEC_DS); + MacroStoreNecRegisterToFile(fp,NEC_ES); + MacroStoreNecRegisterToFile(fp,NEC_SS); + MacroStoreNecRegisterToFile(fp,NEC_IX); + MacroStoreNecRegisterToFile(fp,NEC_IY); + MacroStoreNecRegisterToFile(fp,NEC_BP); + MacroStoreNecRegisterToFile(fp,NEC_SP); + MacroStoreNecRegisterToFile(fp,NEC_FLAGS); + MacroStoreNecRegisterToFile(fp,NEC_VECTOR); + MacroStoreNecRegisterToFile(fp,NEC_PENDING); + MacroStoreNecRegisterToFile(fp,NEC_NMI_STATE); + MacroStoreNecRegisterToFile(fp,NEC_IRQ_STATE); + + write(fp,internalRam,65536); + write(fp,ws_staticRam,65536); + write(fp,ws_ioRam,256); + write(fp,ws_paletteColors,8); + write(fp,ws_palette,16*4*2); + write(fp,wsc_palette,16*16*2); + write(fp,&ws_videoMode,1); + write(fp,&ws_gpu_scanline,1); + write(fp,externalEeprom,131072); + + ws_audio_writeState(fp); + close(fp); + + return(1); +} +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +// +//////////////////////////////////////////////////////////////////////////////// +int ws_rotated(void) +{ + uint8 *rom=memory_getRom(); + uint32 romSize=memory_getRomSize(); + + return(rom[romSize-4]&1); +} diff --git a/oswan/source/ws.h b/oswan/source/ws.h new file mode 100644 index 0000000..864b8c4 --- /dev/null +++ b/oswan/source/ws.h @@ -0,0 +1,33 @@ +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// +// +// +// +// +// +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef __WS_H__ +#define __WS_H__ + +#define WS_SYSTEM_MONO 0 +#define WS_SYSTEM_COLOR 1 +#define WS_SYSTEM_AUTODETECT 2 + +// à supprimer ! +extern uint32 ws_cyclesByLine; + +int ws_init(char *rompath); +int ws_rotated(void); +void ws_set_colour_scheme(int scheme); +void ws_set_system(int system); +void ws_reset(void); +int ws_executeLine(int16 *framebuffer, int renderLine); +void ws_patchRom(void); +int ws_loadState(char *statepath); +int ws_saveState(char *statepath); +void ws_done(void); + +#endif diff --git a/oswan/testserial.c b/oswan/testserial.c new file mode 100644 index 0000000..9534360 --- /dev/null +++ b/oswan/testserial.c @@ -0,0 +1,161 @@ +#include +#include +#include +#include +#include +#include /* UNIX standard function definitions */ +#include /* Error number definitions */ +#include /* POSIX terminal control definitions */ + +/* Serial port */ +#define BDR_9600 (0) +#define BDR_38400 (1) +#define SERIAL_PORT "/dev/cu.usbserial-FTE3AXGN" +int serialfd = -1; +int serial_have_data = 0; +unsigned char serial_data = 0; +int serial_speed = BDR_38400; +void open_serial() +{ + if (serialfd < 0) + { + serialfd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY); + + //set_baudrate(serial_speed); + serial_have_data = 0; + } +} + +void set_baudrate(int speed) +{ + struct termios options; + if (serialfd < 0) + return; + + tcgetattr(serialfd, &options); + + options.c_cflag &= ~PARENB; + options.c_cflag &= ~CSTOPB; + options.c_cflag &= ~CSIZE; + options.c_cflag |= CS8; + + if (speed == BDR_9600) + { + cfsetispeed(&options, B9600); + } + else + { + cfsetospeed(&options, B38400); + } + +// options.c_cflag &= ~CNEW_RTSCTS; + options.c_cflag |= (CLOCAL | CREAD); + options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + + tcsetattr(serialfd, TCSANOW, &options); + + /* Make sure read is not blocking */ + fcntl(serialfd, F_SETFL, FNDELAY); +} + +void close_serial() +{ + close(serialfd); + serialfd = -1; +} + +void check_serial_data() +{ + unsigned char buf[10]; + int f; + if (serialfd < 0) + return; + + if (serial_have_data == 0) + { + f = read(serialfd, buf, 1); + if (f > 0) + { + //printf("Ho [%d]!\n", f);fflush(stdout); + serial_have_data = 0x01; + serial_data = buf[0]; + } + } +} + +unsigned char read_serial() +{ + unsigned char buf[10]; + int f; + if (serialfd < 0) + return 0xFF; + if (serial_have_data > 0) + { + serial_have_data = 0; + return serial_data; + } + f = read(serialfd, buf, 1); + + if (f == 1) + return buf[0]; + + return 0x42; +} + +void write_serial(unsigned char value) +{ + if (serialfd < 0) + return; + write(serialfd, &value, 1); +} + +void fuzz(unsigned char *buf) +{ + if ((rand() % 200) < 5) + { + switch(rand() % 8) + { + case 0: write_serial(0xF6); *buf = rand()%0x10; printf("x"); break; + case 1: write_serial(0xFB); *buf = rand()%0x10; printf("a"); break; + //case 2: write_serial(0xF5); *buf = rand()%0xFF; printf("b"); break; + //case 3: *buf ^= 0x08; printf("c"); break; + //case 4: *buf ^= 0x10; printf("d"); break; + //case 5: *buf ^= 0x20; printf("e"); break; + //case 6: *buf ^= 0x40; printf("f"); break; + //case 7: *buf ^= 0x80; printf("g"); break; + } + fflush(stdout); + } + /* else + printf(" ");*/ +} + +int main(int argc, char *argv[]) +{ + int i = 0; + unsigned char buf; + open_serial(); + if (argc > 1) + set_baudrate(atoi(argv[1])); + else + set_baudrate(0); + + printf("Run!\n"); + while(1) + { + while(serial_have_data == 0) check_serial_data(); + buf = read_serial(); + // if (buf != 0xFC) + //{ + printf("%02X ", buf); fflush(stdout); + i++; + //} + //fuzz(&buf); + if (i >= 32) + { + i = 0; + printf("\n"); + } + write_serial(buf); + } +} diff --git a/oswan/wonderswan.dsp b/oswan/wonderswan.dsp new file mode 100644 index 0000000..f380ada --- /dev/null +++ b/oswan/wonderswan.dsp @@ -0,0 +1,409 @@ +# Microsoft Developer Studio Project File - Name="wonderswan" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=wonderswan - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "wonderswan.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "wonderswan.mak" CFG="wonderswan - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "wonderswan - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "wonderswan - Win32 Debug" (based on\ + "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "wonderswan - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /G6 /MT /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FR /YX /FD /c +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 comctl32.lib comdlg32.lib kernel32.lib user32.lib gdi32.lib winmm.lib winspool.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "wonderswan - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /Gm /GX /Zi /O2 /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 comctl32.lib comdlg32.lib kernel32.lib user32.lib gdi32.lib winspool.lib winmm.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "wonderswan - Win32 Release" +# Name "wonderswan - Win32 Debug" +# Begin Group "nec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\source\nec\nec.cpp + +!IF "$(CFG)" == "wonderswan - Win32 Release" + +# ADD CPP /W1 + +!ELSEIF "$(CFG)" == "wonderswan - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\source\nec\nec.h +# End Source File +# Begin Source File + +SOURCE=.\source\nec\necea.h +# End Source File +# Begin Source File + +SOURCE=.\source\nec\necinstr.h +# End Source File +# Begin Source File + +SOURCE=.\source\nec\necmodrm.h +# End Source File +# End Group +# Begin Group "documentation" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\documentation\ws_communication.txt +# End Source File +# Begin Source File + +SOURCE=.\documentation\ws_controls.txt +# End Source File +# Begin Source File + +SOURCE=.\documentation\ws_dma.txt +# End Source File +# Begin Source File + +SOURCE=.\documentation\ws_external_eeprom.txt +# End Source File +# Begin Source File + +SOURCE=.\documentation\ws_gpu.txt +# End Source File +# Begin Source File + +SOURCE=.\documentation\ws_hardware_type.txt +# End Source File +# Begin Source File + +SOURCE=.\documentation\ws_internal_eeprom.txt +# End Source File +# Begin Source File + +SOURCE=.\documentation\ws_interrupts.txt +# End Source File +# Begin Source File + +SOURCE=.\documentation\ws_lcd_control.txt +# End Source File +# Begin Source File + +SOURCE=.\documentation\ws_line_execution_behaviour.txt +# End Source File +# Begin Source File + +SOURCE=.\documentation\ws_palette.txt +# End Source File +# Begin Source File + +SOURCE=.\documentation\ws_realtimeclock.txt +# End Source File +# Begin Source File + +SOURCE=.\documentation\ws_rom_banks_selectors.txt +# End Source File +# Begin Source File + +SOURCE=.\documentation\ws_rom_header.txt +# End Source File +# Begin Source File + +SOURCE=.\documentation\ws_sound.txt +# End Source File +# Begin Source File + +SOURCE=.\documentation\ws_tileformat.txt +# End Source File +# Begin Source File + +SOURCE=.\documentation\wstech20.txt +# End Source File +# Begin Source File + +SOURCE=.\documentation\wstech20work.txt +# End Source File +# End Group +# Begin Group "tools" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\source\log.cpp +# End Source File +# Begin Source File + +SOURCE=.\source\LOG.H +# End Source File +# Begin Source File + +SOURCE=.\source\ticker.h +# End Source File +# Begin Source File + +SOURCE=.\source\ticker.obj +# End Source File +# Begin Source File + +SOURCE=.\source\types.h +# End Source File +# End Group +# Begin Group "gui" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\gui.rc + +!IF "$(CFG)" == "wonderswan - Win32 Release" + +!ELSEIF "$(CFG)" == "wonderswan - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\source\gui\logo.bmp +# End Source File +# Begin Source File + +SOURCE=.\source\gui\sponsor.bmp +# End Source File +# End Group +# Begin Group "sdl" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\source\sdl\include\SDL.h +# End Source File +# Begin Source File + +SOURCE=.\source\sdl\SDL.lib +# End Source File +# Begin Source File + +SOURCE=.\source\sdl\SDLmain.lib +# End Source File +# Begin Source File + +SOURCE=.\source\sdl\include\SDLptc.h +# End Source File +# End Group +# Begin Group "wonderswan" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\source\audio.cpp +# End Source File +# Begin Source File + +SOURCE=.\source\audio.h +# End Source File +# Begin Source File + +SOURCE=.\source\gpu.cpp +# End Source File +# Begin Source File + +SOURCE=.\source\gpu.h +# End Source File +# Begin Source File + +SOURCE=.\source\ieeprom.h +# End Source File +# Begin Source File + +SOURCE=.\source\initialIo.h +# End Source File +# Begin Source File + +SOURCE=.\source\io.cpp +# End Source File +# Begin Source File + +SOURCE=.\source\io.h +# End Source File +# Begin Source File + +SOURCE=.\source\memory.cpp +# End Source File +# Begin Source File + +SOURCE=.\source\memory.h +# End Source File +# Begin Source File + +SOURCE=.\source\rom.cpp +# End Source File +# Begin Source File + +SOURCE=.\source\rom.h +# End Source File +# Begin Source File + +SOURCE=.\source\ws.cpp +# End Source File +# Begin Source File + +SOURCE=.\source\ws.h +# End Source File +# End Group +# Begin Group "filters" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\source\2xSaI.cpp +# End Source File +# Begin Source File + +SOURCE=.\source\2xSaI.h +# End Source File +# Begin Source File + +SOURCE=.\source\filters\2xsai.h +# End Source File +# Begin Source File + +SOURCE=.\source\filters\doubled.h +# End Source File +# Begin Source File + +SOURCE=.\source\filters\filter_partA.h +# End Source File +# Begin Source File + +SOURCE=.\source\filters\filter_partB.h +# End Source File +# Begin Source File + +SOURCE=.\source\filters\filter_partC.h +# End Source File +# Begin Source File + +SOURCE=.\source\filters\filter_partD.h +# End Source File +# Begin Source File + +SOURCE=.\source\filters\filter_partE.h +# End Source File +# Begin Source File + +SOURCE=.\source\filters\halfscanlines.h +# End Source File +# Begin Source File + +SOURCE=.\source\filters\scanlines.h +# End Source File +# Begin Source File + +SOURCE=.\source\filters\special.h +# End Source File +# Begin Source File + +SOURCE=.\source\filters\standard.h +# End Source File +# Begin Source File + +SOURCE=.\source\filters\super2xsai.h +# End Source File +# Begin Source File + +SOURCE=.\source\filters\supereagle.h +# End Source File +# End Group +# Begin Group "seal" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\source\seal\AUDIO.H +# End Source File +# Begin Source File + +SOURCE=.\source\seal\AUDW32VC.LIB +# End Source File +# End Group +# Begin Source File + +SOURCE=.\source\temp\key.h +# End Source File +# Begin Source File + +SOURCE=.\main.cpp +# End Source File +# End Target +# End Project diff --git a/oswan/wonderswan.dsw b/oswan/wonderswan.dsw new file mode 100644 index 0000000..e6ea04d --- /dev/null +++ b/oswan/wonderswan.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "wonderswan"=.\wonderswan.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/seal-hack/ChangeLog b/seal-hack/ChangeLog new file mode 100644 index 0000000..548c88b --- /dev/null +++ b/seal-hack/ChangeLog @@ -0,0 +1,44 @@ +Release 1.0.7 July 30th, 1999 + - Source code released under the GNU Lesser General Public License (LGPL) + +Release 1.0.6 December 25th, 1998 + - New API functions ASetAudioMixerValue and AUpdateAudioEx + - Minor fixes in ENSONIQ SoundScape and Windows Sound System drivers + - Fixed DJGPP memory protection fault due to page swapping + - Windows 95 and NT driver thread priority changed + - Workaround to get sound on some SB compatible cards + - Port to Intel BeOS R4 platforms + - New experimental accelerated DirectSound driver + +Release 1.0.5 October 18th, 1998 + - Fixed problems with ENSONIQ AudioPCI cards (Thanks Bomb!) + - Port to OS/2 platforms (Thanks Marty!) + - Port to Intel BeOS R3 platforms + - HTML documentation + +Release 1.0.4 April 12th, 1998 + - Memory leak in AFreeWaveFile() fixed + - New API call to retrieve tracks' parameters + +Release 1.0.3 January 9th, 1997 + - Windows Wave and DirectSound drivers bug fixes + - Minor bug fix in XM module file loader + - Silence driver now actually "play" modules + +Release 1.0.1 September 25th, 1996 + - Support for DirectSound in Windows 95 and NT + - Support for Sound Blaster AWE32 (EMU8000) sound cards + - Support for Ultrasound PnP (InterWave) sound cards + - Support for MultiTracker 1.0 module files + - New synchronization callback feature + - New file offset parameter in loading routines + - Data type names changed for better portability + - Fixed mono playback for non-wavetable sound cards + - Volume was too quiet for 8-bit sound cards + - Fixed WATCOM C/C++ 10.x naming convention bug + - Fixed 4DOS-only batch files to work with COMMAND.COM + - Many other minor bug fixes + +Release 1.0.0 June 8th, 1996 + - First release + diff --git a/seal-hack/FILE_ID.DIZ b/seal-hack/FILE_ID.DIZ new file mode 100644 index 0000000..5d2c5a4 --- /dev/null +++ b/seal-hack/FILE_ID.DIZ @@ -0,0 +1,13 @@ +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +SEAL Audio Library Release 1.0.7 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +32-bit multichannel audio system +for DOS, Windows 95, Windows NT, +OS/2, BeOS and Linux platforms. +Supports SB, SBPro, SB16, AWE32, +PAS, PAS16, GUS, GUSDB, GUSMAX, +IW, WSS, ESS and Aria cards. +Plays MOD/MTM/S3M/XM modules. +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +Full source code available! +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= diff --git a/seal-hack/LICENSE.TXT b/seal-hack/LICENSE.TXT new file mode 100644 index 0000000..1c74db3 --- /dev/null +++ b/seal-hack/LICENSE.TXT @@ -0,0 +1,505 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + +Copyright (C) 1991, 1999 Free Software Foundation, Inc. +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Library, + and can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work based + on the Library, the distribution of the whole must be on the terms of + this License, whose permissions for other licensees extend to the + entire whole, and thus to each and every part regardless of who wrote + it. + + Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Library. + + In addition, mere aggregation of another work not based on the Library + with the Library (or with a work based on the Library) on a volume of + a storage or distribution medium does not bring the other work under + the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) year name of author + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in + the library `Frob' (a library for tweaking knobs) written + by James Random Hacker. + + signature of Ty Coon, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/seal-hack/Makefile b/seal-hack/Makefile new file mode 100644 index 0000000..6c245b9 --- /dev/null +++ b/seal-hack/Makefile @@ -0,0 +1,6 @@ +all: + cd src ; make + +clean: + -rm lib/SDL/*.a + cd src ; make clean diff --git a/seal-hack/README.OS2 b/seal-hack/README.OS2 new file mode 100644 index 0000000..edbbfa7 --- /dev/null +++ b/seal-hack/README.OS2 @@ -0,0 +1,39 @@ +This is the OS/2 port of the Synthetic Audio Library (SEAL). + +The DLL included can be used to add OS/2 native support for playing module +files and streamed audio to OS/2 Presentation Manager (PM) and VIO +applications. It can also be used to assist in the porting of other DOS, +Windows, and Linux applications that also use the SEAL API. + +To build applications with the SEAL library, simply link them with the +AUDIO.LIB file and include the AUDIO.H file in your programs. The standard SEAL +documentation covers the usage of the standard SEAL API. There are a few +additional considerations in using the OS/2 version: + +* The OS/2 version is multithreaded. This means that the SEAL library is + updating the audio buffers in the background while the rest of your + application is running. Unlike the DOS and Windows versions, you DO NOT + HAVE TO call the AUpdateAudio function to update the audio buffers. This + also means that some care needs to be taken when updating the voices + and sound buffers yourself. It is recommended that you use DosEnterCritSec + and DosExitCritSec around areas where voices are created and destroyed. + +* Some of the SEAL API functions require other threads to be running when + they are called. If you are in a critical section when you call some + functions, it can cause deadlock because the critical section prevents + other threads in the same task from running. Do not call the following + functions in a critical section: AOpenAudio, ACloseAudio, AUpdateAudio. + +* The AUpdateAudio function was implemented, but not to update the audio. + It was made to be a means of synchronizing your application with the audio + stream. When you call AUpdateAudio, the calling thread will block until + an audio buffer needs more data. For a good example of how to use this + function and the rest of the SEAL API, ask me for the source code for + MAME for OS/2. E-mail me at mta3206@grace.isc.rit.edu. + + +There are no known OS/2 specific bugs at this time. + +Look for a DART-enabled version soon. + +- Marty diff --git a/seal-hack/README.TXT b/seal-hack/README.TXT new file mode 100644 index 0000000..f4c303d --- /dev/null +++ b/seal-hack/README.TXT @@ -0,0 +1,224 @@ + +Synthetic Audio Library (SEAL) Development Kit +Copyright (C) 1995, 1996, 1997, 1998, 1999 Carlos Hasan +All Rights Reserved + +OS/2 Sound Driver Copyright (C) 1998 Martin Amodeo + + +This 1.0.7 release of the Synthetic Audio Library (SEAL) lets you write +applications that conform to the 1.0 SEAL API which is able to play +digital audio waveforms and music modules on many platforms. + + +What's New +---------- + + - Source code released under the GNU Lesser General Public License (LGPL) + +Features +-------- + - simple and powerful API interface + - 32 simultaneous digital audio channels + - smooth pitch shifting, volume and panning controllers per channel + - smart digital filtering for improved sound quality + - efficient digital audio waveform mixing algorithms combined with + uncompromising low-level optimizations + - importing of wave and music file formats such as Protracker 1.1, + MultiTracker 1.0, Scream Tracker 3.0 and FastTracker 2.0 modules + - performance tuned for the i486 and Pentium processors + - native support in DOS for hardware wavetable accelerators such + as the Sound Blaster AWE32, Gravis Forte's UltraSound, and normal + digital audio devices such as the Sound Blaster 1.5/2.0/Pro/16, + Pro Audio Spectrum 16, Windows Sound System, Ensoniq Soundscape + and Aria soundcards + + +Supported platforms +------------------- +The SEAL SDK is available for DOS, Extended DOS, Windows 95, Windows NT, +OS/2, BeOS and Linux platforms. FreeBSD, SPARC SunOS, SPARC Solaris and +SGI Indigo ports are in progress. The following compilers were used to +build the library files: + + - Borland C++ 4.5 compiler for DOS and Win32s + - WATCOM C/C++ 10.0 compiler for DOS and Windows + - Microsoft Visual C++ 4.1 compiler for Windows 95 + - DJGPP 2.0 port of GNU C/C++ compiler for DOS + - GNU C/C++ 2.7.0 for Linux (a.out and ELF) + - Metrowerks CodeWarrior C++ for Intel BeOS Release 3 + - EMX port of GNU CC 2.7.x for OS/2 platforms + + +The SEAL SDK contains +--------------------- + - SEAL API header and library files + - SEAL audio library source code files (GPL license) + - set of example source code files + + +--------------------------------------------------------------------- +IMPORTANT: Please make sure you understand the Copyright and License +information (in the file named LICENSE.TXT) before using this release. +--------------------------------------------------------------------- + + +Installing the Software +----------------------- +The SEAL SDK can be installed unpacking the distribution archive +in your hard disk. For example, + + C:\>PKUNZIP -d SEAL107.ZIP + +The SEAL SDK include and library directories can be installed in +your C programming environment modifying the header and library +directory paths. Here are some examples to compile and link +the SEAL audio system library with your own programs: + + - WATCOM C/C++32 10.0 and DOS4GW DOS Extender: + wcl386 -I\audio\include example.c \audio\lib\dos\audiowcf.lib + + - DJGPP 2.0 port of GNU CC for DOS/DPMI32: + gcc -I\audio\include -o example example.c \audio\lib\dos\audiodjf.a + + - Visual C/C++ 4.1 for Windows 95 and Windows NT: + cl -DWIN32 -I\audio\include example.c \audio\lib\Win32\audw32vc.lib + + - Borland C++ 4.5 for Win32s: + bcc32a -WC -I\audio\include example.c \audio\lib\Win32\audw32bc.lib + + - GNU CC 2.7.0 for Linux (ELF binaries): + gcc -Iaudio/include -o example example.c audio/lib/Linux/libaudio.a + + - Metrowerks CodeWarrior C++ for BeOS R3: + mwcc -Iaudio/include -o example example.c audio/lib/BeOS/libaudio.a + +The above examples assume that the audio system was installed at the +root directory of the current drive. For Windows 95 and Windows NT +applications you must copy the AUDIOW32.DLL dynamic-link library into +the Windows system directory, usually located at C:\WINDOWS\SYSTEM in +your hard disk. + + +Notes about DOS Drivers +----------------------- +For applications running in DOS, the audio system will try to detect +the hardware sound devices installed on your system. Since there can +be problems to autodetect your sound hardware, your application should +provide a way to force the use of a particular audio device driver. + +Here is a list of notes for the autodetection methods used by the audio +device drivers under the DOS operating system: + + - Sound Blaster 1.0/1.5/2.0/Pro/16 device drivers: + These drivers use the BLASTER environment variable to determine + the hardware I/O base port address, IRQ interrupt line and DMA + channels. The model of the card is then determined by hardware + reading the DSP version number. If you do not get sound, try + forcing other SB model by using the "T" parameter of the BLASTER + environment variable: + + T1 = Sound Blaster 1.0 + T2 = Sound Blaster 1.5 + T3 = Sound Blaster 2.0 + T4 = Sound Blaster Pro + T6 = Sound Blaster 16 + + - Sound Blaster AWE32 and Sound Blaster 32 device drivers: + The driver uses the BLASTER environment variable, you must + specify the EMU8000 I/O base port address parameter. If your + card does not have DRAM local sound memory, you must use the + card as a Sound Blaster 16 or earlier. + + - Pro Audio Spectrum, Pro Audio Spectrum Plus/16 device drivers: + These drivers need to have the MVSOUND.SYS driver installed + in your CONFIG.SYS configuration file. The model of the card + is determined by hardware checking the card features bits. + + - Gravis Ultrasound, Ultrasound MAX device drivers: + This driver uses the ULTRASND environment variable to determine + the hardware configuration of your card. For applications using + the DOS4GW extender, the GF1-IRQ number must be less than 8 to + work correctly. + + - Gravis Ultrasound Daughterboard / MAX (CS4231) device drivers: + This driver uses the CS4231 codec of your GUS DB/MAX card, so + you must have the ULTRASND and ULTRA16 environment variables. + + - Gravis Ultrasound PnP (Pro), InterWave-based device drivers: + This driver uses the ULTRASND and INTERWAVE environment variables + to determine the hardware configuration of your sound board. + + - Windows Sound System device driver: + This driver automatically detect WSS sound devices installed + at the 530, E80, F40 or 604 I/O base port addresses and uses + by default the IRQ line #7 and DMA channel #1 for playback. + Since there can be hardware conflicts, the driver first check + for the WSSCFG environment variable which has the following + format: + SET WSSCFG=Annn In Dn + | | | + | | +-- DMA channel (0,1,3) + | +---- IRQ number (7,9,10,11) + +----- I/O port (530,E80,F40,604) + + You must write the above command in your AUTOEXEC.BAT start-up + batch file. Also, some WSS clone devices need to run an utility + to put the card in WSS mode (ie. MAD16 OPTi-based cards). + + - Ensoniq Soundscape, Soundscape Elite device drivers: + These drivers uses the SNDSCAPE environment variable to read + the SNDSCAPE.INI configuration file. + + - Sierra Semoconductors' Aria sound card driver: + This driver uses the ARIA environment variable to read the + hardware configuration parameters. + + - Ensoniq AudioPCI and Creative PCI64 sound cards: + These cards have to be configured in Legacy emulation mode + under DOS. The library will use these cards as Ensoniq + SoundScape ISA cards. + +If you experience any problems, please try avoiding autodetection and +tell your application what device driver to use. Also, ensure your +system has no TSR's loaded in memory (such as SBOS for GUS cards). + + +Notes about Windows 95 +---------------------- +The SEAL audio system for DOS and Extended DOS has been sucessfully +tested under Windows 95 DOS boxes running in foreground. However, +some Windows 95 sound drivers might not be able to share the sound +hardware with DOS sessions (such as the Ultrasound drivers). In such +cases, you must either remove the Windows 95 drivers or exit to DOS +to run your DOS programs. + + +Notes about Linux +----------------- +The SEAL audio system for Linux uses the UNIX Sound System interface, +also known as the VoxWare Kit. The audio system can be easily ported +to other UNIX operating system running in Intel x86 platforms where +the UNIX Sound System interface is also available, such as FreeBSD, +386bsd, SCO and SVR4.2 operating systems. + + +Notes about BeOS +---------------- +The SEAL audio library for Intel BeOS Release 3 also works with +New MediaKit sound drivers found on BeOS R4. The SEAL 1.06 library +comes with ELF binaries for Intel BeOS Release 4. + + +Contacting the Author +--------------------- +If you have questions, problems or comments you can contact the author +at the following email address: chasan@dcc.uchile.cl. + + +Closing Words +------------- +I would like to thank all the beta testers and specially to Jon L. +for the music module file used by the example programs, and to all +the IRC friends at the #coders channel. + diff --git a/seal-hack/doc/man.html b/seal-hack/doc/man.html new file mode 100644 index 0000000..74bb7e8 --- /dev/null +++ b/seal-hack/doc/man.html @@ -0,0 +1,1635 @@ + + + + +SEAL Synthetic Audio Library 1.07 + + + + + +

SEAL Synthetic Audio Library 1.07

+

Programmer's Guide

+ +
+

Copyright Information

+ +Information in this document is subject to change without notice. No part of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, for any purpose, without the express written permission of the author.

+ + The Synthetic Audio Library Software Developer Kit
+ Copyright (C) 1995-1999 Carlos Hasan
+
+ This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version.

+ +If you have questions, problems or comments about the SEAL audio system you can contact the author at the following Internet email address:

+ +Carlos Hasan
+chasan@dcc.uchile.cl +


+ + +

About the Synthetic Audio Library

+ +The Synthetic Audio Library application programming interface allows your applications to play digital audio waveforms and multichannel music sequences in your applications, provides low-latency mixing, hardware acceleration and dynamic digital filtering for improved sound quality.

+ +The SEAL API allows you, as an application developer, access the audio hardware while insulating you from the specific details of that hardware. The design goal of SEAL is speed. Instead of providing a high-level set of functions, it provides a device-independant interface, allowing applications to take full adventage of the capabilities of the audio hardware.

+ +

Supported Platforms and Hardware

+ +The Synthetic Audio Library SEAL SDK is available for DOS, Extended DOS, Windows 95, Windows NT and Linux operating systems. The following compilers are supported in the current version of the audio system:

+ +

    +
  • WATCOM C/C++32 10.0 Compiler for DOS4GW and Win32
  • +
  • DJGPP 2.0 Compiler port of GNU CC for DOS/DPMI32
  • +
  • GNU CC 2.7.0 Compiler for Linux (a.out and ELF) operating system
  • +
  • Visual C++ 4.1 Compiler for Windows 95 and Windows NT
  • +
  • Borland Delphi 2.0 Compiler for Windows 95 and Windows NT
  • +
  • Metrowerks CodeWarrior C++ for BeOS Intel Release 3
  • +
  • GNU CC Compiler for BeOS Intel Release 4
  • +
  • EMX port of GNU CC 2.7.x Compiler for OS/2 operating system
  • +
+ +Any other language for Windows 95 or Windows NT with 32-bit dynamic link libraries support, such as Visual Basic or Borland C++ 5.0, should also be able to use the audio system AUDIOW32.DLL dynamic link library.

+ +Under the DOS operating system the following hardware audio devices are natively supported by the audio system:

+ +

    +
  • Sound Blaster 1.0
  • +
  • Sound Blaster 1.5
  • +
  • Sound Blaster 2.0
  • +
  • Sound Blaster Pro I and II
  • +
  • Sound Blaster 16 / ASP
  • +
  • Sound Blaster 32
  • +
  • Sound Blaster AWE32
  • +
  • Creative PCI64 and PCI128 cards
  • +
  • Windows Sound System
  • +
  • Ensoniq Soundscape
  • +
  • Ensoniq Soundscape Elite
  • +
  • Ensoniq AudioPCI cards
  • +
  • Gravis Ultrasound
  • +
  • Gravis Ultrasound Daughterboard
  • +
  • Gravis Ultrasound MAX
  • +
  • AMD InterWave-based boards
  • +
  • Pro Audio Spectrum
  • +
  • Pro Audio Spectrum Plus
  • +
  • Pro Audio Spectrum 16
  • +
  • Aria sound cards
  • +
+ +Other sound devices compatible with any of the above sound boards are also supported.

+ + +

Data Types

+ +The most fundamental data types used in the audio system are waveforms, modules and voices. The waveform data type represent digital audio data of individual sources of sound, modules represent multichannel music sequences, and voices represent monophonic audio channels used to play waveforms. Each voice can control the sound characteristics of the waveform that is being played through it, such as frequency and volume levels. + +

Features

+ +
    +
  • Mixing +The most used feature of the audio system is the low-latency mixing of digital audio channels. Your application can create up to 32 voices to play concurrently audio data through your sound device. The audio system mixes all the active voices and writes the result to the audio hardware.
  • + +Low-latency mixing allows the user to experience no perceptible delay between the time that the application start playing a waveform through the audio hardware and the time that the speakers reproduct the sound.

    + +

  • Hardware Acceleration +The SEAL audio system automatically takes advantage of accelerated sound hardware, including hardware mixing and hardware local memory. Your application does not need to query the hardware to specifically use hardware acceleration.
  • +
+ +
+ +

Audio Device Interface

+ +

Initialization

+ +The audio device interface allows your application to communicate and control the audio hardware on the system. Your application must initialize the audio system to be able to start using it by calling the AInitialize routine. It's not required for Windows 95 and Windows NT applications.

+ +

Device Capabilities

+ +Before initializing the audio device for playback, your application can enumerate and retrieve information of the registered audio device drivers. The device drivers are enumerated starting from zero, and the AGetAudioNumDevs routine returns the number of audio device drivers installed on the system. The application can retrieve the capabilities information of any of the installed audio device drivers by calling the routine AGetAudioDevCaps.

+ +Your application can also call the routine APingAudio to determine what kind of audio hardware is present on the system. If there is more than one device present on the system, the first detected audio device will be used.

+ +

Opening the Audio Device

+ +After investigating the capabilities of the sound device, your application can open the audio hardware for playback calling AOpenAudio and specifying what audio device, output format, and sampling frequency should be used. Since the specified audio device might not support the desired parameters, the audio system will use the closest configuration supported by the audio hardware.

+ +While the audio system is active, your application must call the routine AUpdateAudio to update and send the output audio buffers to the audio hardware. It's not required for Windows 95 and Windows NT applications.

+ +

Closing the Audio Device

+ +Applications can release the audio hardware by calling the ACloseAudio routine. It's very important to release all the allocated waveforms, modules and voice resources before closing the audio system. + +

Timer Interrupt Services

+ +Your application can install a virtual audio timer interrupt callback routine by calling the ASetAudioTimerProc routine. The rate or speed at which the virtual audio timer routine is called can be changed by calling the routine ASetAudioTimerRate. Since the installed timer callback routine can be called from within a hardware interrupt handler, for applications running under the DOS operating system, your timer routine has the same constrains than hardware interrupt handler routines.

+ +Since the audio system plays music sequences using the virtual audio timer interrupt services, your applications won't be able to play music modules and use the timer services simultaneously. You must use your own timer services if you want to play music in your applications. For applications running in DOS, the hardware timer interrupt vector can be used for such purposes.

+ + +

Audio Voice Interface

+ +

Creating Audio Voices

+ +Your application can allocate audio voices to play digital audio waveforms concurrently. After calling the routine AOpenVoices to specify the amount of available audio voices, your application can call the ACreateAudioVoice routine to allocate audio voices.

+ +Every allocated audio voice must be released by calling ADestroyAudioVoice whenever your application finishes using it. It's important to stop the audio voices before releasing them.

+ +The ACloseVoices routine must be called to release all the available audio voices when your application is going to close the audio system. Your application must stop all the voices and module files before calling it.

+ +

Play Management

+ +Your application can start playing a waveform through a voice by calling the APlayVoice or APrimeVoice routines. The real-time playback of the audio voices is controlled by calling the AStartVoice and AStopVoice routines. The voice stops automatically when the end of the waveform is reached. However, if looping is specified, the voice repeats until AStopVoice is called.

+ +To retrieve or set the current playing position in the waveform of an audio voice, call the AGetVoicePosition or ASetVoicePosition routines. The playing position of the voices is specified as an offset from the start of the waveform data measured in samples.

+ +

Environment Management

+ +To retrieve or set the volume at which a waveform is being played by a particular audio voice your application can call the AGetVoiceVolume and ASetVoiceVolume routines, respectively.

+ +Similarly, by calling the AGetVoiceFrequency and ASetVoiceFrequency routines, you can retrieve and set the sampling frequency at which the audio waveform is being resampled and played by a given audio voice.

+ +To retrieve and set the stereo pan position of an audio voice, your application can call the AGetVoicePanning and ASetVoicePanning routines. These routines have no effect when the system is playing in monophonic format.

+ +

Retrieving State Information

+ +The AGetVoiceStatus routine can be used by your application to determine the current state of an audio voice. The returned boolean value is true when the voice is stopped. Notice that a voice will never stop playing a looped waveform unless the AStopVoice is called.

+ + +

Audio Waveform Interface

+ +

Creating Waveforms

+ +Your application can load waveform files directly from disk by calling ALoadWaveFile. The routine AFreeWaveFile is called to release the waveform from memory. It's also possible to create and destroy custom waveforms calling the ACreateAudioData and ADestroyAudioData routines, respectively. Your application can't release a waveform while it's being played by one or more audio voices.

+ +

Playing Waveforms

+ +The waveform objects, that represent audio data of individual sound sources such as musical instruments or sound effects, can be played through audio voices calling the APlayVoice or APrimeVoice routines. See the Audio Voices Interface section for more information.

+ +

Audio Music Module Interface

+ +

Creating Modules

+ +Your application can load music module files directly from disk by calling ALoadModuleFile. The routine AFreeModuleFile is used to release modules from system memory. If the module file is being played by the audio system, your application must stop it to be able to release it from memory.

+ +

Play Management

+ +The APlayModule routine is used to select and start playing a music module. The audio system can't play music modules concurrently, but there is no limit in the amount of modules loaded in system memory. The AStopModule routine is called to stop playing the current music module, and to be able to select another module for playback or whenever the module is going to be released from memory. + +While a music module is being played by the audio system, your application can control the real-time playback of the module by calling the APauseModule and AResumeModule routines to pause or resume playing the music sequence.

+ +

Environment Management

+ +Your application can retrieve or set the current module position by calling the AGetModulePosition and ASetModulePosition routines. These positions are measured in orders and pattern rows.

+ +Similarly, the AGetModuleVolume and ASetModuleVolume routines can be used by your application to change the global volume at which the audio system is playing the music sequence. These routines can only be called while a music module is active.

+ +

Reference Guide

+ +

Functions

+ + + + +
UINT AIAPI Ainitialize(VOID)

+ +Initializes the Synthetic Audio Library.

+ +Returns zero on success.

+ +This routine must be called to initialize the audio system, after initialization your application can use the audio system API routines. It's not required to initialize the audio system for applications running in Windows 95 or Windows NT.

+ +See also AOpenAudio, ACloseAudio

+ + + +


UINT AIAPI AGetVersion(VOID)

+ +Retrieves the Synthetic Audio Library version.

+ +Returns the audio system major and minor version numbers.

+ +This routine can be used by your application to get the audio system version number, the major version number is encoded in the most significant byte of the returned value and the minor version number in the least significant byte.

+ + + +


UINT AIAPI AGetAudioNumDevs(VOID)

+ +Retrieves number of installed audio device drivers.

+ +Returns the number of device drivers installed on the system.

+ +This routine can be used by your application to enumerate the installed audio device drivers on the system. The AGetAudioDevCaps routine can be used to retrieve information from a particular audio device driver.

+ +See also AGetAudioDevCaps + + + +


UINT AIAPI AGetAudioDevCaps(UINT nDeviceId, LPAUDIOCAPS lpCaps)

+ +Retrieves information about audio device drivers.

+ +Return zero on success.

+ +

    +
  • nDeviceId +Audio device driver identifier.
  • + +
  • lpCaps +Address of an AUDIOCAPS structure that will hold the capabitilies information of the audio device driver referenced by the nDeviceId device driver identifier.
  • +
+ +This routine retrieves the audio capabilities information from an audio device driver identified by the nDevideId parameter. The AGetAudioNumDevs returns the number of installed audio devices on the system.

+ +

+    VOID PrintAudioDevs(VOID)
+    {
+        AUDIOCAPS caps;
+        UINT nDeviceId;
+
+        /* show all the installed device drivers */
+        for (nDeviceId = 0; nDeviceId < AGetAudioNumDevs(); nDeviceId++) {
+            AGetAudioDevCaps(nDeviceId, &caps);
+            printf("nDeviceId=%d wProductId=%d szProductName=%s\n",
+                   nDeviceId, caps.wProductId, caps.szProductName);
+        }
+    }
+
+ +See also AGetAudioNumDevs + + + +
UINT AIAPI AGetErrorText(UINT nErrorCode, LPSTR lpText, UINT nSize)

+ +Return readable text description for a given error return code.

+ +Return zero on success.

+ +

    +
  • nErrorCode +Numeric error return code to be translated.
  • + +
  • lpText +Address of the null-terminated text description buffer.
  • + +
  • nSize +Number of bytes of the text description buffer.
  • +
+ +Most of the routines in the Synthetic Audio Library return numeric error codes which can be translated to a readable text description using this routine. The returned text description is a null-terminated string of ASCII characters.

+ +

+    VOID InitializeAudio(VOID)
+    {
+        AUDIOINFO info;
+        CHAR szText[128];
+        UINT rc;
+
+        info.nDeviceId = AUDIO_DEVICE_MAPPER;
+        info.wFormat = AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO;
+        info.nSampleRate = 44100;
+        if ((rc = AOpenAudio(&info)) != AUDIO_ERROR_NONE) {
+            AGetErrorText(rc, szText, sizeof(szText) - 1);
+            printf("ERROR: %s\n", szText);
+            exit(1);
+       }
+    }
+
+ + + +
UINT AIAPI APingAudio(LPUINT lpnDeviceId)

+ +Automatically detect the installed audio device.

+ +Returns zero on success.

+ +

    +
  • lpnDeviceId +Address of an unsigned integer that will hold the detect device identifier.
  • +
+ +This routine can be used to determine which audio device is present on the system. Alternatively, your application can detect and use an audio device by using the virtual audio device identifer AUDIO_DEVICE_MAPPER to open the audio system with the AOpenAudio routine.

+ +

+    VOID DetectAudioDevice(VOID)
+    {
+        AUDIOCAPS caps;
+        UINT nDeviceId;
+
+        if (APingAudio(&nDeviceId) != AUDIO_ERROR_NONE) {
+            printf("no audio device found.\n");
+        }
+        else {
+            AGetAudioDevCaps(nDeviceId, &caps);
+            printf("%s device found.\n", caps.szProductName);
+        }
+    }
+
+ +See Also AOpenAudio, AGetAudioDevCaps + + + +
UINT AIAPI AOpenAudio(LPAUDIOINFO lpInfo)

+ +Open audio device for playback.

+ +Returns zero on success.

+ +

    +
  • lpInfo +Address of an AUDIOINFO structure that holds the playback configuration.
  • +
+ +This routine open a given audio device for playback at the specified format and sampling frequency. Since the hardware device might not support the desired configuration, the audio system will use the closest parameters which are then returned in the AUDIOINFO structure.

+ +

+    VOID InitializeAudio(VOID)
+    {
+        AUDIOINFO info;
+
+        info.nDeviceId = AUDIO_DEVICE_MAPPER;
+        info.wFormat = AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO;
+        info.nSampleRate = 44100;
+        if (AOpenAudio(&info) != AUDIO_ERROR_NONE) {
+            printf("Audio initialization failed.\n");
+            exit(1);
+        }
+        else {
+            printf("Audio device initialized at %d bits %s %u Hz\n",
+                   info.wFormat & AUDIO_FORMAT_16BITS ? 16 : 8,
+                   info.wFormat & AUDIO_FORMAT_STEREO ? 
+                   "stereo": "mono", info.nSampleRate);
+        }
+    }
+
+ +See Also ACloseAudio, AUpdateAudio + + + +
UINT AIAPI ACloseAudio(VOID)

+ +Close the audio device.

+ +Returns zero on success.

+ +This routine must be called to close the audio device before leaving from your application. Your application must release all the resources allocated before closing the audio system.

+ +See Also AOpenAudio, AUpdateAudio + + + +


UINT AIAPI AUpdateAudio(VOID)

+ +Updates the audio system output buffers.

+ +Returns zero on success.

+ +This routine must be called periodically by your application to update the audio buffers which are sent to the hardware for playback. If your application fails to call this routine enough times per second, the audio output will sound like a broken disc. It's not required to call this routine for Windows 95 and Windows NT applications.

+ +See Also AOpenAudio, ACloseAudio, AUpdateAudioEx + + + +


UINT AIAPI AUpdateAudioEx(UINT nFrames)

+ +Updates the audio system output buffers.

+ +Returns zero on success.

+ +

    +
  • nFrames +The maximum amount of sample frames to update in the output buffer. +
+ +This routine is similar to AUpdateAudio but lets you have more control on the latency of the audio system. It must be called to update up to nFrames sample frames in the output buffer. For example, every time you call AUpdateAudioEx(nSampleRate/100) the audio system will fill up to 10 ms of sound in the output buffer.

+ +See Also AOpenAudio, ACloseAudio, AUpdateAudio + + + +


UINT AIAPI ASetAudioMixerValue(UINT nChannel, UINT nValue)

+ +Changes the audio mixer settings.

+ +Returns zero on success.

+ +

    +
  • nChannel +The mixer channel identifier. +
  • nValue +The new mixer channel's value (0-256). +
+ +This routine changes the mixer level settings of the audio engine. Currently the only channel supported is the AUDIO_MIXER_MASTER_VOLUME channel which sets the overall mixing volume level for all the audio voices. + + +
UINT AIAPI ASetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave)

+ +Install audio wave callback routine. Internal use only.

+ +Returns zero on success.

+ +This routine is used internally by the audio system to install the audio wave callback routine used by the software wavetable synthesizer to fill the hardware DMA audio buffer with samples.

+ + + +


UINT AIAPI ASetAudioTimerProc(LPFNAUDIOTIMER lpfnAudioTimer)

+ +Install virtual audio timer callback routine.

+ +Returns zero on success.

+ +

    +
  • lpfnAudioTimer +Address of the timer handler routine.
  • +
+ +This routine set the virtual audio timer callback routine. Since the audio system uses this timer to play module files in background, your application should not use this routine while the system is playing a music sequence. The virtual timer callback can be called from a hardware interrupt handler for applications running in DOS.

+ +

+    volatile UINT nTickCounter = 0;
+
+    VOID AIAPI TimerHandler(VOID)
+    {
+        nTickCounter++;
+    }
+
+    VOID InitTimerHandler(VOID)
+    {
+        /* the handler will be called at 125 BPM (50 times per second) */
+        ASetAudioTimerProc(TimerHandler);
+        ASetAudioTimerRate(125);
+    }
+
+    VOID DoneTimerHandler(VOID)
+    {
+        ASetAudioTimerProc(NULL);
+    }
+
+ +See Also ASetAudioTimerRate + + + +
UINT AIAPI ASetAudioTimerRate(UINT nTimerRate)

+ +Changes the virtual audio timer rate.

+ +Returns zero on success.

+ +

    +
  • nTimerRate +The timer rate given in beats per minute (32-255).
  • +
+ +This routine changes the rate at which the virtual audio timer callback will be called by the audio system. Since the virtual audio timer is used by the system to play music sequences, your application can change the tempo or speed of the music by calling this routine while the module is being played.

+ +See Also ASetAudioTimerProc + + + +


UINT AIAPI AOpenVoices(UINT nVoices)

+ +Open audio voices.

+ +Returns zero on success.

+ +

    +
  • nVoices +Maximum number of allocatable audio voices (1-32).
  • +
+ +This routine is used to open audio voices for playback. The number of opened voices may affect both the performance and sound quality for some audio devices, so your application should allocate the minimum amount of voices. Your application must call the routine ACloseVoices to close all the audio voices before exiting or when the number of opened voices need to be changed.

+ +See Also ACloseVoices, ACreateAudioVoice, ADestroyAudioVoice + + + +


UINT AIAPI ACloseVoices(VOID)

+ +Close all the audio voices.

+ +Returns zero on success.

+ +This routine closes all the active audio voices. Before calling this routine, all the allocated voices, including those allocated indirectly by calling the APlayModule routine, must be released.

+ +See Also AOpenVoices, ACreateAudioVoice, ADestroyAudioVoice + + + +


UINT AIAPI ACreateAudioVoice(LPHAC lphVoice)

+ +Allocates a single audio voice.

+ +Returns zero on success.

+ +

    +
  • lphVoice +Address of a voice handle that will hold the allocated voice.
  • +
+ +This routine allocates an audio voice which can be used by your application to play waveforms through it. The routine will fail if no more voices are availables or if the application has not yet called AOpenVoices to open audio voices.

+ +

+    VOID PlayWaveform(LPAUDIOWAVE lpWave)
+    {
+        HAC hVoice;
+        BOOL stopped;
+
+        /* allocate an audio voice or channel */                
+        if (ACreateAudioVoice(&hVoice) == AUDIO_ERROR_NONE) {
+            /* play the waveform through the voice */
+            APlayVoice(hVoice, lpWave);
+            ASetVoiceVolume(hVoice, 64);
+            ASetVoicePanning(hVoice, 128);
+            /* wait until the wave finishes or a key is pressed */
+            while (!kbhit()) {
+                AUpdateAudio();
+                AGetVoiceStatus(hVoice, &stopped);
+                if (stopped) break;
+            }
+            /* stop the voice (if already playing) */
+            AStopVoice(hVoice);
+            /* release the allocated voice */
+            ADestroyAudioVoice(hVoice);
+        }
+    }
+
+ +See Also AOpenVoices, ACloseVoices, ADestroyAudioVoice + + + +
UINT AIAPI ADestroyAudioVoice(HAC hVoice)

+ +Releases an allocated audio voice.

+ +Returns zero on success.

+ +

    +
  • hVoice +Handle of the audio voice which will be released.
  • +
+ +This routine releases an audio voice that was previously allocated by calling the ACreateAudioVoice routine. Your application should not release voices which are currently being used to play a waveform.

+ +See Also ACreateAudioVoice + + + +


UINT AIAPI APlayVoice(HAC hVoice, LPAUDIOWAVE lpWave)

+ +Start playing a waveform through a voice.

+ +Returns zero on success.

+ +

    +
  • hVoice +Handle of the audio voice that will play the waveform.
  • + +
  • lpWave +Address of the waveform structure to be played.
  • +
+ +This routine start playing a waveform through an audio voice at the default sampling frequency. The volume and panning settings of the audio voice are not changed, so your application may need to change these parameters manually.

+ +See Also APrimeVoice, AStartVoice, AStopVoice + + + +


UINT AIAPI APrimeVoice(HAC hVoice, LPAUDIOWAVE lpWave)

+ +Prepares a waveform on an audio voice.

+ +Returns zero on success.

+ +

    +
  • hVoice +Handle of the audio voice that will be prepared.
  • + +
  • lpWave +Address of the waveform structure that will be played.
  • +
+ +This routine is similar to APlayVoice but will only prepare a waveform to be played through a voice. The routine AStartVoice must be called to actually start playing the waveform. The frequency, volume and panning settings of the voice are not changed by this routine.

+ +

+    VOID PlayChord(HAC aVoices[3], LPAUDIOWAVE lpWave, LONG aFreqs[3])
+    {
+        UINT n;
+
+        /* first prepare the voices to play the waveform */
+        for (n = 0 ; n < 3 ; n++) {
+            APrimeVoice(aVoices[n], lpWave);
+            ASetVoiceFrequency(aVoices[n], aFreqs[n]);
+            ASetVoiceVolume(aVoices[n], 64);
+        }
+        /* now start playing all them simultaneously */
+        for (n = 0 ; n < 3 ; n++) {
+            AStartVoice(aVoices[n]);
+        }
+    }
+
+ +See Also APlayVoice, AStartVoice, AStopVoice + + + +
UINT AIAPI AStartVoice(HAC hVoice)

+ +Start playing an audio voice.

+ +Returns zero on success.

+ +

    +
  • hVoice +Handle of the audio voice to be started.
  • +
+ +This routines starts or continues playing a waveform through an audio voice that was prepared or stopped by the APrimeVoice or AStopVoice routines.

+ +See Also APrimeVoice, APlayVoice, AStopVoice + + + +


UINT AIAPI AStopVoice(HAC hVoice)

+ +Stop playing an audio voice.

+ +Returns zero on success.

+ +

    +
  • hVoice +Handle of the audio voice to be stopped.
  • +
+ +This routine stop an audio voice. Your application can restart the audio voice by calling the AStartVoice routine, the voice will continue playing the waveform starting at the position where it was previously stopped.

+ +See Also APrimeVoice, APlayVoice, AStartVoice + + + +


UINT AIAPI ASetVoicePosition(HAC hVoice, LONG dwPosition)

+ +Changes the voice playing position.

+ +Returns zero on success.

+ +

    +
  • hVoice +Handle of an audio voice.
  • + +
  • dwPosition +Playing position measured in samples.
  • +
+ +This routine changes the playing position of an audio voice. The position will be changed in real-time, so your application can program echo effects using a pair of allocated voices, for example.

+ +

+    VOID PlayEchoVoices(HAC aVoices[2], LPAUDIOWAVE lpWave, LONG dwDelay)
+    {
+        /* prepare two voices with the same waveform */
+        APrimeVoice(aVoices[0], lpWave);
+        APrimeVoice(aVoices[1], lpWave);
+        ASetVoiceFrequency(aVoices[0], lpWave->nSampleRate);
+        ASetVoiceFrequency(aVoices[1], lpWave->nSampleRate);
+
+        /* set voice volumes (the "echo" voice has a lower volume) */
+        ASetVoiceVolume(aVoices[0], 64);
+        ASetVoiceVolume(aVoices[1], 32);
+
+        /* set the delay (measured in samples) for the "echo" voice */
+        ASetVoicePosition(aVoices[1], dwDelay);
+
+        /* start both voices as simultenously as possible */                
+        AStartVoice(aVoices[0]);
+        AStartVoice(aVoices[1]);
+    }
+
+ +See Also AGetVoicePosition + + + +
UINT AIAPI ASetVoiceFrequency(HAC hVoice, LONG dwFrequency)

+ +Changes the voice sampling frequency.

+ +Returns zero on success.

+ +

    +
  • hVoice +Handle of the audio voice to be changed.
  • + +
  • dwFrequency +Sampling frequency measured in Hertz (cycles per second).
  • +
+ +This routine changes the sampling frequency of an audio voice. Your application can use this routine to do things like pitch slides or simple stereo enhancement effects by changing the frequency of the audio voices in real-time.

+ +

+    VOID PlayVoiceStereo(HAC aVoices[2], LPAUDIOWAVE lpWave, LONG dwPitchShift)
+    {
+        /* prepare two voices to play a waveform */
+        APrimeVoice(aVoices[0], lpWave);
+        APrimeVoice(aVoices[1], lpWave);
+        ASetVoiceVolume(aVoices[0], 64);
+        ASetVoiceVolume(aVoices[1], 64);
+
+        /* slightly change the pitch of one of the voices */
+        ASetVoiceFrequency(aVoices[0], lpWave->nSampleRate);
+        ASetVoiceFrequency(aVoices[1], lpWave->nSampleRate + dwPitchShift);
+
+        /* set the pan position of the voices to left and right */
+        ASetVoicePanning(aVoices[0], 0);
+        ASetVoicePanning(aVoices[1], 255);
+
+        /* start both voices simultaneously */
+        AStartVoice(aVoices[0]);
+        AStartVoice(aVoices[1]);
+    }
+
+ +See Also AGetVoiceFrequency + + + +
UINT AIAPI ASetVoiceVolume(HAC hVoice, UINT nVolume)

+ +Changes the voice volume level.

+ +Returns zero on success.

+ +

    +
  • hVoice +Handle of the audio voice to be changed.
  • + +
  • nVolume +Linear volume level (0-64).
  • +
+ +This routine changes the volume level of an audio voice. The voices can be faded in and out smoothly in real-time using this routine and the virtual audio timer services, for example.

+ +See Also AGetVoiceVolume + + + +


UINT AIAPI ASetVoicePanning(HAC hVoice, UINT nPanning)

+ +Changes the voice stereo pan position.

+ +Returns zero on success.

+ +

    +
  • hVoice +Handle of the audio voice to be changed.
  • + +
  • nPanning +Stereo pan position value (0-255).
  • +
+ +This routine changes the stereo pan position of an audio voice. It has no effect when the audio system is playing in monophonic mode.

+ +See Also AGetVoicePanning + + + +


UINT AIAPI AGetVoicePosition(HAC hVoice, LPLONG lpdwPosition)

+ +Retrieves the playing position of a voice.

+ +Returns zero on success.

+ +

    +
  • hVoice +Handle of the audio voice to be queried.
  • + +
  • lpdwPosition +Address of a long variable which will hold the playing position.
  • +
+ +This routine retrieves the current playing position of an audio voice measured in samples. Your application can use this routine to implement a double buffering algorithm to play streams of audio data from disk using a single audio voice.

+ +See Also ASetVoicePosition + + + +
UINT AIAPI AGetVoiceFrequency(HAC hVoice, LPLONG lpdwFrequency)

+ +Retrieves the sampling frequency of a voice.

+ +Returns zero on success.

+ +

    +
  • hVoice +Handle of the audio voice to be queried.
  • + +
  • lpdwFrequency +Address of a long variable that will hold the frequency.
  • +
+ +This routine retrieves the current sampling frequency of an audio voice. Your application should not expect to get back the same frequency used in the last call to the ASetVoiceFrequency routine, due to possible rounding errors that occur when the audio system translates frequencies in Hertz to the device dependant format used by the hardware audio device.

+ +See Also ASetVoiceFrequency + + + +


UINT AIAPI AGetVoiceVolume(HAC hVoice, LPUINT lpnVolume)

+ +Retrieves the volume level of a voice.

+ +Returns zero on success.

+ +

    +
  • hVoice +Handle of the audio voice to be queried.
  • + +
  • lpnVolume +Address of an unsigned integer variable that will hold the volume.
  • +
+ +This routine retrieves the current volume level of an audio voice. Your application should not expect to get back the same volume level used in the last call to the ASetVoiceVolume routine, due to possible rounding errors that occur when the audio system translates linear volumes to the device dependant format used by the hardware audio device.

+ +See Also ASetVoiceVolume + + + +


UINT AIAPI AGetVoicePanning(HAC hVoice, LPUINT lpnPanning)

+ +Retrieves the stereo pan position of a voice.

+ +Returns zero on success.

+ +

    +
  • hVoice +Handle of the audio voice which will be queried.
  • + +
  • lpnPanning +Address of an unsigned integer variable that will hold the pan position.
  • +
+ +This routine retrieves the current stereo pan position of an audio voice. Your application should not expect to get back the same pan position used in the last call to the ASetVoicePanning routine, due to possible rounding errors that occur when the audio system translates pan positions to the device dependant format used by the hardware audio device.

+ +See Also ASetVoicePanning + + + +


UINT AIAPI AGetVoiceStatus(HAC hVoice, LPBOOL lpbStatus)

+ +Retrieves the current status of a voice.

+ +Returns zero on success.

+ +

    +
  • hVoice +Handle of the audio voice that will be queried.
  • + +
  • lpbStatus +Address of a boolean variable that will hold the voice status.
  • +
+ +This routine retrieves the current status of an audio voice. Your application can use this routine to determine if a voice is stopped or if it's playing a waveform.

+ +

+    VOID CheckVoice(HAC hVoice)
+    {
+        BOOL stopped;
+        AGetVoiceStatus(hVoice, &stopped);
+        if (stopped)
+            printf("voice is stopped.\n");
+    }
+
+ +See Also AStartVoice, AStopVoice + + + +
LONG AIAPI AGetAudioDataAvail(VOID)

+ +Retrieves the amount of available DRAM memory.

+ +Returns amount of available DRAM memory (in bytes).

+ +This routine retrieves the number of free bytes on the hardware audio device when applicable. It can be used to determine if there is enough space to hold a set of samples or waveforms simultaneously. It returns zero when the audio system is using system memory to hold the audio waveforms data.

+ +

+    VOID ShowFreeMemory(VOID)
+    {
+        LONG dwMemFree;
+        dwMemFree = AGetAudioDataAvail();
+        printf("%ld bytes free.\n", dwMemFree);
+    }
+
+ + + +
UINT AIAPI ACreateAudioData(LPAUDIOWAVE lpWave)

+ +Creates a waveform object.

+ +Returns zero on success.

+ +

    +
  • lpWave +Address of the waveform structure.
  • +
+ +This routine is used to create custom waveform objects. Your application can also use ALoadWaveFile to load RIFF/WAVE waveform files from disk. The current version of the audio system only support 8 and 16 bit mono one-shot or looped waveforms (reverse and bidirectional looping modes are not supported by AWE32 audio devices).

+ +

+    LPAUDIOWAVE CreateAudio8BitMono(WORD nSampleRate,
+                                    LPBYTE lpData, DWORD dwLength)
+    {
+        LPAUDIOWAVE lpWave;
+        /* first allocate structure to hold the waveform object */
+        if ((lpWave = (LPAUDIOWAVE) malloc(sizeof(AUDIOWAVE))) != NULL) {
+            /* create a 8-bit mono one-shot waveform object */
+            lpWave->wFormat = AUDIO_FORMAT_8BITS | AUDIO_FORMAT_MONO;
+            lpWave->nSampleRate = nSampleRate;
+            lpWave->dwLength = dwLength;
+            lpWave->dwLoopStart = lpWave->dwLoopEnd = 0;
+            if (ACreateAudioData(lpWave) != AUDIO_ERROR_NONE) {
+                free(lpWave);
+                return NULL;
+            }
+            /* copy the data into the waveform object */
+            memcpy(lpWave->lpData, lpData, dwLength);
+            /* upload the data to the audio DRAM local memory */
+            AWriteAudioData(lpWave, 0L, dwLength);
+        }
+        return lpWave;
+    }
+
+ +The waveform structure fields dwLength, dwLoopStart and dwLoopEnd are all measured in bytes, not samples, so your application should be careful to handle 16 bit waveform objects.

+ +See Also ADestroyAudioData, AWriteAudioData + + + +


UINT AIAPI ADestroyAudioData(LPAUDIOWAVE lpWave)

+ +Releases a waveform object.

+ +Returns zero on success.

+ +

    +
  • lpWave +Address of the waveform object to be released.
  • +
+ +This routine releases a waveform object previously allocated by calling the ACreateAudioData routine. Before releasing any waveform, your application must be sure that no voices are currently playing the waveform.

+ +See Also ACreateAudioData, AWriteAudioData + + + +


UINT AIAPI AWriteAudioData(LPAUDIOWAVE lpWave, DWORD dwOffset, UINT nCount)

+ +Upload waveform audio data to DRAM local memory.

+ +Returns zero on success.

+ +

    +
  • lpWave +Address of the waveform object.
  • + +
  • dwOffset +Starting offset of the block of samples to be uploaded.
  • + +
  • nCount +Number of bytes in the block of samples to be transferred.
  • +
+ +This routine uploads a block of samples from system memory to the hardware DRAM local memory when applicable. Your application must call this routine everytime it writes to the waveform audio data. The chunk of samples to be uploaded is specified by the offset and count parameters measured in bytes.

+ +

+    VOID StreamData8BitMono(FILE *stream, HAC hVoice, LPAUDIOWAVE lpWave)
+    {
+        BYTE aBuffer[1024];
+        LPBYTE lpChunk;
+        UINT nLength, nChunkSize;
+        DWORD dwOffset, dwVoicePosition;
+
+        /* check if the waveform is large enough for double buffering */
+        if (2*sizeof(aBuffer) > lpWave->dwLength) {
+            printf("the waveform is too small\n");
+            return;
+        }
+
+        /* first clean up the audio waveform buffer */
+        memset(lpWave->lpData, 0x80, lpWave->dwLength);
+        AWriteAudioData(lpWave, 0L, lpWave->dwLength);
+
+        /* start playing the waveform with forward looping enabled */
+        lpWave->wFormat |= AUDIO_FORMAT_LOOP;
+        lpWave->dwLoopStart = 0L;
+        lpWave->dwLoopEnd = lpWave->dwLength;
+        APlayVoice(hVoice, lpWave);
+        ASetVoiceVolume(hVoice, 64);
+
+        /* play the whole 8-bit mono stream of audio through the voice */
+        dwOffset = 0;
+        while ((nLength = fread(aBuffer, 1, nLength, stream)) != 0) {
+            /* write the waveform audio data in chunks */
+            lpChunk = aBuffer;
+            while (nLength > 0) {
+                /* determine size of chunk of data */
+                nChunkSize = nLength;
+                if (dwOffset + nChunkSize >= lpWave->dwLength)
+                    nChunkSize = lpWave->dwLength - dwOffset;
+
+                /* wait until we can write the chunk of data */
+                for (;;) {
+                    AUpdateAudio();
+                    AGetVoicePosition(hVoice, &dwVoicePosition);
+                    if (dwOffset + nChunkSize > lpWave->dwLength) {
+                        if (dwVoicePosition < dwOffset &&
+                            dwVoicePosition > dwOffset +
+                            nChunkSize - lpWave->dwLength)
+                            break;
+                    }
+                    else {
+                        if (dwVoicePosition < dwOffset ||
+                            dwVoicePosition > dwOffset + nChunkSize)
+                            break;
+                    }
+                }
+
+                /* upload the chunk of waveform data */
+                memcpy(lpWave->lpData + dwOffset, lpChunk, nChunkSize);
+                AWriteAudioData(lpWave, dwOffset, nChunkSize);
+                if ((dwOffset += nChunkSize) >= lpWave->dwLength)
+                    dwOffset = 0;
+                lpChunk += nChunkSize;
+                nLength -= nChunkSize;
+            }
+        }
+    }
+
+ +See Also ACreateAudioData, ADestroyAudioData + + + +
UINT AIAPI ALoadWaveFile(LPSTR lpszFileName, LPAUDIOWAVE* lplpWave, DWORD dwOffset)

+ +Load a RIFF/WAVE waveform file from disk.

+ +Returns zero on success.

+ +

    +
  • lpszFileName +Filename of the .WAV waveform file on disk.
  • + +
  • lplpWave +Address of a pointer to a waveform structure.
  • + +
  • dwOffset +Starting file offset of the waveform file.
  • +
+ +This routine load a RIFF/WAVE waveform from disk. The loaded waveform must be released with the AFreeWaveFile routine.

+ +

+    VOID PlayWaveFile(HAC hVoice, LPSTR lpszFileName)
+    {
+        LPAUDIOWAVE lpWave;
+        BOOL stopped;
+
+        if (ALoadWaveFile(lpszFileName, &lpWave, 0L) == AUDIO_ERROR_NONE) {
+            APlayVoice(hVoice, lpWave);
+            ASetVoiceVolume(hVoice, 64);
+            while (!kbhit()) {
+                AUpdateAudio();
+                AGetVoiceStatus(hVoice, &stopped);
+                if (stopped) break;
+            }
+            AFreeWaveFile(lpWave);
+        }
+    }
+
+ +See Also AFreeWaveFile + + + +
UINT AIAPI AFreeWaveFile(LPAUDIOWAVE lpWave)

+ +Releases a loaded RIFF/WAVE waveform file.

+ +Returns zero on success.

+ +

    +
  • lpWave +Address of the waveform structure to be released.
  • +
+ +This routine releases waveform files loaded from disk. Your application can't use ADestroyAudioData to release waveforms loaded from disk. You must stop any voice that is playing the waveform before releasing it.

+ +See Also ALoadWaveFile + + + +


UINT AIAPI APlayModule(LPAUDIOMODULE lpModule)

+ +Start playing a music module file.

+ +Returns zero on success.

+ +

    +
  • lpModule +Address of the module to be played.
  • +
+ +This routine start playing a module file in background using the audio system module player. Your application can stop a module by calling the AStopModule routine. The application must have enough available audio voices to play the music module.

+ +See Also AStopModule + + + + +


UINT AIAPI AStopModule(VOID)

+ +Stop playing a music module file.

+ +Returns zero on success.

+ +This routine stop and releases the audio system module player. After calling this routine, your application can select and start another module by calling the APlayModule routine.

+ +See Also APlayModule + + + +


UINT AIAPI APauseModule(VOID)

+ +Stop playing a music module file.

+ +Returns zero on success.

+ +This routine stop the audio system module player. You can later continue playing the music module by calling the AResumeModule routine. Your application must use AStopModule when the currently select module file is going to be released, or if another music module must be played.

+ +See Also APlayModule, AStopModule, AResumeModule + + + +


UINT AIAPI AResumeModule(VOID)

+ +Restart playing a music module file.

+ +Returns zero on success.

+ +This routine is used to continue playing a music module that was previously paused by the APauseModule routine. Your application can use AGetModuleStatus to retrieve the current state of the audio system module player.

+ +See Also APlayModule, AStopModule, APauseModule, AGetModuleStatus + + + +


UINT AIAPI ASetModuleVolume(UINT nVolume)

+ +Changes the music module global volume.

+ +Returns zero on success.

+ +

    +
  • nVolume +The new volume level for the music module (0-64).
  • +
+ +This routine changes the global volume at which the audio system is playing a music module sequence.

+ +See Also APlayModule, AStopModule, AGetModuleVolume + + + +


UINT AIAPI ASetModulePosition(UINT nOrder, UINT nRow)

+ +Changes the music module playing position.

+ +Returns zero on success.

+ +

    +
  • nOrder +The new order position.
  • + +
  • nRow +The new pattern row number.
  • +
+ +This routine changes the playing position of the audio system module player. Your application can use this routine to play small music sequences or patterns of sound effects, intro music, etc. all of them stored in the same music module file.

+ +See Also APlayModule, AStopModule, AGetModulePosition + + + +


UINT AIAPI AGetModuleVolume(LPUINT lpnVolume)

+ +Retrieves the music module global volume.

+ +Returns zero on success.

+ +

    +
  • lpnVolume +Address of an unsigned integer that will hold the module volume.
  • +
+ +This routine retrieves the global volume used by the audio system to play a music module sequence.

+ +See Also APlayModule, AStopModule, ASetModuleVolume + + + +


UINT AIAPI AGetModulePosition(LPUINT lpnOrder, LPUINT lpnRow)

+ +Retrieves the music module playing position.

+ +Returns zero on success.

+ +

    +
  • lpnOrder +Address of an unsigned integer that will hold the order position.
  • + +
  • lpnRow +Address of an unsigned integer that will hold the pattern row number.
  • +
+ +This routine retrieves the playing position of the audio system module player. Your application can use this routine to synchronize graphics or video with the music.

+ +See Also APlayModule, AStopModule, ASetModulePosition + + + +


UINT AIAPI AGetModuleStatus(LPBOOL lpbStatus)

+ +Retrieves the current state of the music module player.

+ +Returns zero on success.

+ +

    +
  • lpbStatus +Address of an unsigned integer that will hold the status.
  • +
+ +This routine retrieves the current status of the audio system module player. The routine returns true if the module player is paused or false otherwise. The audio system pauses the module file when the APauseModule routine is called or when the end of a non-looped music sequence is reached.

+ +See Also APlayModule, AStopModule, APauseModule, AResumeModule + + + +


UINT AIAPI ASetModuleCallback(LPFNAUDIOCALLBACK lpfnAudioCallback)

+ +Changes the music module synchronization callback routine.

+ +Returns zero on success.

+ +

    +
  • lpfnAudioCallback +Address of the synchronization callback routine.
  • +
+ +This routine changes the synchronization routine that is called by the audio system module player whenever it encounters a synchronization mark in the pattern effects column, the argument of the effect is passed to the callback routine. For ScreamTracker 3.0 and FastTracker 2.0 modules, the command effect Znn is used for synchronization (where nn is an hexadecimal number passed to the synchronization callback routine). For applications running under DOS, the synchronization callback can be called from within a hardware interrupt handler routine.

+ +

+    #define START_INTRO_SEQUENCE     0x01        /* Z01 */
+    #define START_VECTOR_GRAPHICS    0x02        /* Z02 */
+
+    VOID AIAPI SyncCallback(BYTE nParms, UINT nOrder, UINT nRow)
+    {
+        switch (nParms) {
+        case START_INTRO_SEQUENCE:
+            StartIntroSequence();
+            break;
+        case START_VECTOR_GRAPHICS:
+            StartVectorGraphics();
+            break;
+        default:
+            /* unknown Znn command found at position (nOrder, nRow) */
+             break;
+        }
+    }
+
+    VOID InitSyncCallback(VOID)
+    {
+        ASetModuleCallback(SyncCallback);
+    }
+
+    VOID DoneSyncCallback(VOID)
+    {
+        ASetModuleCallback(NULL);
+    }
+
+ + + +
UINT AIAPI ALoadModuleFile(LPSTR lpszFileName, LPAUDIOMODULE* lplpModule, DWORD dwOffset)

+ +Load MOD/MTM/S3M/XM module files from disk.

+ +Returns zero on success.

+ +

    +
  • lpszFileName +File name of the music module file.
  • + +
  • lplpModule +Address of a music module reference variable.
  • + +
  • dwOffset +Starting file offset of the music module file.
  • +
+ +This routine loads MOD/MTM/S3M/XM music module files from disk. The music module can be played and stopped by calling the APlayModule and AStopModule routines, respectively.

+ +See Also AFreeModuleFile + + + +


UINT AIAPI AFreeModuleFile(LPAUDIOMODULE lpModule)

+ +Releases a music module file from memory.

+ +Returns zero on success.

+ +

    +
  • lpModule +Address of a music module file in memory.
  • +
+ +This routine releases music module files from memory previously loaded by the ALoadModuleFile routine. Your application can't release modules currently being played by the audio system.

+ +See Also ALoadModuleFile + + + +

Structures

+ + +
AUDIOCAPS

+ +

+    typedef struct {
+        WORD    wProductId;
+        CHAR    szProductName[30];
+        DWORD   dwFormats;
+    } AUDIOCAPS, *LPAUDIOCAPS;
+
+ +The AUDIOCAPS structure contains the audio capabilities information that can be obtained by calling AGetAudioDevCaps for a given audio device driver.

+ +Members:

+ +

    +
  • wProductId +Specifies the hardware audio device product identifier. This member can hold any of the following values:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Value Description
    AUDIO_PRODUCT_NONE Virtual silence device
    AUDIO_PRODUCT_SB Sound Blaster 1.0 device
    AUDIO_PRODUCT_SB15 Sound Blaster 1.5 device
    AUDIO_PRODUCT_SB20 Sound Blaster 2.0 device
    AUDIO_PRODUCT_SBPRO Sound Blaster Pro I or II device
    AUDIO_PRODUCT_SB16 Sound Blaster 16/ASP device
    AUDIO_PRODUCT_AWE32 Sound Blaster AWE32 device
    AUDIO_PRODUCT_WSS Windows Sound System device
    AUDIO_PRODUCT_ESS Ensoniq Soundscape (Elite) device
    AUDIO_PRODUCT_GUS Gravis Ultrasound (GF1) device
    AUDIO_PRODUCT_GUSDB Gravis Ultrasound Daughterboard device
    AUDIO_PRODUCT_GUSMAX Gravis Ultrasound Max (CS4231) device
    AUDIO_PRODUCT_IWAVE AMD Interwave-based device
    AUDIO_PRODUCT_PAS Pro Audio Spectrum (Plus) device
    AUDIO_PRODUCT_PAS16 Pro Audio Spectrum 16 device
    AUDIO_PRODUCT_ARIA Sierra Semiconductors Aria Sound device
    AUDIO_PRODUCT_WINDOWSMicrosoft Windows WAVE device
    AUDIO_PRODUCT_DSOUND Microsoft Windows DirectSound device
    AUDIO_PRODUCT_LINUX UNIX Sound System for Linux device
    AUDIO_PRODUCT_SPARC SPARC workstation 8-bit ulaw or dbri device
    AUDIO_PRODUCT_SGI Silicon Graphics Indigo Audio Ports device
    AUDIO_PRODUCT_OS2MMPMOS/2 Multimedia Presentation Manager device
    AUDIO_PRODUCT_OS2DARTOS/2 DART Real Time Audio device
    AUDIO_PRODUCT_BEOSR3 BeOS Release 3 OLD MediaKit device
    AUDIO_PRODUCT_BEOS BeOS Release 4 New MediaKit device

  • + +
  • szProductName +Null terminated readable text string describing the hardware audio device product.
  • + +
  • dwFormats +Specifies the playback formats supported by the hardware audio device product. This member can be built using any combination of the following values: + + + + + + + + + + + + + + + +
    Value Description
    AUDIO_FORMAT_1M08 8-bit mono 11025 Hz
    AUDIO_FORMAT_1S08 8-bit stereo 11025 Hz
    AUDIO_FORMAT_1M16 16-bit mono 11025 Hz
    AUDIO_FORMAT_1S16 16-bit stereo 11025 Hz
    AUDIO_FORMAT_2M08 8-bit mono 22050 Hz
    AUDIO_FORMAT_2S08 8-bit stereo 22050 Hz
    AUDIO_FORMAT_2M16 16-bit mono 22050 Hz
    AUDIO_FORMAT_2S16 16-bit stereo 22050 Hz
    AUDIO_FORMAT_4M08 8-bit mono 44100 Hz
    AUDIO_FORMAT_4S08 8-bit stereo 44100 Hz
    AUDIO_FORMAT_4M16 16-bit mono 44100 Hz
    AUDIO_FORMAT_4S16 16-bit stereo 44100 Hz
  • + +
+ + +
AUDIOINFO

+ +

+    typedef struct {
+        UINT    nDeviceId;
+        WORD    wFormat;
+        WORD    nSampleRate;
+    } AUDIOINFO, *LPAUDIOINFO;
+
+ +Audio information structure used to open the hardware audio device for playback by using the AOpenAudio routine.

+ +Members:

+ +

    +
  • nDeviceId +Specifies the audio device we want to use for playback. The following virtual audio device identifiers are always defined:

    + + + + + +
    Value Description
    AUDIO_DEVICE_NONE Silence device driver
    AUDIO_DEVICE_MAPPER Audio mapper driver

  • + +
  • wFormat +Specifies the audio output format for playback. This member can be built using the following values:

    + + + + + + + + +
    Value Description
    AUDIO_FORMAT_8BITS 8 bits per sample
    AUDIO_FORMAT_16BITS 16 bits per sample
    AUDIO_FORMAT_MONO Monophonic output
    AUDIO_FORMAT_STEREO Stereo output
    AUDIO_FORMAT_FILTER Enable filtering

  • + +
  • nSampleRate +Specifies the sampling frequency used for playback. It's recommended to use the standard frequencies 11025, 22050 or 44100 Hz for better compatibility.
  • +
+ + +
AUDIOWAVE

+ +

+    typedef struct {
+        LPBYTE  lpData;
+        DWORD   dwHandle; 
+        DWORD   dwLength;
+        DWORD   dwLoopStart; 
+        DWORD   dwLoopEnd;
+        WORD    nSampleRate;
+        WORD    wFormat;
+    } AUDIOWAVE, *LPAUDIOWAVE;
+
+ +Audio waveform structure used to hold all the information related to a single waveform. + +Members:

+ +

    +
  • lpData +Read Only. Address of the a buffer in system memory used to hold the waveform data.
  • + +
  • dwHandle +Read Only. Handle used internally by the audio device drivers to reference the waveform data.
  • + +
  • dwLength +Specifies the length in bytes of the waveform data.
  • + +
  • dwLoopStart +Specifies the loop start point measured in bytes, only used for looped samples.
  • + +
  • dwLoopEnd +Specifies the loop end point measured in bytes, only used for looped samples.
  • + +
  • nSampleEate +The default sampling frequency of the waveform data.
  • + +
  • wFormat +Specifies the format and the looping type of the waveform data. This member can be built using the following defines:

    + + + + + + + + + + +
    Value Description
    AUDIO_FORMAT_8BITS 8 bits per sample
    AUDIO_FORMAT_16BITS 16 bits per sample
    AUDIO_FORMAT_MONO Monophonic output
    AUDIO_FORMAT_STEREO Stereo output
    AUDIO_FORMAT_LOOP Forward looping
    AUDIO_FORMAT_BIDILOOP Bidirectional looping
    AUDIO_FORMAT_REVERSE Reverse playing

  • +
+ + +
AUDIOMODULE

+ +

+    typedef struct {
+        CHAR    szModuleName[32];
+        WORD    wFlags;
+        WORD    nOrders;
+        WORD    nRestart;
+        WORD    nTracks;
+        WORD    nPatterns;
+        WORD    nPatches;
+        WORD    nTempo;
+        WORD    nBPM;
+        BYTE    aOrderTable[AUDIO_MAX_ORDERS];
+        BYTE    aPanningTable[AUDIO_MAX_VOICES];
+        LPAUDIOPATTERN aPatternTable;
+        LPAUDIOPATCH aPatchTable;
+    } AUDIOMODULE, *LPAUDIOMODULE;
+
+ +This structure holds all the information related to a single music module file loaded in system memory.

+ +Members:

+ +

    +
  • szModuleName +Specifies the music module name as a null-terminated text string.
  • + +
  • wFlags +Specifies some intial flags for the music module. This member can be built using the following values:

    + + + + + + +
    Value Description
    AUDIO_MODULE_LINEAR The module uses linear frequencies
    AUDIO_MODULE_AMIGA Use Amiga logarithmic frequencies
    AUDIO_MODULE_PANNING Use pan position from instruments

  • + +
  • nOrders +Number of entries in the sequence order table.
  • + +
  • nRestart +Specifies the restart order position for looped modules.
  • + +
  • nTracks +Number of tracks used in the music module.
  • + +
  • nPatterns +Number of patterns used in the music module.
  • + +
  • nPatches +Number of patches or instruments used in the music module.
  • + +
  • nTempo +Initial speed or tempo value.
  • + +
  • nBPM +Initial BPM or beats per minute value.
  • + +
  • aOrderTable +Specifies the sequence order in which the patterns are played.
  • + +
  • aPanningTable +Initial stereo pan position for all the music module tracks.
  • + +
  • aPatternTable +Array of pattern structures.
  • + +
  • aPatchTable +Array of patches structures.
  • +
+ + +
RETURN CODES

+ + + + + + + + + + + + + + + +
Value Description
AUDIO_ERROR_NONE No error
AUDIO_ERROR_INVALHANDLE Invalid voice or waveform handle
AUDIO_ERROR_INVALPARAM Invalid parameter passed
AUDIO_ERROR_NOTSUPPORTED Invalid audio system call
AUDIO_ERROR_BADDEVICEID Invalid device identifier
AUDIO_ERROR_NODEVICE No audio device found
AUDIO_ERROR_DEVICEBUSY Audio device is busy
AUDIO_ERROR_BADFORMAT Bad or unsupported audio playback format
AUDIO_ERROR_NOMEMORY Not enough system memory
AUDIO_ERROR_NODRAMMEMORY Not enough onboard DRAM memory
AUDIO_ERROR_FILENOTFOUND Module or waveform file not found
AUDIO_ERROR_BADFILEFORMAT Invalid module or waveform file format
+ +


+November 30th, 1998. + + + diff --git a/seal-hack/examples/check.c b/seal-hack/examples/check.c new file mode 100644 index 0000000..df8de61 --- /dev/null +++ b/seal-hack/examples/check.c @@ -0,0 +1,479 @@ +/* check.c - misc. routines from the reference guide */ + +#include +#include +#include +#include +#ifndef linux +#include +#endif +#include + + +/* enable filtering */ +#define FILTER + + +/* soy paranoico! */ +#define Assert(x) AssertFailed((x),#x,__LINE__,__FILE__) + +void AssertFailed(UINT rc, LPSTR lpszExpr, int nLine, LPSTR lpszFileName) +{ + CHAR szText[128]; + + if (rc != AUDIO_ERROR_NONE) { + AGetErrorText(rc, szText, sizeof(szText) - 1); + fprintf(stderr, "ASSERT(%s:%d): %s\nERROR: %s\n", + lpszFileName, nLine, lpszExpr, szText); + ACloseAudio(); + exit(1); + } +} + + + +/* APingAudio, AGetAudioDevCaps */ +VOID DetectAudioDevice(VOID) +{ + AUDIOCAPS caps; + UINT nDeviceId; + if (APingAudio(&nDeviceId) != AUDIO_ERROR_NONE) + printf("no audio found\n"); + else { + AGetAudioDevCaps(nDeviceId, &caps); + printf("%s device found\n", caps.szProductName); + } +} + + +/* AGetAudioDevCaps, AGetAudioNumDevs */ +VOID PrintAudioDevs(VOID) +{ + AUDIOCAPS caps; + UINT nDeviceId; + for (nDeviceId = 0; nDeviceId < AGetAudioNumDevs(); nDeviceId++) { + Assert(AGetAudioDevCaps(nDeviceId, &caps)); + printf("nDeviceId=%d wProductId=%d szProductName=%s\n", + nDeviceId, caps.wProductId, caps.szProductName); + } +} + + +/* AOpenAudio, AGetErrorText */ +VOID InitializeAudio(VOID) +{ + AUDIOINFO info; + CHAR szText[128]; + UINT rc; + + info.nDeviceId = AUDIO_DEVICE_MAPPER; + info.wFormat = AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO; + #ifdef FILTER + info.wFormat |= AUDIO_FORMAT_FILTER; + #endif + info.nSampleRate = 44100; + if ((rc = AOpenAudio(&info)) != AUDIO_ERROR_NONE) { + AGetErrorText(rc, szText, sizeof(szText) - 1); + printf("ERROR: %s\n", szText); + exit(1); + } + else { + printf("Audio device initialized at %d bits %s %u Hz\n", + info.wFormat & AUDIO_FORMAT_16BITS ? 16 : 8, + info.wFormat & AUDIO_FORMAT_STEREO ? + "stereo" : "mono", info.nSampleRate); + } +} + + +/* ASetAudioTimerProc, ASetAudioTimerRate */ +volatile UINT nTickCounter = 0; + +VOID AIAPI TimerHandler(VOID) +{ + nTickCounter++; +} + +VOID InitTimerHandler(VOID) +{ + Assert(ASetAudioTimerProc(TimerHandler)); + Assert(ASetAudioTimerRate(125)); +} + +VOID DoneTimerHandler(VOID) +{ + Assert(ASetAudioTimerProc(NULL)); +} + +VOID TestTimerServices(VOID) +{ + InitTimerHandler(); + do { + #ifndef WIN32 + Assert(AUpdateAudio()); + #endif + fprintf(stderr, "Elapsed: %2.2f secs\r", nTickCounter / 50.0F); + } while (nTickCounter < 2*50); + DoneTimerHandler(); +} + + +/* ACreateAudioVoice, ADestroyAudioVoice, APlayVoice, ASetVoiceXXX */ +VOID PlayWaveform(LPAUDIOWAVE lpWave) +{ + HAC hVoice; + BOOL stopped; + Assert(ACreateAudioVoice(&hVoice)); + Assert(APlayVoice(hVoice, lpWave)); + Assert(ASetVoiceVolume(hVoice, 64)); + Assert(ASetVoicePanning(hVoice, 128)); + printf("press any key to stop\n"); + while (!kbhit()) { + #ifndef WIN32 + Assert(AUpdateAudio()); + #endif + Assert(AGetVoiceStatus(hVoice, &stopped)); + if (stopped) break; + } + if (kbhit()) getch(); + Assert(AStopVoice(hVoice)); + Assert(ADestroyAudioVoice(hVoice)); +} + +VOID TestPlayWaveform(VOID) +{ + LPAUDIOWAVE lpWave; + Assert(ALoadWaveFile("test.wav", &lpWave, 0)); + lpWave->wFormat |= AUDIO_FORMAT_LOOP; + lpWave->dwLoopStart = 0; + lpWave->dwLoopEnd = lpWave->dwLength; + Assert(AOpenVoices(1)); + PlayWaveform(lpWave); + Assert(ACloseVoices()); + Assert(AFreeWaveFile(lpWave)); +} + + +/* APrimeVoice, AStartVoice, ASetVoiceXXX */ +VOID PlayChord(HAC aVoices[3], LPAUDIOWAVE lpWave, LONG aFreqs[3]) +{ + UINT n; + for (n = 0; n < 3; n++) { + Assert(APrimeVoice(aVoices[n], lpWave)); + Assert(ASetVoiceFrequency(aVoices[n], aFreqs[n])); + Assert(ASetVoiceVolume(aVoices[n], 64)); + } + for (n = 0; n < 3; n++) { + Assert(AStartVoice(aVoices[n])); + } +} + +VOID TestPlayChord(VOID) +{ + LPAUDIOWAVE lpWave; + HAC aVoices[3]; + LONG aFreqs[3] = { (8*6000)/8, (8*6000)/6, (8*6000)/5 }; + UINT n; + Assert(ALoadWaveFile("test.wav", &lpWave, 0)); + Assert(AOpenVoices(3)); + for (n = 0; n < 3; n++) + Assert(ACreateAudioVoice(&aVoices[n])); + printf("press any key to stop\n"); + InitTimerHandler(); + while (!kbhit()) { + #ifndef WIN32 + Assert(AUpdateAudio()); + #endif + /* play chord two times per second */ + if (nTickCounter >= 25) { + PlayChord(aVoices, lpWave, aFreqs); + nTickCounter -= 25; + } + } + if (kbhit()) getch(); + DoneTimerHandler(); + for (n = 0; n < 3; n++) { + Assert(AStopVoice(aVoices[n])); + Assert(ADestroyAudioVoice(aVoices[n])); + } + Assert(ACloseVoices()); + Assert(AFreeWaveFile(lpWave)); +} + + +/* ASetVoicePosition, AGetVoicePosition */ +VOID PlayEchoVoices(HAC aVoices[2], LPAUDIOWAVE lpWave, LONG dwDelay) +{ + Assert(APrimeVoice(aVoices[0], lpWave)); + Assert(APrimeVoice(aVoices[1], lpWave)); + Assert(ASetVoiceFrequency(aVoices[0], lpWave->nSampleRate / 2)); + Assert(ASetVoiceFrequency(aVoices[1], lpWave->nSampleRate / 2)); + Assert(ASetVoiceVolume(aVoices[0], 64)); + Assert(ASetVoiceVolume(aVoices[1], 48)); + Assert(ASetVoicePosition(aVoices[1], dwDelay)); + Assert(AStartVoice(aVoices[0])); + Assert(AStartVoice(aVoices[1])); +} + +VOID TestPlayEcho(VOID) +{ + LPAUDIOWAVE lpWave; + HAC aVoices[2]; + UINT n; + Assert(ALoadWaveFile("test.wav", &lpWave, 0)); + Assert(AOpenVoices(2)); + for (n = 0; n < 2; n++) + Assert(ACreateAudioVoice(&aVoices[n])); + printf("press any key to stop\n"); + InitTimerHandler(); + while (!kbhit()) { + #ifndef WIN32 + Assert(AUpdateAudio()); + #endif + /* play voices two times per second */ + if (nTickCounter >= 25) { + PlayEchoVoices(aVoices, lpWave, 800); + nTickCounter -= 25; + } + } + if (kbhit()) getch(); + DoneTimerHandler(); + for (n = 0; n < 2; n++) { + Assert(AStopVoice(aVoices[n])); + Assert(ADestroyAudioVoice(aVoices[n])); + } + Assert(ACloseVoices()); + Assert(AFreeWaveFile(lpWave)); +} + + +/* ASetVoiceFrequency */ +VOID PlayVoiceStereo(HAC aVoices[2], LPAUDIOWAVE lpWave, LONG dwPitchShift) +{ + Assert(APrimeVoice(aVoices[0], lpWave)); + Assert(APrimeVoice(aVoices[1], lpWave)); + Assert(ASetVoiceVolume(aVoices[0], 64)); + Assert(ASetVoiceVolume(aVoices[1], 64)); + Assert(ASetVoiceFrequency(aVoices[0], lpWave->nSampleRate)); + Assert(ASetVoiceFrequency(aVoices[1], lpWave->nSampleRate + dwPitchShift)); + Assert(ASetVoicePanning(aVoices[0], 0)); + Assert(ASetVoicePanning(aVoices[1], 255)); + Assert(AStartVoice(aVoices[0])); + Assert(AStartVoice(aVoices[1])); +} + +VOID TestPlayStereoEnh(VOID) +{ + LPAUDIOWAVE lpWave; + HAC aVoices[2]; + UINT n; + Assert(ALoadWaveFile("test.wav", &lpWave, 0)); + Assert(AOpenVoices(2)); + for (n = 0; n < 2; n++) + Assert(ACreateAudioVoice(&aVoices[n])); + printf("press any key to stop\n"); + InitTimerHandler(); + while (!kbhit()) { + #ifndef WIN32 + Assert(AUpdateAudio()); + #endif + /* play voices two times per second */ + if (nTickCounter >= 25) { + PlayVoiceStereo(aVoices, lpWave, 100); + nTickCounter -= 25; + } + } + if (kbhit()) getch(); + DoneTimerHandler(); + for (n = 0; n < 2; n++) { + Assert(AStopVoice(aVoices[n])); + Assert(ADestroyAudioVoice(aVoices[n])); + } + Assert(ACloseVoices()); + Assert(AFreeWaveFile(lpWave)); +} + + +/* ACreateAudioData, AWriteAudioData */ +LPAUDIOWAVE CreateAudio8BitMono(WORD nSampleRate, + LPBYTE lpData, DWORD dwLength) +{ + LPAUDIOWAVE lpWave; + if ((lpWave = (LPAUDIOWAVE) malloc(sizeof(AUDIOWAVE))) != NULL) { + lpWave->wFormat = AUDIO_FORMAT_8BITS | AUDIO_FORMAT_MONO; + lpWave->nSampleRate = nSampleRate; + lpWave->dwLength = dwLength; + lpWave->dwLoopStart = lpWave->dwLoopEnd = 0L; + Assert(ACreateAudioData(lpWave)); + memcpy(lpWave->lpData, lpData, dwLength); + Assert(AWriteAudioData(lpWave, 0L, dwLength)); + } + return lpWave; +} + +VOID TestCreateAudioData(VOID) +{ + LPAUDIOWAVE lpWave; + HAC hVoice; + static BYTE aData[4000]; + UINT n; + + /* create 500 Hz sinewave (sampled at 4 kHz) */ + for (n = 0; n < sizeof(aData); n++) + aData[n] = (BYTE)(127.0 * sin((500.0 * 3.141592653 * n) / sizeof(aData))); + + lpWave = CreateAudio8BitMono(4000, aData, sizeof(aData)); + if (lpWave == NULL) { + printf("not enough memory\n"); + return; + } + Assert(AOpenVoices(1)); + Assert(ACreateAudioVoice(&hVoice)); + printf("press any key to stop\n"); + InitTimerHandler(); + while (!kbhit()) { + #ifndef WIN32 + Assert(AUpdateAudio()); + #endif + /* play voices two times per second */ + if (nTickCounter >= 25) { + Assert(APlayVoice(hVoice, lpWave)); + Assert(ASetVoiceVolume(hVoice, 64)); + nTickCounter -= 25; + } + } + if (kbhit()) getch(); + DoneTimerHandler(); + Assert(AStopVoice(hVoice)); + Assert(ADestroyAudioVoice(hVoice)); + Assert(ACloseVoices()); + Assert(ADestroyAudioData(lpWave)); + free(lpWave); +} + + +/* ACreateAudioData, AWriteAudioData */ +VOID StreamData8BitMono(FILE *stream, HAC hVoice, LPAUDIOWAVE lpWave) +{ + static BYTE aBuffer[1024]; + LPBYTE lpChunk; + UINT nLength, nChunkSize; + DWORD dwOffset; + static LONG dwVoicePosition; + + if (2*sizeof(aBuffer) > lpWave->dwLength) { + printf("the waveform is too small\n"); + return; + } + memset(lpWave->lpData, 0x80, lpWave->dwLength); + Assert(AWriteAudioData(lpWave, 0L, lpWave->dwLength)); + lpWave->wFormat |= AUDIO_FORMAT_LOOP; + lpWave->dwLoopStart = 0L; + lpWave->dwLoopEnd = lpWave->dwLength; + Assert(APlayVoice(hVoice, lpWave)); + Assert(ASetVoiceVolume(hVoice, 64)); + dwOffset = 0L; + while ((nLength = fread(aBuffer, 1, sizeof(aBuffer), stream)) != 0) { + if (kbhit()) break; + + #ifndef SIGNED + { + UINT n; + for (n = 0; n < nLength; n++) + aBuffer[n] ^= 0x80; + } + #endif + + lpChunk = aBuffer; + while (nLength > 0) { + nChunkSize = nLength; + if (dwOffset + nChunkSize > lpWave->dwLength) + nChunkSize = lpWave->dwLength - dwOffset; + for (;;) { + #ifndef WIN32 + Assert(AUpdateAudio()); + #endif + Assert(AGetVoicePosition(hVoice, &dwVoicePosition)); + if (dwOffset + nChunkSize > lpWave->dwLength) { + if (dwVoicePosition < dwOffset && + dwVoicePosition > dwOffset + + nChunkSize - lpWave->dwLength) + break; + } + else { + if (dwVoicePosition < dwOffset || + dwVoicePosition > dwOffset + nChunkSize) + break; + } + } + memcpy(lpWave->lpData + dwOffset, lpChunk, nChunkSize); + Assert(AWriteAudioData(lpWave, dwOffset, nChunkSize)); + if ((dwOffset += nChunkSize) >= lpWave->dwLength) + dwOffset = 0L; + lpChunk += nChunkSize; + nLength -= nChunkSize; + } + } + if (kbhit()) getch(); +} + +VOID TestAudioStream(VOID) +{ + FILE *stream; + HAC hVoice; + AUDIOWAVE Wave; + + /* open .wav file and skip header structure */ + if ((stream = fopen("8mono.wav", "rb")) == NULL) { + printf("cant open raw 8-bit mono file\n"); + return; + } + fseek(stream, 48L, SEEK_SET); + + /* start playing the "data" chunk of the .wav file */ + Assert(AOpenVoices(1)); + Assert(ACreateAudioVoice(&hVoice)); + Wave.wFormat = AUDIO_FORMAT_8BITS | AUDIO_FORMAT_MONO; + Wave.nSampleRate = 11025; + Wave.dwLength = Wave.dwLoopEnd = 10000; + Wave.dwLoopStart = 0; + Assert(ACreateAudioData(&Wave)); + printf("press any key to stop\n"); + StreamData8BitMono(stream, hVoice, &Wave); + Assert(AStopVoice(hVoice)); + Assert(ADestroyAudioVoice(hVoice)); + Assert(ACloseVoices()); + Assert(ADestroyAudioData(&Wave)); + fclose(stream); +} + + +void main(void) +{ + #ifndef WIN32 + AInitialize(); + #endif + + printf("------------ DetectAudioDevice() ------------\n"); + DetectAudioDevice(); + printf("------------ PrintAudioDevs() ---------------\n"); + PrintAudioDevs(); + printf("------------ InitializeAudio() --------------\n"); + InitializeAudio(); + printf("------------ TestTimerServices() ------------\n"); + TestTimerServices(); + printf("------------ TestPlayWaveform() -------------\n"); + TestPlayWaveform(); + printf("------------ TestPlayChord() ----------------\n"); + TestPlayChord(); + printf("------------ TestPlayEcho() -----------------\n"); + TestPlayEcho(); + printf("------------ TestPlayStereoEnh() ------------\n"); + TestPlayStereoEnh(); + printf("------------ TestCreateAudioData() ----------\n"); + TestCreateAudioData(); + printf("------------ TestAudioStream() --------------\n"); + TestAudioStream(); + printf("------------ ACloseAudio() ------------------\n"); + Assert(ACloseAudio()); +} diff --git a/seal-hack/examples/demo.pas b/seal-hack/examples/demo.pas new file mode 100644 index 0000000..92c9869 --- /dev/null +++ b/seal-hack/examples/demo.pas @@ -0,0 +1,49 @@ +program Demo; +uses + SysUtils, Audio; + +var + Caps: TAudioCaps; + Info: TAudioInfo; + pModule: PAudioModule; + szFileName : Array [0..127] of Char; + bStatus: Integer; +begin + if ParamCount <> 1 then + begin + Writeln('use: demo filename[.mod|.s3m|.xm]'); + Halt(0); + end; + Info.nDeviceId := AUDIO_DEVICE_MAPPER; + Info.wFormat := AUDIO_FORMAT_16BITS or AUDIO_FORMAT_STEREO or AUDIO_FORMAT_FILTER; + Info.nSampleRate := 44100; + if AOpenAudio(Info) <> 0 then + begin + Writeln('Audio initialization failed'); + Halt(1); + end; + AGetAudioDevCaps(Info.nDeviceId, Caps); + Write(Caps.szProductName,' playing at '); + if Info.wFormat and AUDIO_FORMAT_16BITS <> 0 then + Write('16-bit ') else Write('8-bit '); + if Info.wFormat and AUDIO_FORMAT_STEREO <> 0 then + Write('stereo ') else Write('mono '); + Writeln(Info.nSampleRate,' Hz'); + if ALoadModuleFile(StrPCopy(szFileName, ParamStr(1)), pModule, 0) <> 0 then + begin + Writeln('Cant load module file'); + ACloseAudio; + Halt(1); + end; + AOpenVoices(pModule^.nTracks); + APlayModule(pModule); + while (AGetModuleStatus(bStatus) = 0) do + begin + if bStatus <> 0 then break; + AUpdateAudio; + end; + AStopModule; + ACloseVoices; + AFreeModuleFile(pModule); + ACloseAudio; +end. diff --git a/seal-hack/examples/example1 b/seal-hack/examples/example1 new file mode 100755 index 0000000..e487675 Binary files /dev/null and b/seal-hack/examples/example1 differ diff --git a/seal-hack/examples/example1.c b/seal-hack/examples/example1.c new file mode 100644 index 0000000..08056f1 --- /dev/null +++ b/seal-hack/examples/example1.c @@ -0,0 +1,67 @@ +/* example1.c - initialize and print device information */ + +#include +#include +#include +#include + +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__) || defined(__DJGPP__) +#include +#else +#define kbhit() 0 +#endif + +int main(void) +{ + AUDIOINFO info; + AUDIOCAPS caps; + UINT rc, nDevId; + + /* initialize audio library */ + AInitialize(); + + /* show registered device drivers */ + printf("List of registered devices:\n"); + for (nDevId = 0; nDevId < AGetAudioNumDevs(); nDevId++) { + AGetAudioDevCaps(nDevId, &caps); + printf(" %2d. %s\n", nDevId, caps.szProductName); + } + printf("\n"); + + /* + * NOTE: Here we can use any of the above devices, or we can + * use the virtual device AUDIO_DEVICE_MAPPER for detection. + */ + + /* open audio device */ + info.nDeviceId = AUDIO_DEVICE_MAPPER; + info.wFormat = AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO; + info.nSampleRate = 44100; + if ((rc = AOpenAudio(&info)) != AUDIO_ERROR_NONE) { + CHAR szText[80]; + AGetErrorText(rc, szText, sizeof(szText) - 1); + printf("ERROR: %s\n", szText); + exit(1); + } + + /* + * NOTE: Since the audio device may not support the playback + * format and sampling frequency, the audio system uses the + * closest configuration which is then returned to the user + * in the AUDIOINFO structure. + * + */ + + /* print information */ + AGetAudioDevCaps(info.nDeviceId, &caps); + printf("%s at %d-bit %s %u Hz detected\n", + caps.szProductName, + info.wFormat & AUDIO_FORMAT_16BITS ? 16 : 8, + info.wFormat & AUDIO_FORMAT_STEREO ? "stereo" : "mono", + info.nSampleRate); + + + /* close audio device */ + ACloseAudio(); + return 0; +} diff --git a/seal-hack/examples/example1.dSYM/Contents/Info.plist b/seal-hack/examples/example1.dSYM/Contents/Info.plist new file mode 100644 index 0000000..331d4c1 --- /dev/null +++ b/seal-hack/examples/example1.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.example1 + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/seal-hack/examples/example1.dSYM/Contents/Resources/DWARF/example1 b/seal-hack/examples/example1.dSYM/Contents/Resources/DWARF/example1 new file mode 100644 index 0000000..aeaf3e0 Binary files /dev/null and b/seal-hack/examples/example1.dSYM/Contents/Resources/DWARF/example1 differ diff --git a/seal-hack/examples/example2 b/seal-hack/examples/example2 new file mode 100755 index 0000000..eb417b4 Binary files /dev/null and b/seal-hack/examples/example2 differ diff --git a/seal-hack/examples/example2.c b/seal-hack/examples/example2.c new file mode 100644 index 0000000..b8d2e64 --- /dev/null +++ b/seal-hack/examples/example2.c @@ -0,0 +1,70 @@ +/* example2.c - play a module file */ + +#include +#include +#include +#include + +#if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) || defined(__DJGPP__) +#include +#else +#define kbhit() 0 +#endif + +int main(void) +{ + AUDIOINFO info; + LPAUDIOMODULE lpModule; + int ret; + + /* initialize audio library */ + AInitialize(); + + /* open audio device */ + info.nDeviceId = 2;// AUDIO_DEVICE_MAPPER; + info.wFormat = AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO; + info.nSampleRate = 44100; + +#ifdef USEFILTER + /* enable antialias dynamic filtering */ + info.wFormat |= AUDIO_FORMAT_FILTER; +#endif + + AOpenAudio(&info); + + /* load module file */ + ret = ALoadModuleFile("test.s3m", &lpModule, 0); + if (lpModule == NULL) + { + printf("Error loding file... [%d]\n", ret); + return -1; + } + + /* open voices and play module */ + AOpenVoices(lpModule->nTracks); + APlayModule(lpModule); + + /* program main execution loop */ + printf("Playing module file, press any key to stop.\n"); + while (!kbhit()) { + BOOL stopped; + + /* check if the module is stopped */ + AGetModuleStatus(&stopped); + if (stopped) break; + + /* update audio system */ + AUpdateAudio(); + } + + /* stop module and close voices */ + AStopModule(); + ACloseVoices(); + + /* release module file */ + AFreeModuleFile(lpModule); + + /* close audio device */ + ACloseAudio(); + return 0; +} diff --git a/seal-hack/examples/example2.dSYM/Contents/Info.plist b/seal-hack/examples/example2.dSYM/Contents/Info.plist new file mode 100644 index 0000000..c3b7bfd --- /dev/null +++ b/seal-hack/examples/example2.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.example2 + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/seal-hack/examples/example2.dSYM/Contents/Resources/DWARF/example2 b/seal-hack/examples/example2.dSYM/Contents/Resources/DWARF/example2 new file mode 100644 index 0000000..6e457fe Binary files /dev/null and b/seal-hack/examples/example2.dSYM/Contents/Resources/DWARF/example2 differ diff --git a/seal-hack/examples/example3 b/seal-hack/examples/example3 new file mode 100755 index 0000000..16f7664 Binary files /dev/null and b/seal-hack/examples/example3 differ diff --git a/seal-hack/examples/example3.c b/seal-hack/examples/example3.c new file mode 100644 index 0000000..1b0a9ce --- /dev/null +++ b/seal-hack/examples/example3.c @@ -0,0 +1,87 @@ +/* example3.c - play a waveform file */ + +#include +#include +#include +#include + +#if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) || defined(__DJGPP__) +#include +#else +#define kbhit() 0 +#endif + +#define NUMVOICES 3*3 + +#define FREQ(nPeriod) (((LONG) lpWave->nSampleRate * 428) / nPeriod) + +UINT aPeriodTable[48] = +{ /* C C# D D# E F F# G G# A A# B */ + 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 +}; + +int main(void) +{ + AUDIOINFO info; + LPAUDIOWAVE lpWave; + HAC hVoice[NUMVOICES]; + BOOL stopped; + UINT n, m; + + /* initialize audio library */ + AInitialize(); + + /* open audio device */ + info.nDeviceId = AUDIO_DEVICE_MAPPER; + info.wFormat = AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO; + info.nSampleRate = 44100; + AOpenAudio(&info); + + /* load waveform file */ + ALoadWaveFile("test.wav", &lpWave, 0); + + /* open and allocate voices */ + AOpenVoices(NUMVOICES); + for (n = 0; n < NUMVOICES; n++) { + ACreateAudioVoice(&hVoice[n]); + ASetVoiceVolume(hVoice[n], 64); + ASetVoicePanning(hVoice[n], n & 1 ? 0 : 255); + } + + /* program main execution loop */ + printf("Playing waveform, press any key to stop.\n"); + for (n = m = 0; !kbhit() && n < 48 - 7; n++) { + /* play chord C-E-G */ + APlayVoice(hVoice[m+0], lpWave); + APlayVoice(hVoice[m+1], lpWave); + APlayVoice(hVoice[m+2], lpWave); + ASetVoiceFrequency(hVoice[m+0], FREQ(aPeriodTable[n+0])); + ASetVoiceFrequency(hVoice[m+1], FREQ(aPeriodTable[n+4])); + ASetVoiceFrequency(hVoice[m+2], FREQ(aPeriodTable[n+7])); + m = (m + 3) % NUMVOICES; + + /* wait until note finishes */ + do { + /* update audio system */ + AUpdateAudio(); + AGetVoiceStatus(hVoice[0], &stopped); + } while (!stopped); + } + + /* stop and release voices */ + for (n = 0; n < NUMVOICES; n++) { + AStopVoice(hVoice[n]); + ADestroyAudioVoice(hVoice[n]); + } + ACloseVoices(); + + /* release the waveform file */ + AFreeWaveFile(lpWave); + + /* close audio device */ + ACloseAudio(); + return 0; +} diff --git a/seal-hack/examples/example3.dSYM/Contents/Info.plist b/seal-hack/examples/example3.dSYM/Contents/Info.plist new file mode 100644 index 0000000..9b254cd --- /dev/null +++ b/seal-hack/examples/example3.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.example3 + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/seal-hack/examples/example3.dSYM/Contents/Resources/DWARF/example3 b/seal-hack/examples/example3.dSYM/Contents/Resources/DWARF/example3 new file mode 100644 index 0000000..4fa1679 Binary files /dev/null and b/seal-hack/examples/example3.dSYM/Contents/Resources/DWARF/example3 differ diff --git a/seal-hack/examples/example4 b/seal-hack/examples/example4 new file mode 100755 index 0000000..0f52ee0 Binary files /dev/null and b/seal-hack/examples/example4 differ diff --git a/seal-hack/examples/example4.c b/seal-hack/examples/example4.c new file mode 100644 index 0000000..5df35f7 --- /dev/null +++ b/seal-hack/examples/example4.c @@ -0,0 +1,78 @@ +/* example4.c - play module and waveform file */ + +#include +#include +#include +#include + +#if defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__) || defined(__DJGPP__) +#include +#else +#define kbhit() 0 +#endif + +int main(void) +{ + AUDIOINFO info; + LPAUDIOMODULE lpModule; + LPAUDIOWAVE lpWave; + HAC hVoice; + BOOL stopped; + + /* initialize audio library */ + AInitialize(); + + /* open audio device */ + info.nDeviceId = 1;//AUDIO_DEVICE_MAPPER; + info.wFormat = AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO; + info.nSampleRate = 44100; + AOpenAudio(&info); + + /* load module and waveform file */ + ALoadModuleFile("test.s3m", &lpModule, 0); + ALoadWaveFile("test.wav", &lpWave, 0); + + /* open voices for module and waveform */ + AOpenVoices(lpModule->nTracks + 1); + + /* play the module file */ + APlayModule(lpModule); + ASetModuleVolume(64); + + /* play the waveform through a voice */ + ACreateAudioVoice(&hVoice); + APlayVoice(hVoice, lpWave); + ASetVoiceVolume(hVoice, 48); + ASetVoicePanning(hVoice, 128); + + /* program main execution loop */ + printf("Playing module and waveform, press any key to stop.\n"); + while (!kbhit()) { + /* update audio system */ + AUpdateAudio(); + + /* restart waveform if stopped */ + AGetVoiceStatus(hVoice, &stopped); + if (stopped) APlayVoice(hVoice, lpWave); + + /* check if the module is stopped */ + AGetModuleStatus(&stopped); + if (stopped) break; + } + + /* stop playing the waveform */ + AStopVoice(hVoice); + ADestroyAudioVoice(hVoice); + + /* stop playing the module */ + AStopModule(); + ACloseVoices(); + + /* release the waveform & module */ + AFreeWaveFile(lpWave); + AFreeModuleFile(lpModule); + + /* close audio device */ + ACloseAudio(); + return 0; +} diff --git a/seal-hack/examples/example4.dSYM/Contents/Info.plist b/seal-hack/examples/example4.dSYM/Contents/Info.plist new file mode 100644 index 0000000..efacd36 --- /dev/null +++ b/seal-hack/examples/example4.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.example4 + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/seal-hack/examples/example4.dSYM/Contents/Resources/DWARF/example4 b/seal-hack/examples/example4.dSYM/Contents/Resources/DWARF/example4 new file mode 100644 index 0000000..66350a0 Binary files /dev/null and b/seal-hack/examples/example4.dSYM/Contents/Resources/DWARF/example4 differ diff --git a/seal-hack/examples/example5 b/seal-hack/examples/example5 new file mode 100755 index 0000000..8a3fce1 Binary files /dev/null and b/seal-hack/examples/example5 differ diff --git a/seal-hack/examples/example5.c b/seal-hack/examples/example5.c new file mode 100644 index 0000000..844c4a4 --- /dev/null +++ b/seal-hack/examples/example5.c @@ -0,0 +1,120 @@ +/* example5.c - update the system using the timer interrupt, please compile + * using WATCOM C/C++32 and assume that the stack segment is + * not pegged to the DGROUP segment: + * + * wcl386 -l=dos4g -zu -s -I..\include example5.c ..\lib\dos\audiowcf.lib + */ + +#ifndef __WATCOMC__ + +#include + +int main(void) +{ + printf("This example only works with WATCOM C/C++32 and DOS4GW\n"); + return 0; +} + +#else + +#include +#include +#include +#include +#include +#include + +/* call the timer handler 70 times per second */ +#define TIMER_RATE (1193180/70) + +volatile void (interrupt far *lpfnBIOSTimerHandler)(void) = NULL; +volatile long dwTimerAccum = 0L; + +void SetBorderColor(BYTE nColor) +{ + outp(0x3c0, 0x31); + outp(0x3c0, nColor); +} + +void interrupt far TimerHandler(void) +{ + SetBorderColor(1); + AUpdateAudio(); + SetBorderColor(0); + if ((dwTimerAccum += TIMER_RATE) >= 0x10000L) { + dwTimerAccum -= 0x10000L; + lpfnBIOSTimerHandler(); + } + else { + outp(0x20, 0x20); + } +} + +VOID InitTimerHandler(VOID) +{ + lpfnBIOSTimerHandler = _dos_getvect(0x08); + _dos_setvect(0x08, TimerHandler); + outp(0x43, 0x34); + outp(0x40, LOBYTE(TIMER_RATE)); + outp(0x40, HIBYTE(TIMER_RATE)); +} + +VOID DoneTimerHandler(VOID) +{ + outp(0x43, 0x34); + outp(0x40, 0x00); + outp(0x40, 0x00); + _dos_setvect(0x08, lpfnBIOSTimerHandler); +} + + +int main(void) +{ + static AUDIOINFO info; + static AUDIOCAPS caps; + static LPAUDIOMODULE lpModule; + + /* initialize audio library */ + AInitialize(); + + /* open audio device */ + info.nDeviceId = AUDIO_DEVICE_MAPPER; + info.wFormat = AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO; + info.nSampleRate = 44100; + AOpenAudio(&info); + + /* show device information */ + AGetAudioDevCaps(info.nDeviceId, &caps); + printf("%s detected. Please type EXIT to return.\n", caps.szProductName); + + /* load module file */ + ALoadModuleFile("test.s3m", &lpModule, 0); + + /* open voices for module */ + AOpenVoices(lpModule->nTracks); + + /* play the module file */ + APlayModule(lpModule); + + /* initialize the timer routines */ + InitTimerHandler(); + + /* invoke the DOS command processor */ + system(getenv("COMSPEC")); + + /* terminate the timer routines */ + DoneTimerHandler(); + + /* stop playing the module */ + AStopModule(); + ACloseVoices(); + + /* release the waveform & module */ + AFreeModuleFile(lpModule); + + /* close audio device */ + ACloseAudio(); + return 0; +} + +#endif diff --git a/seal-hack/examples/example5.dSYM/Contents/Info.plist b/seal-hack/examples/example5.dSYM/Contents/Info.plist new file mode 100644 index 0000000..dd95b14 --- /dev/null +++ b/seal-hack/examples/example5.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.example5 + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/seal-hack/examples/example5.dSYM/Contents/Resources/DWARF/example5 b/seal-hack/examples/example5.dSYM/Contents/Resources/DWARF/example5 new file mode 100644 index 0000000..08cb14a Binary files /dev/null and b/seal-hack/examples/example5.dSYM/Contents/Resources/DWARF/example5 differ diff --git a/seal-hack/examples/example6 b/seal-hack/examples/example6 new file mode 100755 index 0000000..bd68c2b Binary files /dev/null and b/seal-hack/examples/example6 differ diff --git a/seal-hack/examples/example6.c b/seal-hack/examples/example6.c new file mode 100644 index 0000000..b8bffb6 --- /dev/null +++ b/seal-hack/examples/example6.c @@ -0,0 +1,100 @@ +/* example6.c - play a streamed sample (sine wave) using triple buffering */ + +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__) || defined(__DJGPP__) +#include +#else +#define kbhit() 0 +#endif + +int main(void) +{ + AUDIOINFO info; + AUDIOCAPS caps; + AUDIOWAVE wave; + HAC voice; + int i; + float t, dt; + long position, chunkSize, chunkPosition; + + /* initialize library */ + AInitialize(); + + /* open audio device */ + info.nDeviceId = AUDIO_DEVICE_MAPPER; + info.wFormat = AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO; + info.nSampleRate = 44100; + AOpenAudio(&info); + + /* show device name */ + AGetAudioDevCaps(info.nDeviceId, &caps); + printf("%s detected. Press any key to exit.\n", caps.szProductName); + + /* open audio voice */ + AOpenVoices(1); + ACreateAudioVoice(&voice); + ASetVoiceVolume(voice, 64); + ASetVoicePanning(voice, 128); + + /* setup buffer length to 1/60th of a second */ + chunkPosition = 0; + chunkSize = info.nSampleRate / 60; + + /* create a looped sound buffer of 3 x 1/60th secs */ + wave.nSampleRate = info.nSampleRate; + wave.dwLength = 3 * chunkSize; + wave.dwLoopStart = 0; + wave.dwLoopEnd = wave.dwLength; + wave.wFormat = AUDIO_FORMAT_8BITS | AUDIO_FORMAT_MONO | AUDIO_FORMAT_LOOP; + ACreateAudioData(&wave); + + /* clean up sound buffer */ + memset(wave.lpData, 0, wave.dwLength); + AWriteAudioData(&wave, 0, wave.dwLength); + + /* setup 200 Hz sine wave parameters */ + t = 0.0; + dt = 2.0 * M_PI * 200.0 / wave.nSampleRate; + + printf("%d-bit %s %u Hz, buffer size = %ld, chunk size = %ld\n", + info.wFormat & AUDIO_FORMAT_16BITS ? 16 : 8, + info.wFormat & AUDIO_FORMAT_STEREO ? "stereo" : "mono", + info.nSampleRate, wave.dwLength, chunkSize); + + /* start playing the sound buffer */ + APlayVoice(voice, &wave); + + while (!kbhit()) { + /* do not fill more than 'chunkSize' samples */ + AUpdateAudioEx(chunkSize); + + /* update the chunk of samples at 'chunkPosition' */ + AGetVoicePosition(voice, &position); + if (position < chunkPosition || position >= chunkPosition + chunkSize) { + for (i = 0; i < chunkSize; i++) + wave.lpData[chunkPosition++] = 64.0 * sin(t += dt); + AWriteAudioData(&wave, chunkPosition - chunkSize, chunkSize); + if (chunkPosition >= wave.dwLength) + chunkPosition = 0; + } + } + + /* stop playing the buffer */ + AStopVoice(voice); + + /* release sound buffer */ + ADestroyAudioData(&wave); + + /* release audio voices */ + ADestroyAudioVoice(voice); + ACloseVoices(); + + /* close audio device */ + ACloseAudio(); + return 0; +} diff --git a/seal-hack/examples/example6.dSYM/Contents/Info.plist b/seal-hack/examples/example6.dSYM/Contents/Info.plist new file mode 100644 index 0000000..f2679f4 --- /dev/null +++ b/seal-hack/examples/example6.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.example6 + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/seal-hack/examples/example6.dSYM/Contents/Resources/DWARF/example6 b/seal-hack/examples/example6.dSYM/Contents/Resources/DWARF/example6 new file mode 100644 index 0000000..d4a4e87 Binary files /dev/null and b/seal-hack/examples/example6.dSYM/Contents/Resources/DWARF/example6 differ diff --git a/seal-hack/examples/mk b/seal-hack/examples/mk new file mode 100755 index 0000000..4cc8a63 --- /dev/null +++ b/seal-hack/examples/mk @@ -0,0 +1,41 @@ +#!/bin/sh + +case `uname -sr` in + IRIX\ 4.0.*) + CC=gcc + STRIP=strip + LIBS="-L../lib/Indigo -laudio -lm" ;; + SunOS\ 4.1.*) + CC=gcc + STRIP=strip + LIBS="-L../lib/SunOS -laudio -lm" ;; + SunOS\ 5.*) + CC=gcc + STRIP=strip + LIBS="-L../lib/Solaris -laudio -lm" ;; + Linux*) + CC=gcc + STRIP=strip + LIBS="-L../lib/Linux -lsdlseal -lm `sdl-config --libs`" ;; + Darwin*) + CC=clang + STRIP=false + LIBS="-L../lib/MacOSX -laudio -lm `allegro-config --libs` -arch i386" ;; + FreeBSD*) + CC=gcc + STRIP=strip + LIBS="-L../lib/FreeBSD -laudio -lm" ;; + BeOS*) + CC=gcc + STRIP=true + LIBS="-L../lib/BeOS -laudio -lroot -lbe -lmedia" ;; + *) + echo "This program has not been tested on your machine!" + exit +esac + +for f in 1 2 3 4 5 6; do + echo "compiling example$f.c" + $CC -I../include -g -o example$f example$f.c $LIBS + $STRIP example$f +done diff --git a/seal-hack/examples/mk.bat b/seal-hack/examples/mk.bat new file mode 100644 index 0000000..ca2340d --- /dev/null +++ b/seal-hack/examples/mk.bat @@ -0,0 +1,88 @@ +@echo off + +if "%1"=="bcl" goto bcl +if "%1"=="wcl" goto wcl +if "%1"=="bcx" goto bcx +if "%1"=="wcf" goto wcf +if "%1"=="djf" goto djf +if "%1"=="w16bc" goto w16bc +if "%1"=="w16wc" goto w16wc +if "%1"=="w32bc" goto w32bc +if "%1"=="w32wc" goto w32wc +if "%1"=="w32vc" goto w32vc +if "%1"=="w32bp" goto w32bp + +:usage +echo **** usage: build [target] +echo **** +echo **** 16-bit DOS real mode, large memory model: +echo **** bcl - Borland C++ 3.1 real mode +echo **** wcl - Watcom C/C++16 10.0 real mode +echo **** +echo **** 16-bit DOS protected mode, large memory model: +echo **** bcx - Borland C++ 4.5 protected mode (DPMI16 PowerPack) +echo **** +echo **** 32-bit DOS protected mode, flat memory model: +echo **** wcf - Watcom C/C++32 10.0 protected mode (DOS4GW Extender) +echo **** djf - DJGPP V 2.0 protected mode (GO32/DPMI32 Extender) +echo **** +echo **** 16-bit Windows 3.x protected mode, large memory model: +echo **** w16bc - Borland C++ 3.1 protected mode (Win16) +echo **** w16wc - Watcom C/C++16 10.0 protected mode (Win16) +echo **** +echo **** 32-bit Windows 95/NT protected mode, flat memory model: +echo **** w32bc - Borland C++ 4.5 protected mode (Win32) +echo **** w32wc - Watcom C/C++16 10.0 protected mode (Win32) +echo **** w32vc - Microsoft Visual C++ 4.1 protected mode (Win32) +echo **** w32bp - Borland Delphi 2.0 protected mode (Win32) +echo **** +echo **** NOTE: 16-bit libraries are not available in this release. +goto exit + +:bcl +for %%f in (*.c) do bcc -ml -I..\include ..\lib\dos\audiobcl.lib %%f +goto exit + +:wcl +for %%f in (*.c) do wcl -ml -I..\include ..\lib\dos\audiowcl.lib %%f +goto exit + +:bcx +for %%f in (*.c) do bcc -ml -WX -I..\include ..\lib\dos\audiobcx.lib %%f +goto exit + +:wcf +for %%f in (*.c) do wcl386 -zq -I..\include ..\lib\dos\audiowcf.lib %%f +goto exit + +:djf +for %%f in (1 2 3 4) do gcc -o example%%f.exe -I..\include example%%f.c -L..\lib\dos -laudio +goto exit + +:w16bc +for %%f in (*.c) do bcc -ml -W -I..\include ..\lib\win16\audw16bc.lib %%f +goto exit + +:w16wc +for %%f in (*.c) do wcl -ml -zw -I..\include ..\lib\win16\audw16wc.lib mmsystem.lib %%f +goto exit + +:w32bc +for %%f in (*.c) do bcc32a -WC -DWIN32 -I..\include ..\lib\win32\audw32bc.lib %%f +goto exit + +:w32wc +for %%f in (*.c) do wcl386 -l=nt -DWIN32 -I..\include ..\lib\win32\audw32wc.lib %%f +goto exit + +:w32vc +for %%f in (*.c) do cl -DWIN32 -I..\include ..\lib\win32\audw32vc.lib %%f +goto exit + +:w32bp +dcc32 -CC -U..\include demo.pas +goto exit + +:exit +if exist *.obj del *.obj > nul +if exist *.o del *.o > nul diff --git a/seal-hack/examples/test.s3m b/seal-hack/examples/test.s3m new file mode 100644 index 0000000..bc9a48f Binary files /dev/null and b/seal-hack/examples/test.s3m differ diff --git a/seal-hack/examples/test.wav b/seal-hack/examples/test.wav new file mode 100644 index 0000000..9c50baf Binary files /dev/null and b/seal-hack/examples/test.wav differ diff --git a/seal-hack/examples/vb/form1.frm b/seal-hack/examples/vb/form1.frm new file mode 100644 index 0000000..585399e --- /dev/null +++ b/seal-hack/examples/vb/form1.frm @@ -0,0 +1,377 @@ +VERSION 5.00 +Object = "{BDC217C8-ED16-11CD-956C-0000C04E4C0A}#1.1#0"; "TABCTL32.OCX" +Begin VB.Form Form1 + BorderStyle = 1 'Fixed Single + Caption = "Seal 1.03 - Visual Basic Interface" + ClientHeight = 5220 + ClientLeft = 2220 + ClientTop = 2205 + ClientWidth = 6690 + ControlBox = 0 'False + LinkTopic = "Form1" + MaxButton = 0 'False + PaletteMode = 1 'UseZOrder + ScaleHeight = 5220 + ScaleWidth = 6690 + Begin VB.CommandButton Command3 + Caption = "Quit" + Height = 375 + Left = 5880 + TabIndex = 12 + Top = 0 + Width = 735 + End + Begin VB.TextBox Text1 + Appearance = 0 'Flat + BackColor = &H80000004& + BorderStyle = 0 'None + Enabled = 0 'False + BeginProperty Font + Name = "MS Sans Serif" + Size = 8.25 + Charset = 0 + Weight = 700 + Underline = 0 'False + Italic = 0 'False + Strikethrough = 0 'False + EndProperty + Height = 285 + Left = 1440 + TabIndex = 9 + Text = "None" + Top = 120 + Width = 4215 + End + Begin TabDlg.SSTab SSTab1 + Height = 4455 + Left = 360 + TabIndex = 0 + Top = 480 + Width = 6015 + _ExtentX = 10610 + _ExtentY = 7858 + _Version = 327680 + Tab = 2 + TabHeight = 520 + TabCaption(0) = "Song Selector" + TabPicture(0) = "Form1.frx":0000 + Tab(0).ControlCount= 3 + Tab(0).ControlEnabled= 0 'False + Tab(0).Control(0)= "File1" + Tab(0).Control(0).Enabled= 0 'False + Tab(0).Control(1)= "Drive1" + Tab(0).Control(1).Enabled= 0 'False + Tab(0).Control(2)= "Dir1" + Tab(0).Control(2).Enabled= 0 'False + TabCaption(1) = "PlayBack Controls" + TabPicture(1) = "Form1.frx":001C + Tab(1).ControlCount= 6 + Tab(1).ControlEnabled= 0 'False + Tab(1).Control(0)= "Label2" + Tab(1).Control(0).Enabled= 0 'False + Tab(1).Control(1)= "Frame1" + Tab(1).Control(1).Enabled= 0 'False + Tab(1).Control(2)= "Command2" + Tab(1).Control(2).Enabled= -1 'True + Tab(1).Control(3)= "PlayButton" + Tab(1).Control(3).Enabled= -1 'True + Tab(1).Control(4)= "Command1" + Tab(1).Control(4).Enabled= -1 'True + Tab(1).Control(5)= "StopButton" + Tab(1).Control(5).Enabled= -1 'True + TabCaption(2) = "Author Info" + TabPicture(2) = "Form1.frx":0038 + Tab(2).ControlCount= 4 + Tab(2).ControlEnabled= -1 'True + Tab(2).Control(0)= "Label4" + Tab(2).Control(0).Enabled= 0 'False + Tab(2).Control(1)= "Label3" + Tab(2).Control(1).Enabled= 0 'False + Tab(2).Control(2)= "Command4" + Tab(2).Control(2).Enabled= 0 'False + Tab(2).Control(3)= "Command5" + Tab(2).Control(3).Enabled= 0 'False + Begin VB.CommandButton Command5 + Caption = "SEAL Page" + Height = 615 + Left = 1200 + TabIndex = 16 + Top = 3240 + Width = 3855 + End + Begin VB.CommandButton Command4 + Caption = "Egerter Software Home Page" + Height = 615 + Left = 1200 + TabIndex = 13 + Top = 2040 + Width = 3855 + End + Begin VB.CommandButton StopButton + Caption = "Stop" + Height = 495 + Left = -72480 + TabIndex = 7 + Top = 2520 + Width = 855 + End + Begin VB.CommandButton Command1 + Caption = "Next" + Height = 495 + Left = -71400 + TabIndex = 6 + Top = 1800 + Width = 855 + End + Begin VB.CommandButton PlayButton + Caption = "Play" + Height = 495 + Left = -72480 + TabIndex = 5 + Top = 1800 + Width = 855 + End + Begin VB.CommandButton Command2 + Caption = "Prev" + Height = 495 + Left = -73560 + TabIndex = 4 + Top = 1800 + Width = 855 + End + Begin VB.DirListBox Dir1 + Height = 1440 + Left = -74280 + TabIndex = 3 + Top = 960 + Width = 4695 + End + Begin VB.DriveListBox Drive1 + Height = 315 + Left = -74280 + TabIndex = 2 + Top = 480 + Width = 4695 + End + Begin VB.FileListBox File1 + Height = 1650 + Left = -74280 + Pattern = "*.mod;*.s3m;*.mtm;*.xm" + TabIndex = 1 + Top = 2520 + Width = 4695 + End + Begin VB.Frame Frame1 + Caption = "Playback" + Height = 2175 + Left = -74280 + TabIndex = 10 + Top = 1200 + Width = 4575 + End + Begin VB.Label Label3 + Caption = "SEAL by Carlos Hasan" + BeginProperty Font + Name = "MS Sans Serif" + Size = 8.25 + Charset = 0 + Weight = 700 + Underline = 0 'False + Italic = 0 'False + Strikethrough = 0 'False + EndProperty + Height = 255 + Left = 1440 + TabIndex = 15 + Top = 1080 + Width = 3495 + End + Begin VB.Label Label4 + Caption = "Modifications to VB interface by Barry Egerter" + Height = 255 + Left = 1440 + TabIndex = 14 + Top = 1320 + Width = 3615 + End + Begin VB.Label Label2 + Caption = "Use this simple playback system to control the music." + Height = 255 + Left = -74160 + TabIndex = 11 + Top = 720 + Width = 4335 + End + End + Begin VB.Label Label1 + Caption = "Current Song:" + Height = 255 + Left = 360 + TabIndex = 8 + Top = 120 + Width = 1095 + End +End +Attribute VB_Name = "Form1" +Attribute VB_GlobalNameSpace = False +Attribute VB_Creatable = False +Attribute VB_PredeclaredId = True +Attribute VB_Exposed = False +Dim iewindow As InternetExplorer +Dim szFileName As String * 256 +Dim lpModule As Long +Dim bSongPlaying As Long + + +Private Sub Command1_Click() + + Dim pnOrder As Long + Dim lpnRow As Long + + If AGetModulePosition(pnOrder, lpnRow) <> AUDIO_ERROR_NONE Then + Exit Sub + End If + + If ASetModulePosition(pnOrder + 1, 0) <> AUDIO_ERROR_NONE Then + Exit Sub + End If + +End Sub + +Private Sub Command2_Click() + + Dim pnOrder As Long + Dim lpnRow As Long + + If AGetModulePosition(pnOrder, lpnRow) <> AUDIO_ERROR_NONE Then + Exit Sub + End If + + If pnOrder > 1 Then + pnOrder = pnOrder - 1 + Else + pnOrder = 0 + End If + + If ASetModulePosition(pnOrder, 0) <> AUDIO_ERROR_NONE Then + Exit Sub + End If + +End Sub + +Private Sub Command3_Click() + + StopButton_Click + Form1.Hide + Unload Form1 + +End Sub + +Private Sub Command4_Click() + + Set iewindow = New InternetExplorer + + iewindow.Visible = True + iewindow.Navigate ("http://www.egerter.com") + +End Sub + +Private Sub Command5_Click() + + Set iewindow = New InternetExplorer + + iewindow.Visible = True + iewindow.Navigate ("http://www.egerter.com/seal") + +End Sub + +Private Sub Dir1_Change() + + File1.Path = Dir1.Path + File1.Refresh + +End Sub + +Private Sub Drive1_Change() + + Dir1.Path = Drive1.Drive + Dir1.Refresh + +End Sub + +Private Sub File1_Click() + + Text1.Text = Dir1.Path + "\" + File1.filename + Text1.Refresh + szFileName = Text1.Text + StopButton_Click + + SSTab1.Tab = 1 + +End Sub + +Private Sub PlayButton_Click() + ' WARNING! It's the very first time I have ever used VB, after some hours + ' I could finally write a sort of interface for AUDIOW32.DLL, it's not + ' perfect, there are still some things I couldn't figure how to port. + ' I used VB 4.0 and SEAL 1.03 to test this code. + + Dim Info As AudioInfo + + If bSongPlaying Then + StopButton_Click + End If + + ' set up audio configuration structure + Info.nDeviceId = AUDIO_DEVICE_MAPPER + Info.wFormat = AUDIO_FORMAT_STEREO + AUDIO_FORMAT_16BITS + Info.nSampleRate = 22050 ' 44100 is an unsigned 16-bit integer! + + ' open the default audio device, return if error + If AOpenAudio(Info) <> AUDIO_ERROR_NONE Then + Exit Sub + End If + + ' open 32 active voices + If AOpenVoices(32) <> AUDIO_ERROR_NONE Then + ACloseAudio + Exit Sub + End If + + ' load module file from disk, shutdown and return if error + If ALoadModuleFile(szFileName, lpModule, 0) <> AUDIO_ERROR_NONE Then + ACloseVoices + ACloseAudio + Exit Sub + End If + + ' start playing the module file + If APlayModule(lpModule) <> AUDIO_ERROR_NONE Then + ACloseVoices + ACloseAudio + Exit Sub + End If + + bSongPlaying = 1 + +End Sub + +Private Sub StopButton_Click() + + If bSongPlaying = 0 Then + Exit Sub + End If + + bSongPlaying = 0 + + ' stop playing the module file + AStopModule + + ' release the module file + AFreeModuleFile (lpModule) + + ' close audio device + ACloseVoices + ACloseAudio + +End Sub diff --git a/seal-hack/examples/vb/form1.frx b/seal-hack/examples/vb/form1.frx new file mode 100644 index 0000000..4d38e06 Binary files /dev/null and b/seal-hack/examples/vb/form1.frx differ diff --git a/seal-hack/examples/vb/project1.vbp b/seal-hack/examples/vb/project1.vbp new file mode 100644 index 0000000..2fe0f1c --- /dev/null +++ b/seal-hack/examples/vb/project1.vbp @@ -0,0 +1,43 @@ +Type=Exe +Object={F9043C88-F6F2-101A-A3C9-08002B2F49FB}#1.1#0; COMDLG32.OCX +Object={BDC217C8-ED16-11CD-956C-0000C04E4C0A}#1.1#0; TABCTL32.OCX +Object={3B7C8863-D78F-101B-B9B5-04021C009402}#1.1#0; RICHTX32.OCX +Object={6B7E6392-850A-101B-AFC0-4210102A8DA7}#1.1#0; COMCTL32.OCX +Object={FAEEE763-117E-101B-8933-08002B2F4F5A}#1.1#0; DBLIST32.OCX +Object={00028C01-0000-0000-0000-000000000046}#1.0#0; DBGRID32.OCX +Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#C:\WINDOWS\SYSTEM\stdole2.tlb#Standard OLE Types +Reference=*\G{EE008642-64A8-11CE-920F-08002B369A33}#2.0#0#C:\WINDOWS\SYSTEM\MSRDO20.DLL#Microsoft Remote Data Object 2.0 +Reference=*\G{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}#1.0#0#C:\WINDOWS\SYSTEM\SHDOCVW.DLL#Microsoft Internet Controls +Form=Form1.frm +Module=Audio; audio.Bas +Form=frmSplash.frm +IconForm="Form1" +Startup="frmSplash" +HelpFile="" +Title="SealStuf" +ExeName32="SEAL_VB.exe" +Command32="" +Name="SEALVB" +HelpContextID="0" +CompatibleMode="0" +MajorVer=1 +MinorVer=0 +RevisionVer=0 +AutoIncrementVer=0 +ServerSupportFiles=0 +VersionComments="Modified by Barry Egerter with initial code by Carlos Hasan" +VersionCompanyName="Egerter Software" +CompilationType=0 +OptimizationType=0 +FavorPentiumPro(tm)=0 +CodeViewDebugInfo=0 +NoAliasing=0 +BoundsCheck=0 +OverflowCheck=0 +FlPointCheck=0 +FDIVCheck=0 +UnroundedFP=0 +StartMode=0 +Unattended=0 +ThreadPerObject=0 +MaxNumberOfThreads=1 diff --git a/seal-hack/examples/vb/project1.vbw b/seal-hack/examples/vb/project1.vbw new file mode 100644 index 0000000..f50c536 --- /dev/null +++ b/seal-hack/examples/vb/project1.vbw @@ -0,0 +1,3 @@ +Form1 = 212, 37, 735, 505, C, 23, 44, 546, 512, +Audio = 0, 0, 0, 0, C +frmSplash = 88, 88, 611, 556, C, 92, 63, 615, 531, diff --git a/seal-hack/examples/vb/splash.frm b/seal-hack/examples/vb/splash.frm new file mode 100644 index 0000000..e6eb17a --- /dev/null +++ b/seal-hack/examples/vb/splash.frm @@ -0,0 +1,230 @@ +VERSION 5.00 +Begin VB.Form frmSplash + BorderStyle = 3 'Fixed Dialog + ClientHeight = 4245 + ClientLeft = 255 + ClientTop = 1410 + ClientWidth = 7380 + ClipControls = 0 'False + ControlBox = 0 'False + Icon = "Splash.frx":0000 + KeyPreview = -1 'True + LinkTopic = "Form2" + MaxButton = 0 'False + MinButton = 0 'False + ScaleHeight = 4245 + ScaleWidth = 7380 + ShowInTaskbar = 0 'False + StartUpPosition = 2 'CenterScreen + Begin VB.Frame Frame1 + Height = 4050 + Left = 150 + TabIndex = 0 + Top = 60 + Width = 7080 + Begin VB.Timer Timer1 + Interval = 1000 + Left = 6600 + Top = 3240 + End + Begin VB.Label Label1 + AutoSize = -1 'True + Caption = "Visual Basic Interface" + BeginProperty Font + Name = "Arial" + Size = 15.75 + Charset = 0 + Weight = 700 + Underline = 0 'False + Italic = 0 'False + Strikethrough = 0 'False + EndProperty + Height = 360 + Left = 2400 + TabIndex = 9 + Top = 1800 + Width = 3240 + End + Begin VB.Image imgLogo + Height = 2385 + Left = 360 + Picture = "Splash.frx":000C + Stretch = -1 'True + Top = 795 + Width = 1815 + End + Begin VB.Label lblCopyright + Caption = "Copyright 1997" + BeginProperty Font + Name = "Arial" + Size = 8.25 + Charset = 0 + Weight = 400 + Underline = 0 'False + Italic = 0 'False + Strikethrough = 0 'False + EndProperty + Height = 255 + Left = 4560 + TabIndex = 4 + Top = 3060 + Width = 2415 + End + Begin VB.Label lblCompany + Caption = "Egerter Software" + BeginProperty Font + Name = "Arial" + Size = 8.25 + Charset = 0 + Weight = 400 + Underline = 0 'False + Italic = 0 'False + Strikethrough = 0 'False + EndProperty + Height = 255 + Left = 4560 + TabIndex = 3 + Top = 3270 + Width = 2415 + End + Begin VB.Label lblWarning + AutoSize = -1 'True + Caption = "Warning - Do not close the application while a song is still playing.......bugs exist!" + BeginProperty Font + Name = "Arial" + Size = 8.25 + Charset = 0 + Weight = 400 + Underline = 0 'False + Italic = 0 'False + Strikethrough = 0 'False + EndProperty + Height = 210 + Left = 600 + TabIndex = 2 + Top = 3720 + Width = 5790 + End + Begin VB.Label lblVersion + Alignment = 1 'Right Justify + AutoSize = -1 'True + Caption = "Version 1.0" + BeginProperty Font + Name = "Arial" + Size = 12 + Charset = 0 + Weight = 700 + Underline = 0 'False + Italic = 0 'False + Strikethrough = 0 'False + EndProperty + Height = 285 + Left = 5580 + TabIndex = 5 + Top = 2700 + Width = 1275 + End + Begin VB.Label lblPlatform + Alignment = 1 'Right Justify + AutoSize = -1 'True + Caption = "for Windows 95/NT" + BeginProperty Font + Name = "Arial" + Size = 15.75 + Charset = 0 + Weight = 700 + Underline = 0 'False + Italic = 0 'False + Strikethrough = 0 'False + EndProperty + Height = 360 + Left = 4020 + TabIndex = 6 + Top = 2340 + Width = 2835 + End + Begin VB.Label lblProductName + AutoSize = -1 'True + Caption = "Seal 1.03" + BeginProperty Font + Name = "Arial" + Size = 32.25 + Charset = 0 + Weight = 700 + Underline = 0 'False + Italic = 0 'False + Strikethrough = 0 'False + EndProperty + Height = 765 + Left = 2280 + TabIndex = 8 + Top = 1080 + Width = 2775 + End + Begin VB.Label lblLicenseTo + Alignment = 1 'Right Justify + Caption = "Licensed to all users of the Egerter Software Web site. Free for home and office use." + BeginProperty Font + Name = "Arial" + Size = 8.25 + Charset = 0 + Weight = 400 + Underline = 0 'False + Italic = 0 'False + Strikethrough = 0 'False + EndProperty + Height = 255 + Left = 120 + TabIndex = 1 + Top = 240 + Width = 6855 + End + Begin VB.Label lblCompanyProduct + AutoSize = -1 'True + Caption = "Carlos Hasan presents" + BeginProperty Font + Name = "Arial" + Size = 18 + Charset = 0 + Weight = 700 + Underline = 0 'False + Italic = 0 'False + Strikethrough = 0 'False + EndProperty + Height = 435 + Left = 1800 + TabIndex = 7 + Top = 705 + Width = 3870 + End + End +End +Attribute VB_Name = "frmSplash" +Attribute VB_GlobalNameSpace = False +Attribute VB_Creatable = False +Attribute VB_PredeclaredId = True +Attribute VB_Exposed = False +Dim counter +Option Explicit + +Private Sub Form_KeyPress(KeyAscii As Integer) + Unload Me +End Sub + +Private Sub Form_Unload(Cancel As Integer) + + Load Form1 + Form1.Show + +End Sub + +Private Sub Frame1_Click() + Unload Me +End Sub + +Private Sub Timer1_Timer() + counter = counter + 1 + If counter > 7 Then + Unload Me + End If +End Sub diff --git a/seal-hack/examples/vb/splash.frx b/seal-hack/examples/vb/splash.frx new file mode 100644 index 0000000..0cdadcd Binary files /dev/null and b/seal-hack/examples/vb/splash.frx differ diff --git a/seal-hack/include/audio.bas b/seal-hack/include/audio.bas new file mode 100644 index 0000000..4a21117 --- /dev/null +++ b/seal-hack/include/audio.bas @@ -0,0 +1,288 @@ +Attribute VB_Name = "Audio" +' +' $Id: audio.h 1.17 1996/09/25 17:13:02 chasan released $ +' +' SEAL Synthetic Audio Library API Interface +' +' Copyright (C) 1995, 1996, 1997, 1998, 1999 Carlos Hasan +' +' This program is free software; you can redistribute it and/or modify +' it under the terms of the GNU Lesser General Public License as published +' by the Free Software Foundation; either version 2 of the License, or +' (at your option) any later version. +' +' MICROSOFT VISUAL BASIC INTERFACE FOR WINDOWS 95/NT +' + +Option Explicit + +' audio system version number +Public Const AUDIO_SYSTEM_VERSION = &H101 + +' audio capabilities bit fields definitions +Public Const AUDIO_FORMAT_1M08 = &H1 +Public Const AUDIO_FORMAT_1S08 = &H2 +Public Const AUDIO_FORMAT_1M16 = &H4 +Public Const AUDIO_FORMAT_1S16 = &H8 +Public Const AUDIO_FORMAT_2M08 = &H10 +Public Const AUDIO_FORMAT_2S08 = &H20 +Public Const AUDIO_FORMAT_2M16 = &H40 +Public Const AUDIO_FORMAT_2S16 = &H80 +Public Const AUDIO_FORMAT_4M08 = &H100 +Public Const AUDIO_FORMAT_4S08 = &H200 +Public Const AUDIO_FORMAT_4M16 = &H400 +Public Const AUDIO_FORMAT_4S16 = &H800 + +' audio format bit fields defines for devices and waveforms +Public Const AUDIO_FORMAT_8BITS = &H0 +Public Const AUDIO_FORMAT_16BITS = &H1 +Public Const AUDIO_FORMAT_LOOP = &H10 +Public Const AUDIO_FORMAT_BIDILOOP = &H20 +Public Const AUDIO_FORMAT_REVERSE = &H80 +Public Const AUDIO_FORMAT_MONO = &H0 +Public Const AUDIO_FORMAT_STEREO = &H100 +Public Const AUDIO_FORMAT_FILTER = &H8000 + +' audio resource limits defines +Public Const AUDIO_MAX_VOICES = 32 +Public Const AUDIO_MAX_SAMPLES = 16 +Public Const AUDIO_MAX_PATCHES = 128 +Public Const AUDIO_MAX_PATTERNS = 256 +Public Const AUDIO_MAX_ORDERS = 256 +Public Const AUDIO_MAX_NOTES = 96 +Public Const AUDIO_MAX_POINTS = 12 +Public Const AUDIO_MIN_PERIOD = 1 +Public Const AUDIO_MAX_PERIOD = 31999 +Public Const AUDIO_MIN_VOLUME = 0 +Public Const AUDIO_MAX_VOLUME = 64 +Public Const AUDIO_MIN_PANNING = 0 +Public Const AUDIO_MAX_PANNING = 255 +Public Const AUDIO_MIN_POSITION = 0 +Public Const AUDIO_MAX_POSITION = 1048576 +Public Const AUDIO_MIN_FREQUENCY = 512 +Public Const AUDIO_MAX_FREQUENCY = 524288 + +' audio error code defines +Public Const AUDIO_ERROR_NONE = 0 +Public Const AUDIO_ERROR_INVALHANDLE = 1 +Public Const AUDIO_ERROR_INVALPARAM = 2 +Public Const AUDIO_ERROR_NOTSUPPORTED = 3 +Public Const AUDIO_ERROR_BADDEVICEID = 4 +Public Const AUDIO_ERROR_NODEVICE = 5 +Public Const AUDIO_ERROR_DEVICEBUSY = 6 +Public Const AUDIO_ERROR_BADFORMAT = 7 +Public Const AUDIO_ERROR_NOMEMORY = 8 +Public Const AUDIO_ERROR_NODRAMMEMORY = 9 +Public Const AUDIO_ERROR_FILENOTFOUND = 10 +Public Const AUDIO_ERROR_BADFILEFORMAT = 11 +Public Const AUDIO_LAST_ERROR = 11 + +' audio device identifiers +Public Const AUDIO_DEVICE_NONE = 0 +Public Const AUDIO_DEVICE_MAPPER = 65535 + +' audio product identifiers +Public Const AUDIO_PRODUCT_NONE = 0 +Public Const AUDIO_PRODUCT_SB = 1 +Public Const AUDIO_PRODUCT_SB15 = 2 +Public Const AUDIO_PRODUCT_SB20 = 3 +Public Const AUDIO_PRODUCT_SBPRO = 4 +Public Const AUDIO_PRODUCT_SB16 = 5 +Public Const AUDIO_PRODUCT_AWE32 = 6 +Public Const AUDIO_PRODUCT_WSS = 7 +Public Const AUDIO_PRODUCT_ESS = 8 +Public Const AUDIO_PRODUCT_GUS = 9 +Public Const AUDIO_PRODUCT_GUSDB = 10 +Public Const AUDIO_PRODUCT_GUSMAX = 11 +Public Const AUDIO_PRODUCT_IWAVE = 12 +Public Const AUDIO_PRODUCT_PAS = 13 +Public Const AUDIO_PRODUCT_PAS16 = 14 +Public Const AUDIO_PRODUCT_ARIA = 15 +Public Const AUDIO_PRODUCT_WINDOWS = 256 +Public Const AUDIO_PRODUCT_LINUX = 257 +Public Const AUDIO_PRODUCT_SPARC = 258 +Public Const AUDIO_PRODUCT_SGI = 259 +Public Const AUDIO_PRODUCT_DSOUND = 260 + +' audio envelope bit fields +Public Const AUDIO_ENVELOPE_ON = &H1 +Public Const AUDIO_ENVELOPE_SUSTAIN = &H2 +Public Const AUDIO_ENVELOPE_LOOP = &H4 + +' audio pattern bit fields +Public Const AUDIO_PATTERN_PACKED = &H80 +Public Const AUDIO_PATTERN_NOTE = &H1 +Public Const AUDIO_PATTERN_SAMPLE = &H2 +Public Const AUDIO_PATTERN_VOLUME = &H4 +Public Const AUDIO_PATTERN_COMMAND = &H8 +Public Const AUDIO_PATTERN_PARAMS = &H10 + +' audio module bit fields +Public Const AUDIO_MODULE_AMIGA = &H0 +Public Const AUDIO_MODULE_LINEAR = &H1 +Public Const AUDIO_MODULE_PANNING = &H8000 + +' FIXME: structures should be byte aligned + +' audio capabilities structure +Public Type AudioCaps + wProductId As Integer ' product identifier + szProductName As String * 30 ' product name + dwFormats As Long ' formats supported +End Type + + +' audio format structure +Public Type AudioInfo + nDeviceId As Long ' device identifier + wFormat As Integer ' playback format + nSampleRate As Integer ' sampling frequency +End Type + +' audio waveform structure +Public Type AudioWave + lpData As Long ' data pointer + dwHandle As Long ' waveform handle + dwLength As Long ' waveform length + dwLoopStart As Long ' loop start point + dwLoopEnd As Long ' loop end point + nSampleRate As Integer ' sampling rate + wFormat As Integer ' format bits +End Type + + +' audio envelope point structure +Public Type AudioPoint + nFrame As Integer ' envelope frame + nValue As Integer ' envelope value +End Type + +' audio envelope structure +Public Type AudioEnvelope + aEnvelope(0 To 11) As AudioPoint ' envelope points + nPoints As Byte ' number of points + nSustain As Byte ' sustain point + nLoopStart As Byte ' loop start point + nLoopEnd As Byte ' loop end point + wFlags As Integer ' envelope flags + nSpeed As Integer ' envelope speed +End Type + +' audio sample structure +Public Type AudioSample + szSampleName As String * 32 ' sample name + nVolume As Byte ' default volume + nPanning As Byte ' default panning + nRelativeNote As Byte ' relative note + nFinetune As Byte ' finetune + Wave As AudioWave ' waveform handle +End Type + +' audio patch structure +Public Type AudioPatch + szPatchName As String * 32 ' patch name + aSampleNumber(0 To 95) As Byte ' multi-sample table + nSamples As Integer ' number of samples + nVibratoType As Byte ' vibrato type + nVibratoSweep As Byte ' vibrato sweep + nVibratoDepth As Byte ' vibrato depth + nVibratoRate As Byte ' vibrato rate + nVolumeFadeout As Integer ' volume fadeout + Volume As AudioEnvelope ' volume envelope + Panning As AudioEnvelope ' panning envelope + aSampleTable As Long ' sample table (pointer) +End Type + +' audio pattern structure +Public Type AudioPattern + nPacking As Integer ' packing type + nTracks As Integer ' number of tracks + nRows As Integer ' number of rows + nSize As Integer ' data size + lpData As Long ' data pointer +End Type + +' audio module structure +Public Type AudioModule + szModuleName As String * 32 ' module name + wFlags As Integer ' module flags + nOrders As Integer ' number of orders + nRestart As Integer ' restart position + nTracks As Integer ' number of tracks + nPatterns As Integer ' number of patterns + nPatches As Integer ' number of patches + nTempo As Integer ' initial tempo + nBPM As Integer ' initial BPM + aOrderTable(0 To 255) As Byte ' order table + aPanningTable(0 To 31) As Byte ' panning table + aPatternTable As Long ' pattern table (pointer) + aPatchTable As Long ' patch table (pointer) +End Type + +' FIXME: how do I define callback functions? +'typedef VOID (AIAPI* LPFNAUDIOWAVE)(LPBYTE, UINT); +'typedef VOID (AIAPI* LPFNAUDIOTIMER)(VOID); +'typedef VOID (AIAPI* LPFNAUDIOCALLBACK)(BYTE, UINT, UINT); + +' audio interface API prototypes +Public Declare Function AInitialize Lib "AudioW32" () As Long +Public Declare Function AGetVersion Lib "AudioW32" () As Long +Public Declare Function AGetAudioNumDevs Lib "AudioW32" () As Long +Public Declare Function AGetAudioDevCaps Lib "AudioW32" (ByVal nDeviceId As Long, ByRef lpCaps As AudioCaps) As Long +Public Declare Function AGetErrorText Lib "AudioW32" (ByVal nErrorCode As Long, ByVal lpszText As String, ByVal nSize As Long) As Long + +Public Declare Function APingAudio Lib "AudioW32" (ByRef lpnDeviceId As Long) As Long +Public Declare Function AOpenAudio Lib "AudioW32" (ByRef lpInfo As AudioInfo) As Long +Public Declare Function ACloseAudio Lib "AudioW32" () As Long +Public Declare Function AUpdateAudio Lib "AudioW32" () As Long + +Public Declare Function AOpenVoices Lib "AudioW32" (ByVal nVoices As Long) As Long +Public Declare Function ACloseVoices Lib "AudioW32" () As Long + +Public Declare Function ASetAudioCallback Lib "AudioW32" (ByVal lpfnAudioWave As Long) As Long +Public Declare Function ASetAudioTimerProc Lib "AudioW32" (ByVal lpfnAudioTimer As Long) As Long +Public Declare Function ASetAudioTimerRate Lib "AudioW32" (ByVal nTimerRate As Long) As Long + +Public Declare Function AGetAudioDataAvail Lib "AudioW32" () As Long +Public Declare Function ACreateAudioData Lib "AudioW32" (ByRef lpWave As AudioWave) As Long +Public Declare Function ADestroyAudioData Lib "AudioW32" (ByRef lpWave As AudioWave) As Long +Public Declare Function AWriteAudioData Lib "AudioW32" (ByRef lpWave As AudioWave, ByVal dwOffset As Long, ByVal nCount As Long) As Long + +Public Declare Function ACreateAudioVoice Lib "AudioW32" (ByRef lphVoice As Long) As Long +Public Declare Function ADestroyAudioVoice Lib "AudioW32" (ByVal hVoice As Long) As Long + +Public Declare Function APlayVoice Lib "AudioW32" (ByVal hVoice As Long, ByVal lpWave As Long) As Long +Public Declare Function APrimeVoice Lib "AudioW32" (ByVal hVoice As Long, ByVal lpWave As Long) As Long +Public Declare Function AStartVoice Lib "AudioW32" (ByVal hVoice As Long) As Long +Public Declare Function AStopVoice Lib "AudioW32" (ByVal hVoice As Long) As Long + +Public Declare Function ASetVoicePosition Lib "AudioW32" (ByVal hVoice As Long, ByVal dwPosition As Long) As Long +Public Declare Function ASetVoiceFrequency Lib "AudioW32" (ByVal hVoice As Long, ByVal dwFrequency As Long) As Long +Public Declare Function ASetVoiceVolume Lib "AudioW32" (ByVal hVoice As Long, ByVal nVolume As Long) As Long +Public Declare Function ASetVoicePanning Lib "AudioW32" (ByVal hVoice As Long, ByVal nPanning As Long) As Long + +Public Declare Function AGetVoicePosition Lib "AudioW32" (ByVal hVoice As Long, ByRef lpdwPosition As Long) As Long +Public Declare Function AGetVoiceFrequency Lib "AudioW32" (ByVal hVoice As Long, ByRef lpdwFrequency As Long) As Long +Public Declare Function AGetVoiceVolume Lib "AudioW32" (ByVal hVoice As Long, ByRef lpnVolume As Long) As Long +Public Declare Function AGetVoicePanning Lib "AudioW32" (ByVal hVoice As Long, ByRef lpnPanning As Long) As Long +Public Declare Function AGetVoiceStatus Lib "AudioW32" (ByVal hVoice As Long, ByRef lpnStatus As Long) As Long + +Public Declare Function APlayModule Lib "AudioW32" (ByVal lpModule As Long) As Long +Public Declare Function AStopModule Lib "AudioW32" () As Long +Public Declare Function APauseModule Lib "AudioW32" () As Long +Public Declare Function AResumeModule Lib "AudioW32" () As Long +Public Declare Function ASetModuleVolume Lib "AudioW32" (ByVal nVolume As Long) As Long +Public Declare Function ASetModulePosition Lib "AudioW32" (ByVal nOrder As Long, ByVal nRow As Long) As Long +Public Declare Function AGetModuleVolume Lib "AudioW32" (ByVal lpnVolume As Long) As Long +Public Declare Function AGetModulePosition Lib "AudioW32" (ByRef pnOrder As Long, ByRef lpnRow As Long) As Long +Public Declare Function AGetModuleStatus Lib "AudioW32" (ByRef lpnStatus As Long) As Long +Public Declare Function ASetModuleCallback Lib "AudioW32" (ByVal lpfnAudioCallback As Long) As Long + +' FIXME: how do I define pointers to AudioModule and AudioWave? + +Public Declare Function ALoadModuleFile Lib "AudioW32" (ByVal lpszFileName As String, ByRef lplpModule As Long, ByVal dwFileOffset As Long) As Long +Public Declare Function AFreeModuleFile Lib "AudioW32" (ByVal lpModule As Long) As Long + +Public Declare Function ALoadWaveFile Lib "AudioW32" (ByVal lpszFileName As String, ByRef lplpWave As Long, ByVal dwFileOffset As Long) As Long +Public Declare Function AFreeWaveFile Lib "AudioW32" (ByVal lpWave As Long) As Long + diff --git a/seal-hack/include/audio.h b/seal-hack/include/audio.h new file mode 100644 index 0000000..75e599f --- /dev/null +++ b/seal-hack/include/audio.h @@ -0,0 +1,377 @@ +/* + * $Id: audio.h 1.17 1996/09/25 17:13:02 chasan released $ + * 1.18 1998/10/12 23:54:08 chasan released + * 1.19 1998/10/24 18:20:52 chasan released + * 1.20 1999/06/27 17:49:49 chasan released + * + * SEAL Synthetic Audio Library API Interface + * + * Copyright (C) 1995, 1996, 1997, 1998, 1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __AUDIO_H +#define __AUDIO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WIN32 +#define AIAPI +#else +#define AIAPI __stdcall +#endif + +#ifndef WINAPI + +/* atomic data types definitions */ + typedef void VOID; + typedef char CHAR; + typedef int INT; + typedef long LONG; + typedef int BOOL; + + typedef unsigned char BYTE; + typedef unsigned short WORD; + typedef unsigned int UINT; + typedef unsigned long DWORD; + + typedef VOID* LPVOID; + typedef CHAR* LPCHAR; + typedef INT* LPINT; + typedef LONG* LPLONG; + typedef BOOL* LPBOOL; + typedef BYTE* LPBYTE; + typedef WORD* LPWORD; + typedef UINT* LPUINT; + typedef DWORD* LPDWORD; + typedef CHAR* LPSTR; + typedef DWORD HANDLE; + +/* helper macros */ +#define LOBYTE(s) ((BYTE)(s)) +#define HIBYTE(s) ((BYTE)((WORD)(s)>>8)) +#define LOWORD(l) ((WORD)(l)) +#define HIWORD(l) ((WORD)((DWORD)(l)>>16)) +#define MAKEWORD(l,h) ((WORD)(((BYTE)(l))|(((WORD)((BYTE)(h)))<<8))) +#define MAKELONG(l,h) ((DWORD)(((WORD)(l))|(((DWORD)((WORD)(h)))<<16))) + +#endif + + +/* audio system version number */ +#define AUDIO_SYSTEM_VERSION 0x0106 + +/* audio capabilities bit fields definitions */ +#define AUDIO_FORMAT_1M08 0x00000001 +#define AUDIO_FORMAT_1S08 0x00000002 +#define AUDIO_FORMAT_1M16 0x00000004 +#define AUDIO_FORMAT_1S16 0x00000008 +#define AUDIO_FORMAT_2M08 0x00000010 +#define AUDIO_FORMAT_2S08 0x00000020 +#define AUDIO_FORMAT_2M16 0x00000040 +#define AUDIO_FORMAT_2S16 0x00000080 +#define AUDIO_FORMAT_4M08 0x00000100 +#define AUDIO_FORMAT_4S08 0x00000200 +#define AUDIO_FORMAT_4M16 0x00000400 +#define AUDIO_FORMAT_4S16 0x00000800 + +/* audio format bit fields defines for devices and waveforms */ +#define AUDIO_FORMAT_8BITS 0x0000 +#define AUDIO_FORMAT_16BITS 0x0001 +#define AUDIO_FORMAT_LOOP 0x0010 +#define AUDIO_FORMAT_BIDILOOP 0x0020 +#define AUDIO_FORMAT_REVERSE 0x0080 +#define AUDIO_FORMAT_MONO 0x0000 +#define AUDIO_FORMAT_STEREO 0x0100 +#define AUDIO_FORMAT_FILTER 0x8000 + +/* audio resource limits defines */ +#define AUDIO_MAX_VOICES 32 +#define AUDIO_MAX_SAMPLES 16 +#define AUDIO_MAX_PATCHES 128 +#define AUDIO_MAX_PATTERNS 256 +#define AUDIO_MAX_ORDERS 256 +#define AUDIO_MAX_NOTES 96 +#define AUDIO_MAX_POINTS 12 +#define AUDIO_MIN_PERIOD 1 +#define AUDIO_MAX_PERIOD 31999 +#define AUDIO_MIN_VOLUME 0x00 +#define AUDIO_MAX_VOLUME 0x40 +#define AUDIO_MIN_PANNING 0x00 +#define AUDIO_MAX_PANNING 0xFF +#define AUDIO_MIN_POSITION 0x00000000L +#define AUDIO_MAX_POSITION 0x00100000L +#define AUDIO_MIN_FREQUENCY 0x00000200L +#define AUDIO_MAX_FREQUENCY 0x00080000L + +/* audio error code defines */ +#define AUDIO_ERROR_NONE 0x0000 +#define AUDIO_ERROR_INVALHANDLE 0x0001 +#define AUDIO_ERROR_INVALPARAM 0x0002 +#define AUDIO_ERROR_NOTSUPPORTED 0x0003 +#define AUDIO_ERROR_BADDEVICEID 0x0004 +#define AUDIO_ERROR_NODEVICE 0x0005 +#define AUDIO_ERROR_DEVICEBUSY 0x0006 +#define AUDIO_ERROR_BADFORMAT 0x0007 +#define AUDIO_ERROR_NOMEMORY 0x0008 +#define AUDIO_ERROR_NODRAMMEMORY 0x0009 +#define AUDIO_ERROR_FILENOTFOUND 0x000A +#define AUDIO_ERROR_BADFILEFORMAT 0x000B +#define AUDIO_LAST_ERROR 0x000B + +/* audio device identifiers */ +#define AUDIO_DEVICE_NONE 0x0000 +#define AUDIO_DEVICE_MAPPER 0xFFFF + +/* audio product identifiers */ +#define AUDIO_PRODUCT_NONE 0x0000 +#define AUDIO_PRODUCT_SB 0x0001 +#define AUDIO_PRODUCT_SB15 0x0002 +#define AUDIO_PRODUCT_SB20 0x0003 +#define AUDIO_PRODUCT_SBPRO 0x0004 +#define AUDIO_PRODUCT_SB16 0x0005 +#define AUDIO_PRODUCT_AWE32 0x0006 +#define AUDIO_PRODUCT_WSS 0x0007 +#define AUDIO_PRODUCT_ESS 0x0008 +#define AUDIO_PRODUCT_GUS 0x0009 +#define AUDIO_PRODUCT_GUSDB 0x000A +#define AUDIO_PRODUCT_GUSMAX 0x000B +#define AUDIO_PRODUCT_IWAVE 0x000C +#define AUDIO_PRODUCT_PAS 0x000D +#define AUDIO_PRODUCT_PAS16 0x000E +#define AUDIO_PRODUCT_ARIA 0x000F +#define AUDIO_PRODUCT_WINDOWS 0x0100 +#define AUDIO_PRODUCT_LINUX 0x0101 +#define AUDIO_PRODUCT_SPARC 0x0102 +#define AUDIO_PRODUCT_SGI 0x0103 +#define AUDIO_PRODUCT_DSOUND 0x0104 +#define AUDIO_PRODUCT_OS2MMPM 0x0105 +#define AUDIO_PRODUCT_OS2DART 0x0106 +#define AUDIO_PRODUCT_BEOSR3 0x0107 +#define AUDIO_PRODUCT_BEOS 0x0108 +#define AUDIO_PRODUCT_QNX 0x0109 + +/* audio mixer channels */ +#define AUDIO_MIXER_MASTER_VOLUME 0x0001 +#define AUDIO_MIXER_TREBLE 0x0002 +#define AUDIO_MIXER_BASS 0x0003 +#define AUDIO_MIXER_CHORUS 0x0004 +#define AUDIO_MIXER_REVERB 0x0005 + +/* audio envelope bit fields */ +#define AUDIO_ENVELOPE_ON 0x0001 +#define AUDIO_ENVELOPE_SUSTAIN 0x0002 +#define AUDIO_ENVELOPE_LOOP 0x0004 + +/* audio pattern bit fields */ +#define AUDIO_PATTERN_PACKED 0x0080 +#define AUDIO_PATTERN_NOTE 0x0001 +#define AUDIO_PATTERN_SAMPLE 0x0002 +#define AUDIO_PATTERN_VOLUME 0x0004 +#define AUDIO_PATTERN_COMMAND 0x0008 +#define AUDIO_PATTERN_PARAMS 0x0010 + +/* audio module bit fields */ +#define AUDIO_MODULE_AMIGA 0x0000 +#define AUDIO_MODULE_LINEAR 0x0001 +#define AUDIO_MODULE_PANNING 0x8000 + +#pragma pack(1) + +/* audio capabilities structure */ + typedef struct { + WORD wProductId; /* product identifier */ + CHAR szProductName[30]; /* product name */ + DWORD dwFormats; /* formats supported */ + } AUDIOCAPS, *LPAUDIOCAPS; + +/* audio format structure */ + typedef struct { + UINT nDeviceId; /* device identifier */ + WORD wFormat; /* playback format */ + WORD nSampleRate; /* sampling frequency */ + } AUDIOINFO, *LPAUDIOINFO; + +/* audio waveform structure */ + typedef struct { + LPBYTE lpData; /* data pointer */ + DWORD dwHandle; /* waveform handle */ + DWORD dwLength; /* waveform length */ + DWORD dwLoopStart; /* loop start point */ + DWORD dwLoopEnd; /* loop end point */ + WORD nSampleRate; /* sampling rate */ + WORD wFormat; /* format bits */ + } AUDIOWAVE, *LPAUDIOWAVE; + + +/* audio envelope point structure */ + typedef struct { + WORD nFrame; /* envelope frame */ + WORD nValue; /* envelope value */ + } AUDIOPOINT, *LPAUDIOPOINT; + +/* audio envelope structure */ + typedef struct { + AUDIOPOINT aEnvelope[AUDIO_MAX_POINTS]; /* envelope points */ + BYTE nPoints; /* number of points */ + BYTE nSustain; /* sustain point */ + BYTE nLoopStart; /* loop start point */ + BYTE nLoopEnd; /* loop end point */ + WORD wFlags; /* envelope flags */ + WORD nSpeed; /* envelope speed */ + } AUDIOENVELOPE, *LPAUDIOENVELOPE; + +/* audio sample structure */ + typedef struct { + CHAR szSampleName[32]; /* sample name */ + BYTE nVolume; /* default volume */ + BYTE nPanning; /* default panning */ + BYTE nRelativeNote; /* relative note */ + BYTE nFinetune; /* finetune */ + AUDIOWAVE Wave; /* waveform handle */ + } AUDIOSAMPLE, *LPAUDIOSAMPLE; + +/* audio patch structure */ + typedef struct { + CHAR szPatchName[32]; /* patch name */ + BYTE aSampleNumber[AUDIO_MAX_NOTES]; /* multi-sample table */ + WORD nSamples; /* number of samples */ + BYTE nVibratoType; /* vibrato type */ + BYTE nVibratoSweep; /* vibrato sweep */ + BYTE nVibratoDepth; /* vibrato depth */ + BYTE nVibratoRate; /* vibrato rate */ + WORD nVolumeFadeout; /* volume fadeout */ + AUDIOENVELOPE Volume; /* volume envelope */ + AUDIOENVELOPE Panning; /* panning envelope */ + LPAUDIOSAMPLE aSampleTable; /* sample table */ + } AUDIOPATCH, *LPAUDIOPATCH; + +/* audio pattern structure */ + typedef struct { + WORD nPacking; /* packing type */ + WORD nTracks; /* number of tracks */ + WORD nRows; /* number of rows */ + WORD nSize; /* data size */ + LPBYTE lpData; /* data pointer */ + } AUDIOPATTERN, *LPAUDIOPATTERN; + +/* audio module structure */ + typedef struct { + CHAR szModuleName[32]; /* module name */ + WORD wFlags; /* module flags */ + WORD nOrders; /* number of orders */ + WORD nRestart; /* restart position */ + WORD nTracks; /* number of tracks */ + WORD nPatterns; /* number of patterns */ + WORD nPatches; /* number of patches */ + WORD nTempo; /* initial tempo */ + WORD nBPM; /* initial BPM */ + BYTE aOrderTable[AUDIO_MAX_ORDERS]; /* order table */ + BYTE aPanningTable[AUDIO_MAX_VOICES]; /* panning table */ + LPAUDIOPATTERN aPatternTable; /* pattern table */ + LPAUDIOPATCH aPatchTable; /* patch table */ + } AUDIOMODULE, *LPAUDIOMODULE; + +/* audio music track structure */ + typedef struct { + BYTE nNote; /* note index */ + BYTE nPatch; /* patch number */ + BYTE nSample; /* sample number */ + BYTE nCommand; /* effect command */ + BYTE bParams; /* effect params */ + BYTE nVolumeCmd; /* volume command */ + BYTE nVolume; /* volume level */ + BYTE nPanning; /* stereo panning */ + LONG dwFrequency; /* note frequency */ + WORD wPeriod; /* note period */ + } AUDIOTRACK, *LPAUDIOTRACK; + +/* audio callback function defines */ + typedef VOID (AIAPI* LPFNAUDIOWAVE)(LPBYTE, UINT); + typedef VOID (AIAPI* LPFNAUDIOTIMER)(); + typedef VOID (AIAPI* LPFNAUDIOCALLBACK)(BYTE, UINT, UINT); + +/* audio handle defines */ + typedef HANDLE HAC; + typedef HAC* LPHAC; + +#pragma pack() + +/* audio interface API prototypes */ + UINT AIAPI AInitialize(); + UINT AIAPI AGetVersion(); + UINT AIAPI AGetAudioNumDevs(); + UINT AIAPI AGetAudioDevCaps(UINT nDeviceId, LPAUDIOCAPS lpCaps); + UINT AIAPI AGetErrorText(UINT nErrorCode, LPSTR lpText, UINT nSize); + + UINT AIAPI APingAudio(LPUINT lpnDeviceId); + UINT AIAPI AOpenAudio(LPAUDIOINFO lpInfo); + UINT AIAPI ACloseAudio(); + UINT AIAPI AUpdateAudio(); + UINT AIAPI AUpdateAudioEx(UINT nFrames); + + UINT AIAPI ASetAudioMixerValue(UINT nChannel, UINT nValue); + + UINT AIAPI AOpenVoices(UINT nVoices); + UINT AIAPI ACloseVoices(); + + UINT AIAPI ASetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave); + UINT AIAPI ASetAudioTimerProc(LPFNAUDIOTIMER lpfnAudioTimer); + UINT AIAPI ASetAudioTimerRate(UINT nTimerRate); + + LONG AIAPI AGetAudioDataAvail(); + UINT AIAPI ACreateAudioData(LPAUDIOWAVE lpWave); + UINT AIAPI ADestroyAudioData(LPAUDIOWAVE lpWave); + UINT AIAPI AWriteAudioData(LPAUDIOWAVE lpWave, DWORD dwOffset, UINT nCount); + + UINT AIAPI ACreateAudioVoice(LPHAC lphVoice); + UINT AIAPI ADestroyAudioVoice(HAC hVoice); + + UINT AIAPI APlayVoice(HAC hVoice, LPAUDIOWAVE lpWave); + UINT AIAPI APrimeVoice(HAC hVoice, LPAUDIOWAVE lpWave); + UINT AIAPI AStartVoice(HAC hVoice); + UINT AIAPI AStopVoice(HAC hVoice); + + UINT AIAPI ASetVoicePosition(HAC hVoice, LONG dwPosition); + UINT AIAPI ASetVoiceFrequency(HAC hVoice, LONG dwFrequency); + UINT AIAPI ASetVoiceVolume(HAC hVoice, UINT nVolume); + UINT AIAPI ASetVoicePanning(HAC hVoice, UINT nPanning); + + UINT AIAPI AGetVoicePosition(HAC hVoice, LPLONG lpdwPosition); + UINT AIAPI AGetVoiceFrequency(HAC hVoice, LPLONG lpdwFrequency); + UINT AIAPI AGetVoiceVolume(HAC hVoice, LPUINT lpnVolume); + UINT AIAPI AGetVoicePanning(HAC hVoice, LPUINT lpnPanning); + UINT AIAPI AGetVoiceStatus(HAC hVoice, LPBOOL lpnStatus); + + UINT AIAPI APlayModule(LPAUDIOMODULE lpModule); + UINT AIAPI AStopModule(); + UINT AIAPI APauseModule(); + UINT AIAPI AResumeModule(); + UINT AIAPI ASetModuleVolume(UINT nVolume); + UINT AIAPI ASetModulePosition(UINT nOrder, UINT nRow); + UINT AIAPI AGetModuleVolume(LPUINT lpnVolume); + UINT AIAPI AGetModulePosition(LPUINT pnOrder, LPUINT lpnRow); + UINT AIAPI AGetModuleStatus(LPBOOL lpnStatus); + UINT AIAPI ASetModuleCallback(LPFNAUDIOCALLBACK lpfnAudioCallback); + + UINT AIAPI ALoadModuleFile(LPSTR lpszFileName, + LPAUDIOMODULE* lplpModule, DWORD dwFileOffset); + UINT AIAPI AFreeModuleFile(LPAUDIOMODULE lpModule); + + UINT AIAPI ALoadWaveFile(LPSTR lpszFileName, + LPAUDIOWAVE* lplpWave, DWORD dwFileOffset); + UINT AIAPI AFreeWaveFile(LPAUDIOWAVE lpWave); + + UINT AIAPI AGetModuleTrack(UINT nTrack, LPAUDIOTRACK lpTrack); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/seal-hack/include/audio.pas b/seal-hack/include/audio.pas new file mode 100644 index 0000000..a8b8342 --- /dev/null +++ b/seal-hack/include/audio.pas @@ -0,0 +1,950 @@ +{* + * $Id: audio.h 1.16 1996/09/25 13:09:09 chasan released $ + * + * SEAL Synthetic Audio Library API Interface + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + *} + +unit Audio; + +interface +uses + SysUtils, Windows; + +const + { audio system version number } + AUDIO_SYSTEM_VERSION = $0101; + + { audio capabilities bit fields definitions } + AUDIO_FORMAT_1M08 = $00000001; + AUDIO_FORMAT_1S08 = $00000002; + AUDIO_FORMAT_1M16 = $00000004; + AUDIO_FORMAT_1S16 = $00000008; + AUDIO_FORMAT_2M08 = $00000010; + AUDIO_FORMAT_2S08 = $00000020; + AUDIO_FORMAT_2M16 = $00000040; + AUDIO_FORMAT_2S16 = $00000080; + AUDIO_FORMAT_4M08 = $00000100; + AUDIO_FORMAT_4S08 = $00000200; + AUDIO_FORMAT_4M16 = $00000400; + AUDIO_FORMAT_4S16 = $00000800; + + { audio format bit fields defines for devices and waveforms } + AUDIO_FORMAT_8BITS = $0000; + AUDIO_FORMAT_16BITS = $0001; + AUDIO_FORMAT_LOOP = $0010; + AUDIO_FORMAT_BIDILOOP = $0020; + AUDIO_FORMAT_REVERSE = $0080; + AUDIO_FORMAT_MONO = $0000; + AUDIO_FORMAT_STEREO = $0100; + AUDIO_FORMAT_FILTER = $8000; + + { audio resource limits defines } + AUDIO_MAX_VOICES = 32; + AUDIO_MAX_SAMPLES = 16; + AUDIO_MAX_PATCHES = 128; + AUDIO_MAX_PATTERNS = 256; + AUDIO_MAX_ORDERS = 256; + AUDIO_MAX_NOTES = 96; + AUDIO_MAX_POINTS = 12; + AUDIO_MIN_PERIOD = 1; + AUDIO_MAX_PERIOD = 31999; + AUDIO_MIN_VOLUME = $00; + AUDIO_MAX_VOLUME = $40; + AUDIO_MIN_PANNING = $00; + AUDIO_MAX_PANNING = $FF; + AUDIO_MIN_POSITION = $00000000; + AUDIO_MAX_POSITION = $00100000; + AUDIO_MIN_FREQUENCY = $00000200; + AUDIO_MAX_FREQUENCY = $00080000; + + { audio error code defines } + AUDIO_ERROR_NONE = $0000; + AUDIO_ERROR_INVALHANDLE = $0001; + AUDIO_ERROR_INVALPARAM = $0002; + AUDIO_ERROR_NOTSUPPORTED = $0003; + AUDIO_ERROR_BADDEVICEID = $0004; + AUDIO_ERROR_NODEVICE = $0005; + AUDIO_ERROR_DEVICEBUSY = $0006; + AUDIO_ERROR_BADFORMAT = $0007; + AUDIO_ERROR_NOMEMORY = $0008; + AUDIO_ERROR_NODRAMMEMORY = $0009; + AUDIO_ERROR_FILENOTFOUND = $000A; + AUDIO_ERROR_BADFILEFORMAT = $000B; + AUDIO_LAST_ERROR = $000B; + + { audio device identifiers } + AUDIO_DEVICE_NONE = $0000; + AUDIO_DEVICE_MAPPER = $FFFF; + + { audio product identifiers } + AUDIO_PRODUCT_NONE = $0000; + AUDIO_PRODUCT_SB = $0001; + AUDIO_PRODUCT_SB15 = $0002; + AUDIO_PRODUCT_SB20 = $0003; + AUDIO_PRODUCT_SBPRO = $0004; + AUDIO_PRODUCT_SB16 = $0005; + AUDIO_PRODUCT_AWE32 = $0006; + AUDIO_PRODUCT_WSS = $0007; + AUDIO_PRODUCT_ESS = $0008; + AUDIO_PRODUCT_GUS = $0009; + AUDIO_PRODUCT_GUSDB = $000A; + AUDIO_PRODUCT_GUSMAX = $000B; + AUDIO_PRODUCT_IWAVE = $000C; + AUDIO_PRODUCT_PAS = $000D; + AUDIO_PRODUCT_PAS16 = $000E; + AUDIO_PRODUCT_ARIA = $000F; + AUDIO_PRODUCT_WINDOWS = $0100; + AUDIO_PRODUCT_LINUX = $0101; + AUDIO_PRODUCT_SPARC = $0102; + AUDIO_PRODUCT_SGI = $0103; + AUDIO_PRODUCT_DSOUND = $0104; + + { audio envelope bit fields } + AUDIO_ENVELOPE_ON = $0001; + AUDIO_ENVELOPE_SUSTAIN = $0002; + AUDIO_ENVELOPE_LOOP = $0004; + + { audio pattern bit fields } + AUDIO_PATTERN_PACKED = $0080; + AUDIO_PATTERN_NOTE = $0001; + AUDIO_PATTERN_SAMPLE = $0002; + AUDIO_PATTERN_VOLUME = $0004; + AUDIO_PATTERN_COMMAND = $0008; + AUDIO_PATTERN_PARAMS = $0010; + + { audio module bit fields } + AUDIO_MODULE_AMIGA = $0000; + AUDIO_MODULE_LINEAR = $0001; + AUDIO_MODULE_PANNING = $8000; + +type + { audio capabilities structure } + PAudioCaps = ^TAudioCaps; + TAudioCaps = record + wProductId : Word; { product identifier } + szProductName : Array [0..29] of Char; { product name } + dwFormats : Longint; { formats supported } + end; + + { audio format structure } + PAudioInfo = ^TAudioInfo; + TAudioInfo = record + nDeviceId : Integer; { device identifier } + wFormat : Word; { playback format } + nSampleRate : Word; { sampling rate } + end; + + { audio waveform structure } + PAudioWave = ^TAudioWave; + TAudioWave = record + pData : Pointer; { data pointer } + dwHandle : Longint; { waveform handle } + dwLength : Longint; { waveform length } + dwLoopStart : Longint; { loop start point } + dwLoopEnd : Longint; { loop end point } + nSampleRate : Word; { sampling rate } + wFormat : Word; { format bits } + end; + + + { audio envelope point structure } + PAudioPoint = ^TAudioPoint; + TAudioPoint = record + nFrame : Word; { envelope frame } + nValue : Word; { envelope value } + end; + + { audio envelope structure } + PAudioEnvelope = ^TAudioEnvelope; + TAudioEnvelope = record + aEnvelope : Array [1..AUDIO_MAX_POINTS] of TAudioPoint; { envelope points } + nPoints : Byte; { number of points } + nSustain : Byte; { sustain point } + nLoopStart : Byte; { loop start point } + nLoopEnd : Byte; { loop end point } + wFlags : Word; { envelope flags } + nSpeed : Word; { envelope speed } + end; + + { audio sample structure } + PAudioSample = ^TAudioSample; + TAudioSample = record + szSampleName : Array [0..31] of Char; { sample name } + nVolume : Byte; { default volume } + nPanning : Byte; { default panning } + nRelativeNote : Byte; { relative note } + nFinetune : Byte; { finetune } + Wave : TAudioWave; { waveform handle } + end; + + { audio patch structure } + PAudioPatch = ^TAudioPatch; + TAudioPatch = record + szPatchName : Array [0..31] of Char; { patch name } + aSampleNumber : Array [1..AUDIO_MAX_NOTES] of Byte; { multi-sample table } + nSamples : Word; { number of samples } + nVibratoType : Byte; { vibrato type } + nVibratoSweep : Byte; { vibrato sweep } + nVibratoDepth : Byte; { vibrato depth } + nVibratoRate : Byte; { vibrato rate } + nVolumeFadeout : Word; { volume fadeout } + Volume : TAudioEnvelope; { volume envelope } + Panning : TAudioEnvelope; { panning envelope } + aSampleTable : PAudioSample; { sample table } + end; + + { audio pattern structure } + PAudioPattern = ^TAudioPattern; + TAudioPattern = record + nPacking : Word; { packing type } + nTracks : Word; { number of tracks } + nRows : Word; { number of rows } + nSize : Word; { data size } + pData : Pointer; { data pointer } + end; + + { audio module structure } + PAudioModule = ^TAudioModule; + TAudioModule = record + szModuleName : Array [0..31] of Char; { module name } + wFlags : Word; { module flags } + nOrders : Word; { number of orders } + nRestart : Word; { restart position } + nTracks : Word; { number of tracks } + nPatterns : Word; { number of patterns } + nPatches : Word; { number of patches } + nTempo : Word; { initial tempo } + nBPM : Word; { initial BPM } + aOrderTable : Array [1..AUDIO_MAX_ORDERS] of Byte; { order table } + aPanningTable : Array [1..AUDIO_MAX_VOICES] of Byte; { panning table } + aPatternTable : PAudioPattern; { pattern table } + aPatchTable : PAudioPatch; { patch table } + end; + + { audio callback function defines } + TAudioWaveProc = procedure (pData: Pointer; nCount: Integer); stdcall; + TAudioTimerProc = procedure; stdcall; + TAudioCallback = procedure(nSyncMark: Byte; nOrder, nRow: Integer); stdcall; + + { audio handle defines } + PHAC = ^HAC; + HAC = Integer; + + +{ audio interface API prototypes } +function AInitialize: Integer; stdcall; +function AGetVersion: Integer; stdcall; +function AGetAudioNumDevs: Integer; stdcall; +function AGetAudioDevCaps(nDeviceId: Integer; var pCaps: TAudioCaps): Integer; stdcall; +function AGetErrorText(nErrorCode: Integer; pText: PChar; nSize: Integer): Integer; stdcall; + +function APingAudio(var pnDeviceId: Integer): Integer; stdcall; +function AOpenAudio(var pInfo: TAudioInfo): Integer; stdcall; +function ACloseAudio: Integer; stdcall; +function AUpdateAudio: Integer; stdcall; + +function AOpenVoices(nVoices: Integer): Integer; stdcall; +function ACloseVoices: Integer; stdcall; + +function ASetAudioCallback(pfnWaveProc: TAudioWaveProc): Integer; stdcall; +function ASetAudioTimerProc(pfnTimerProc: TAudioTimerProc): Integer; stdcall; +function ASetAudioTimerRate(nTimerRate: Integer): Integer; stdcall; + +function AGetAudioDataAvail: Longint; stdcall; +function ACreateAudioData(pWave: PAudioWave): Integer; stdcall; +function ADestroyAudioData(pWave: PAudioWave): Integer; stdcall; +function AWriteAudioData(pWave: PAudioWave; dwOffset: Longint; nCount: Integer): Integer; stdcall; + +function ACreateAudioVoice(var phVoice: HAC): Integer; stdcall; +function ADestroyAudioVoice(hVoice: HAC): Integer; stdcall; + +function APlayVoice(hVoice: HAC; pWave: PAudioWave): Integer; stdcall; +function APrimeVoice(hVoice: HAC; pWave: PAudioWave): Integer; stdcall; +function AStartVoice(hVoice: HAC): Integer; stdcall; +function AStopVoice(hVoice: HAC): Integer; stdcall; + +function ASetVoicePosition(hVoice: HAC; dwPosition: Longint): Integer; stdcall; +function ASetVoiceFrequency(hVoice: HAC; dwFrequency: Longint): Integer; stdcall; +function ASetVoiceVolume(hVoice: HAC; nVolume: Integer): Integer; stdcall; +function ASetVoicePanning(hVoice: HAC; nPanning: Integer): Integer; stdcall; + +function AGetVoicePosition(hVoice: HAC; var pdwPosition: Longint): Integer; stdcall; +function AGetVoiceFrequency(hVoice: HAC; var pdwFrequency: Longint): Integer; stdcall; +function AGetVoiceVolume(hVoice: HAC; var pnVolume: Integer): Integer; stdcall; +function AGetVoicePanning(hVoice: HAC; var pnPanning: Integer): Integer; stdcall; +function AGetVoiceStatus(hVoice: HAC; var pnStatus: Integer): Integer; stdcall; + +function APlayModule(pModule: PAudioModule): Integer; stdcall; +function AStopModule: Integer; stdcall; +function APauseModule: Integer; stdcall; +function AResumeModule: Integer; stdcall; +function ASetModuleVolume(nVolume: Integer): Integer; stdcall; +function ASetModulePosition(nOrder, nRow: Integer): Integer; stdcall; +function AGetModuleVolume(var pnVolume: Integer): Integer; stdcall; +function AGetModulePosition(var pnOrder, pnRow: Integer): Integer; stdcall; +function AGetModuleStatus(var pnStatus: Integer): Integer; stdcall; +function ASetModuleCallback(pfnAudioCallback: TAudioCallback): Integer; stdcall; + +function ALoadModuleFile(pszFileName: PChar; var ppModule: PAudioModule; FileOffset: Longint): Integer; stdcall; +function AFreeModuleFile(pModule: PAudioModule): Integer; stdcall; + +function ALoadWaveFile(pszFileName: PChar; var ppWave: PAudioWave; FileOffset: Longint): Integer; stdcall; +function AFreeWaveFile(pWave: PAudioWave): Integer; stdcall; + + +type + TAudio = class(TObject) + constructor Create(Format: Word; SampleRate: Word); + destructor Destroy; override; + procedure Update; + private + FInfo: TAudioInfo; + function GetProductId: Integer; + function GetProductName: String; + public + property DeviceId: Integer read FInfo.nDeviceId; + property ProductId: Integer read GetProductId; + property ProductName: String read GetProductName; + property Format: Word read FInfo.wFormat; + property SampleRate: Word read FInfo.nSampleRate; + end; + + TWaveform = class(TObject) + constructor Create(Format: Word; SampleRate: Word; + Length, LoopStart, LoopEnd: Longint); + constructor LoadFromFile(FileName: String); + destructor Destroy; override; + procedure Write(var Buffer; Count: Integer); + private + FHandle: TAudioWave; + PHandle: PAudioWave; + FVolume: Integer; + FPanning: Integer; + FPosition: Longint; + function GetHandle: PAudioWave; + procedure SetSampleRate(Value: Word); + procedure SetVolume(Value: Integer); + procedure SetPanning(Value: Integer); + procedure SetPosition(Value: LongInt); + public + property Handle: PAudioWave read GetHandle; + property Format: Word read FHandle.wFormat; + property Length: Longint read FHandle.dwLength; + property LoopStart: Longint read FHandle.dwLoopStart; + property LoopEnd: Longint read FHandle.dwLoopEnd; + property SampleRate: Word read FHandle.nSampleRate write SetSampleRate; + property Volume: Integer read FVolume write SetVolume; + property Panning: Integer read FPanning write SetPanning; + property Position: Longint read FPosition write SetPosition; + end; + + TVoice = class(TObject) + constructor Create; + destructor Destroy; override; + procedure Prime(Wave: TWaveform); + procedure Play(Wave: TWaveform); + procedure Start; + procedure Stop; + private + FHandle: HAC; + FWave: TWaveform; + function GetHandle: HAC; + function GetWaveform: TWaveform; + function GetPosition: Longint; + procedure SetPosition(Value: Longint); + function GetFrequency: Longint; + procedure SetFrequency(Value: Longint); + function GetVolume: Integer; + procedure SetVolume(Value: Integer); + function GetPanning: Integer; + procedure SetPanning(Value: Integer); + function GetStopped: Boolean; + public + property Handle: HAC read GetHandle; + property Waveform: TWaveform read GetWaveform; + property Position: Longint read GetPosition write SetPosition; + property Frequency: Longint read GetFrequency write SetFrequency; + property Volume: Integer read GetVolume write SetVolume; + property Panning: Integer read GetPanning write SetPanning; + property Stopped: Boolean read GetStopped; + end; + + TModule = class(TObject) + constructor LoadFromFile(FileName: String); + destructor Destroy; override; + procedure Play; + procedure Stop; + procedure Pause; + procedure Resume; + private + FHandle: PAudioModule; + FCallback: TAudioCallback; + function GetVolume: Integer; + procedure SetVolume(Value: Integer); + function GetOrder: Integer; + procedure SetOrder(Value: Integer); + function GetRow: Integer; + procedure SetRow(Value: Integer); + function GetStopped: Boolean; + procedure SetCallback(Value: TAudioCallback); + public + property Handle: PAudioModule read FHandle; + property Volume: Integer read GetVolume write SetVolume; + property Order: Integer read GetOrder write SetOrder; + property Row: Integer read GetRow write SetRow; + property Stopped: Boolean read GetStopped; + property OnSync: TAudioCallback read FCallback write SetCallback; + private + function GetName: String; + function GetNumOrders: Integer; + function GetNumTracks: Integer; + function GetNumPatterns: Integer; + function GetNumPatches: Integer; + function GetPatch(Index: Integer): PAudioPatch; + public + property Name: String read GetName; + property NumOrders: Integer read GetNumOrders; + property NumTracks: Integer read GetNumTracks; + property NumPatterns: Integer read GetNumPatterns; + property NumPatches: Integer read GetNumPatches; + property Patch[Index: Integer]: PAudioPatch read GetPatch; + end; + + +implementation + +function AInitialize: Integer; stdcall; external 'AUDIOW32.DLL'; +function AGetVersion: Integer; stdcall; external 'AUDIOW32.DLL'; +function AGetAudioNumDevs: Integer; stdcall; external 'AUDIOW32.DLL'; +function AGetAudioDevCaps(nDeviceId: Integer; var pCaps: TAudioCaps): Integer; stdcall; external 'AUDIOW32.DLL'; +function AGetErrorText(nErrorCode: Integer; pText: PChar; nSize: Integer): Integer; stdcall; external 'AUDIOW32.DLL'; + +function APingAudio(var pnDeviceId: Integer): Integer; stdcall; external 'AUDIOW32.DLL'; +function AOpenAudio(var pInfo: TAudioInfo): Integer; stdcall; external 'AUDIOW32.DLL'; +function ACloseAudio: Integer; stdcall; external 'AUDIOW32.DLL'; +function AUpdateAudio: Integer; stdcall; external 'AUDIOW32.DLL'; + +function AOpenVoices(nVoices: Integer): Integer; stdcall; external 'AUDIOW32.DLL'; +function ACloseVoices: Integer; stdcall; external 'AUDIOW32.DLL'; + +function ASetAudioCallback(pfnWaveProc: TAudioWaveProc): Integer; stdcall; external 'AUDIOW32.DLL'; +function ASetAudioTimerProc(pfnTimerProc: TAudioTimerProc): Integer; stdcall; external 'AUDIOW32.DLL'; +function ASetAudioTimerRate(nTimerRate: Integer): Integer; stdcall; external 'AUDIOW32.DLL'; + +function AGetAudioDataAvail: Longint; stdcall; external 'AUDIOW32.DLL'; +function ACreateAudioData(pWave: PAudioWave): Integer; stdcall; external 'AUDIOW32.DLL'; +function ADestroyAudioData(pWave: PAudioWave): Integer; stdcall; external 'AUDIOW32.DLL'; +function AWriteAudioData(pWave: PAudioWave; dwOffset: Longint; nCount: Integer): Integer; stdcall; external 'AUDIOW32.DLL'; + +function ACreateAudioVoice(var phVoice: HAC): Integer; stdcall; external 'AUDIOW32.DLL'; +function ADestroyAudioVoice(hVoice: HAC): Integer; stdcall; external 'AUDIOW32.DLL'; + +function APlayVoice(hVoice: HAC; pWave: PAudioWave): Integer; stdcall; external 'AUDIOW32.DLL'; +function APrimeVoice(hVoice: HAC; pWave: PAudioWave): Integer; stdcall; external 'AUDIOW32.DLL'; +function AStartVoice(hVoice: HAC): Integer; stdcall; external 'AUDIOW32.DLL'; +function AStopVoice(hVoice: HAC): Integer; stdcall; external 'AUDIOW32.DLL'; + +function ASetVoicePosition(hVoice: HAC; dwPosition: Longint): Integer; stdcall; external 'AUDIOW32.DLL'; +function ASetVoiceFrequency(hVoice: HAC; dwFrequency: Longint): Integer; stdcall; external 'AUDIOW32.DLL'; +function ASetVoiceVolume(hVoice: HAC; nVolume: Integer): Integer; stdcall; external 'AUDIOW32.DLL'; +function ASetVoicePanning(hVoice: HAC; nPanning: Integer): Integer; stdcall; external 'AUDIOW32.DLL'; + +function AGetVoicePosition(hVoice: HAC; var pdwPosition: Longint): Integer; stdcall; external 'AUDIOW32.DLL'; +function AGetVoiceFrequency(hVoice: HAC; var pdwFrequency: Longint): Integer; stdcall; external 'AUDIOW32.DLL'; +function AGetVoiceVolume(hVoice: HAC; var pnVolume: Integer): Integer; stdcall; external 'AUDIOW32.DLL'; +function AGetVoicePanning(hVoice: HAC; var pnPanning: Integer): Integer; stdcall; external 'AUDIOW32.DLL'; +function AGetVoiceStatus(hVoice: HAC; var pnStatus: Integer): Integer; stdcall; external 'AUDIOW32.DLL'; + +function APlayModule(pModule: PAudioModule): Integer; stdcall; external 'AUDIOW32.DLL'; +function AStopModule: Integer; stdcall; external 'AUDIOW32.DLL'; +function APauseModule: Integer; stdcall; external 'AUDIOW32.DLL'; +function AResumeModule: Integer; stdcall; external 'AUDIOW32.DLL'; +function ASetModuleVolume(nVolume: Integer): Integer; stdcall; external 'AUDIOW32.DLL'; +function ASetModulePosition(nOrder, nRow: Integer): Integer; stdcall; external 'AUDIOW32.DLL'; +function AGetModuleVolume(var pnVolume: Integer): Integer; stdcall; external 'AUDIOW32.DLL'; +function AGetModulePosition(var pnOrder, pnRow: Integer): Integer; stdcall; external 'AUDIOW32.DLL'; +function AGetModuleStatus(var pnStatus: Integer): Integer; stdcall; external 'AUDIOW32.DLL'; +function ASetModuleCallback(pfnAudioCallback: TAudioCallback): Integer; stdcall; external 'AUDIOW32.DLL'; + +function ALoadModuleFile(pszFileName: PChar; var ppModule: PAudioModule; FileOffset: Longint): Integer; stdcall; external 'AUDIOW32.DLL'; +function AFreeModuleFile(pModule: PAudioModule): Integer; stdcall; external 'AUDIOW32.DLL'; + +function ALoadWaveFile(pszFileName: PChar; var ppWave: PAudioWave; FileOffset: Longint): Integer; stdcall; external 'AUDIOW32.DLL'; +function AFreeWaveFile(pWave: PAudioWave): Integer; stdcall; external 'AUDIOW32.DLL'; + + +const + Semaphore: LongBool = False; + PlayingModule: PAudioModule = nil; + +function SetPlayingModule(Value: PAudioModule): Boolean; pascal; assembler; +asm + mov eax,True + xchg eax,Semaphore + cmp eax,False + jne @@1 + mov eax,PlayingModule + test eax,eax + jne @@0 + mov eax,Value + mov PlayingModule,eax +@@0: + mov Semaphore,False +@@1: + push edx + xor eax,eax + mov edx,PlayingModule + cmp edx,Value + sete al + pop edx +end; + +procedure Assert(Header: String; ErrorCode: Integer); +var + szText: Array [0..255] of Char; +begin + if ErrorCode <> AUDIO_ERROR_NONE then + begin + AGetErrorText(ErrorCode, szText, sizeof(szText) - 1); + raise Exception.Create(Header + ': ' + StrPas(szText)); + end; +end; + + +{ TAudio } +constructor TAudio.Create(Format: Word; SampleRate: Word); +begin + inherited Create; + FInfo.nDeviceId := AUDIO_DEVICE_MAPPER; + FInfo.wFormat := Format; + FInfo.nSampleRate := SampleRate; + Assert('AOpenAudio', AOpenAudio(FInfo)); + Assert('AOpenVoices', AOpenVoices(32)); +end; + +destructor TAudio.Destroy; +begin + Assert('ACloseVoices', ACloseVoices); + Assert('ACloseAudio', ACloseAudio); + inherited Destroy; +end; + +procedure TAudio.Update; +begin + Assert('AUpdateAudio', AUpdateAudio); +end; + +function TAudio.GetProductId: Integer; +var + Caps: TAudioCaps; +begin + Assert('AGetAudioDevCaps', AGetAudioDevCaps(FInfo.nDeviceId, Caps)); + Result := Caps.wProductId; +end; + +function TAudio.GetProductName: String; +var + Caps: TAudioCaps; +begin + Assert('AGetAudioDevCaps', AGetAudioDevCaps(FInfo.nDeviceId, Caps)); + Result := StrPas(Caps.szProductName); +end; + + +{ TWaveform } +constructor TWaveform.Create(Format: Word; SampleRate: Word; + Length, LoopStart, LoopEnd: Longint); +begin + inherited Create; + FPosition := 0; + FVolume := 64; + FPanning := 128; + FHandle.wFormat := Format; + FHandle.dwLength := Length; + FHandle.dwLoopStart := LoopStart; + FHandle.dwLoopEnd := LoopEnd; + FHandle.nSampleRate := SampleRate; + PHandle := nil; + Assert('ACreateAudioData', ACreateAudioData(@FHandle)); +end; + +constructor TWaveform.LoadFromFile(FileName: String); +var + szFileName: Array [0..255] of Char; +begin + inherited Create; + FPosition := 0; + FVolume := 64; + FPanning := 128; + FHandle.pData := nil; + FHandle.wFormat := AUDIO_FORMAT_8BITS or AUDIO_FORMAT_MONO; + FHandle.dwLength := 0; + FHandle.dwLoopStart := 0; + FHandle.dwLoopEnd := 0; + FHandle.nSampleRate := 22050; + Assert('ALoadWaveFile', ALoadWaveFile(StrPCopy(szFileName, FileName), PHandle, 0)); + if Assigned(PHandle) then + FHandle := PHandle^; +end; + +destructor TWaveform.Destroy; +begin + if Assigned(PHandle) then + begin + Assert('AFreeWaveFile', AFreeWaveFile(PHandle)); + end + else if Assigned(FHandle.pData) then + begin + Assert('ADestroyAudioData', ADestroyAudioData(@FHandle)); + end; + inherited Destroy; +end; + +procedure TWaveform.Write(var Buffer; Count: Integer); +var + Size: Integer; +begin + if Assigned(FHandle.pData) then + begin + while (Count > 0) and (FHandle.dwLength > 0) do + begin + Size := Count; + if FPosition + Size > FHandle.dwLength then + Size := FHandle.dwLength - FPosition; + Move(Buffer, PChar(FHandle.pData)[FPosition], Size); + Assert('AWriteAudioData', AWriteAudioData(@FHandle, FPosition, Size)); + Inc(FPosition, Size); + if FPosition >= FHandle.dwLength then + Dec(FPosition, FHandle.dwLength); + Dec(Count, Size); + end; + end; +end; + +function TWaveform.GetHandle: PAudioWave; +begin + Result := @FHandle; +end; + +procedure TWaveform.SetSampleRate(Value: Word); +begin + if (Value >= AUDIO_MIN_FREQUENCY) and (Value <= AUDIO_MAX_FREQUENCY) then + FHandle.nSampleRate := Value; +end; + +procedure TWaveform.SetVolume(Value: Integer); +begin + if (Value >= AUDIO_MIN_VOLUME) and (Value <= AUDIO_MAX_VOLUME) then + FVolume := Value; +end; + +procedure TWaveform.SetPanning(Value: Integer); +begin + if (Value >= AUDIO_MIN_PANNING) and (Value <= AUDIO_MAX_PANNING) then + FPanning := Value; +end; + +procedure TWaveform.SetPosition(Value: LongInt); +begin + if (Value >= 0) and (Value < FHandle.dwLength) then + FPosition := Value; +end; + + +{ TVoice} +constructor TVoice.Create; +begin + inherited Create; + FWave := nil; + Assert('ACreateAudioVoice', ACreateAudioVoice(FHandle)); +end; + +destructor TVoice.Destroy; +begin + if FHandle <> 0 then + Assert('ADestroyAudioVoice', ADestroyAudioVoice(FHandle)); + inherited Destroy; +end; + +procedure TVoice.Prime(Wave: TWaveform); +begin + if Assigned(Wave) then + begin + FWave := Wave; + Assert('APrimeVoice', APrimeVoice(FHandle, FWave.Handle)); + Assert('ASetVoiceFrequency', ASetVoiceFrequency(FHandle, FWave.SampleRate)); + Assert('ASetVoiceVolume', ASetVoiceVolume(FHandle, FWave.Volume)); + Assert('ASetVoicePanning', ASetVoicePanning(FHandle, FWave.Panning)); + end; +end; + +procedure TVoice.Play(Wave: TWaveform); +begin + if Assigned(Wave) then + begin + FWave := Wave; + Assert('APrimeVoice', APrimeVoice(FHandle, FWave.Handle)); + Assert('ASetVoiceFrequency', ASetVoiceFrequency(FHandle, FWave.SampleRate)); + Assert('ASetVoiceVolume', ASetVoiceVolume(FHandle, FWave.Volume)); + Assert('ASetVoicePanning', ASetVoicePanning(FHandle, FWave.Panning)); + Assert('AStartVoice', AStartVoice(FHandle)); + end; +end; + +procedure TVoice.Start; +begin + Assert('AStartVoice', AStartVoice(FHandle)); +end; + +procedure TVoice.Stop; +begin + Assert('AStopVoice', AStopVoice(FHandle)); +end; + +function TVoice.GetHandle: HAC; +begin + Result := FHandle; +end; + +function TVoice.GetWaveform: TWaveform; +begin + Result := FWave; +end; + +function TVoice.GetPosition: Longint; +var + Value: Longint; +begin + Assert('AGetVoicePosition', AGetVoicePosition(FHandle, Value)); + Result := Value; +end; + +procedure TVoice.SetPosition(Value: Longint); +begin + Assert('ASetVoicePosition', ASetVoicePosition(FHandle, Value)); +end; + +function TVoice.GetFrequency: Longint; +var + Value: Longint; +begin + Assert('AGetVoiceFrequency', AGetVoiceFrequency(FHandle, Value)); + Result := Value; +end; + +procedure TVoice.SetFrequency(Value: Longint); +begin + Assert('ASetVoiceFrequency', ASetVoiceFrequency(FHandle, Value)); +end; + +function TVoice.GetVolume: Integer; +var + Value: Integer; +begin + Assert('AGetVoiceVolume', AGetVoiceVolume(FHandle, Value)); + Result := Value; +end; + +procedure TVoice.SetVolume(Value: Integer); +begin + Assert('ASetVoiceVolume', ASetVoiceVolume(FHandle, Value)); +end; + +function TVoice.GetPanning: Integer; +var + Value: Integer; +begin + Assert('AGetVoicePanning', AGetVoicePanning(FHandle, Value)); + Result := Value; +end; + +procedure TVoice.SetPanning(Value: Integer); +begin + Assert('ASetVoicePanning', ASetVoicePanning(FHandle, Value)); +end; + +function TVoice.GetStopped: Boolean; +var + Value: Integer; +begin + Assert('AGetVoiceStatus', AGetVoiceStatus(FHandle, Value)); + Result := Value <> 0; +end; + + +{ TModule } +constructor TModule.LoadFromFile(FileName: String); +var + szFileName: Array [0..255] of Char; +begin + inherited Create; + FHandle := nil; + FCallback := nil; + Assert('ALoadModuleFile', ALoadModuleFile(StrPCopy(szFileName, FileName), FHandle, 0)); +end; + +destructor TModule.Destroy; +begin + if Assigned(FHandle) then + begin + if not Stopped then Stop; + Assert('AFreeModuleFile', AFreeModuleFile(FHandle)); + end; + inherited Destroy; +end; + +procedure TModule.Play; +begin + if Assigned(FHandle) and SetPlayingModule(FHandle) then + Assert('APlayModule', APlayModule(FHandle)); +end; + +procedure TModule.Stop; +begin + if Assigned(FHandle) and (PlayingModule = FHandle) then + begin + Assert('AStopModule', AStopModule); + PlayingModule := nil; + end; +end; + +procedure TModule.Pause; +begin + if Assigned(FHandle) and (PlayingModule = FHandle) then + Assert('APauseModule', APauseModule); +end; + +procedure TModule.Resume; +begin + if Assigned(FHandle) and (PlayingModule = FHandle) then + Assert('AResumeModule', AResumeModule); +end; + +function TModule.GetVolume: Integer; +var + Value: Integer; +begin + Result := 0; + if Assigned(FHandle) and (PlayingModule = FHandle) then + begin + Assert('AGetModuleVolume', AGetModuleVolume(Value)); + Result := Value; + end; +end; + +procedure TModule.SetVolume(Value: Integer); +begin + if Assigned(FHandle) and (PlayingModule = FHandle) then + Assert('ASetModuleVolume', ASetModuleVolume(Value)); +end; + +function TModule.GetOrder: Integer; +var + Order, Row: Integer; +begin + Result := 0; + if Assigned(FHandle) and (PlayingModule = FHandle) then + begin + Assert('AGetModulePosition', AGetModulePosition(Order, Row)); + Result := Order; + end; +end; + +procedure TModule.SetOrder(Value: Integer); +begin + if Assigned(FHandle) and (PlayingModule = FHandle) then + Assert('ASetModulePosition', ASetModulePosition(Value, Row)); +end; + +function TModule.GetRow: Integer; +var + Order, Row: Integer; +begin + Result := 0; + if Assigned(FHandle) and (PlayingModule = FHandle) then + begin + Assert('AGetModulePosition', AGetModulePosition(Order, Row)); + Result := Row; + end; +end; + +procedure TModule.SetRow(Value: Integer); +begin + if Assigned(FHandle) and (PlayingModule = FHandle) then + Assert('ASetModulePosition', ASetModulePosition(Order, Value)); +end; + +function TModule.GetStopped: Boolean; +var + Value: Integer; +begin + Result := True; + if Assigned(FHandle) and (PlayingModule = FHandle) then + begin + Assert('AGetModuleStatus', AGetModuleStatus(Value)); + Result := Value <> 0; + end; +end; + +procedure TModule.SetCallback(Value: TAudioCallback); +begin + if Assigned(FHandle) and (PlayingModule = FHandle) then + begin + FCallback := Value; + Assert('ASetModuleCallback', ASetModuleCallback(Value)); + end; +end; + +function TModule.GetName: String; +begin + Result := ''; + if Assigned(FHandle) then + Result := StrPas(FHandle^.szModuleName); +end; + +function TModule.GetNumOrders: Integer; +begin + Result := 0; + if Assigned(FHandle) then + Result := FHandle^.nOrders; +end; + +function TModule.GetNumTracks: Integer; +begin + Result := 0; + if Assigned(FHandle) then + Result := FHandle^.nTracks; +end; + +function TModule.GetNumPatterns: Integer; +begin + Result := 0; + if Assigned(FHandle) then + Result := FHandle^.nPatterns; +end; + +function TModule.GetNumPatches: Integer; +begin + Result := 0; + if Assigned(FHandle) then + Result := FHandle^.nPatches; +end; + +function TModule.GetPatch(Index: Integer): PAudioPatch; +begin + Result := nil; + if Assigned(FHandle) then + begin + if (Index >= 1) and (Index <= FHandle^.nPatches) then + Result := PAudioPatch(@PChar(FHandle^.aPatchTable)[sizeof(TAudioPatch) * Pred(Index)]); + end; +end; + +end. diff --git a/seal-hack/lib/MacOSX/libaudio.a b/seal-hack/lib/MacOSX/libaudio.a new file mode 100644 index 0000000..715a317 Binary files /dev/null and b/seal-hack/lib/MacOSX/libaudio.a differ diff --git a/seal-hack/lib/SDL/libaudio.a b/seal-hack/lib/SDL/libaudio.a new file mode 100644 index 0000000..53b89d8 Binary files /dev/null and b/seal-hack/lib/SDL/libaudio.a differ diff --git a/seal-hack/src/BeOS/Makefile b/seal-hack/src/BeOS/Makefile new file mode 100644 index 0000000..f7dd05c --- /dev/null +++ b/seal-hack/src/BeOS/Makefile @@ -0,0 +1,36 @@ +# Makefile for BeOS Release 4 operating systems + +CC = gcc +AR = ar +AS = nasm +CFLAGS = -c -O3 -Wall -Wno-multichar -D__ASM__ -D__FLAT__ +ARFLAGS = cr +LIBS = -L../lib/BeOS/ -laudio -lroot -lbe -lmedia + +OBJS = audio.o wavfile.o xmfile.o s3mfile.o modfile.o mtmfile.o \ + iofile.o modeng.o nondrv.o mixdrv.o _mixdrv.o be3drv.o bedrv.o + +LIB = ../lib/BeOS/libaudio.a + +all : mp clean + @echo done. + +mp : mp.o $(LIB) + $(CC) -o mp mp.o $(LIBS) + +$(LIB) : $(OBJS) + $(AR) $(ARFLAGS) $(LIB) $(OBJS) + +.SUFFIXES: .c .cpp .h .obj + +.c.o: + $(CC) $(CFLAGS) $< + +.cpp.o: + $(CC) $(CFLAGS) $< + +.asm.o: + $(AS) $< + +clean : + @rm -rf *.o diff --git a/seal-hack/src/BeOS/audio_driver.h b/seal-hack/src/BeOS/audio_driver.h new file mode 100644 index 0000000..37b1154 --- /dev/null +++ b/seal-hack/src/BeOS/audio_driver.h @@ -0,0 +1,45 @@ +/* audio_driver.h */ +/* Jon Watte 19971223 */ +/* Interface to drivers found in /dev/audio */ +/* Devices found in /dev/old follow a different API! */ + +#if !defined(_AUDIO_DRIVER_H) +#define _AUDIO_DRIVER_H + +#if !defined(_SUPPORT_DEFS_H) +#include +#endif /* _SUPPORT_DEFS_H */ +#if !defined(_DRIVERS_H) +#include +#endif /* _DRIVERS_H */ + +enum { + /* arg = ptr to struct audio_format */ + B_AUDIO_GET_AUDIO_FORMAT = B_AUDIO_DRIVER_BASE, + B_AUDIO_SET_AUDIO_FORMAT, + /* arg = ptr to float[4] */ + B_AUDIO_GET_PREFERRED_SAMPLE_RATES +}; + +/* this is the definition of what the audio driver can do for you */ +typedef struct audio_format { + float sample_rate; /* ~4000 - ~48000, maybe more */ + int32 channels; /* 1 or 2 */ + int32 format; /* 0x11 (uchar), 0x2 (short) or 0x24 (float) */ + int32 big_endian; /* 0 for little endian, 1 for big endian */ + size_t buf_header; /* typically 0 or 16 */ + size_t play_buf_size; /* size of playback buffer (latency) */ + size_t rec_buf_size; /* size of record buffer (latency) */ +} audio_format; + +/* when buffer header is in effect, this is what gets read before data */ +typedef struct audio_buf_header { + bigtime_t capture_time; + uint32 capture_size; + float sample_rate; +} audio_buf_header; + + + +#endif /* _AUDIO_DRIVER_H */ + diff --git a/seal-hack/src/BeOS/old_audio_driver.h b/seal-hack/src/BeOS/old_audio_driver.h new file mode 100644 index 0000000..1a88f04 --- /dev/null +++ b/seal-hack/src/BeOS/old_audio_driver.h @@ -0,0 +1,86 @@ +/* audio_driver.h - BeOS Release 3 interface to sound drivers */ + +#ifndef _AUDIO_DRIVER_H_ +#define _AUDIO_DRIVER_H_ + +#include + +enum { + B_AUDIO_GET_PARAMS = B_DEVICE_OP_CODES_END, + B_AUDIO_SET_PARAMS, + B_AUDIO_SET_PLAYBACK_COMPLETION_SEM, + B_AUDIO_SET_CAPTURE_COMPLETION_SEM, + B_AUDIO_RESERVED_1, /* unused */ + B_AUDIO_RESERVED_2, /* unused */ + B_AUDIO_DEBUG_ON, /* unused */ + B_AUDIO_DEBUG_OFF, /* unused */ + B_AUDIO_WRITE_BUFFER, + B_AUDIO_READ_BUFFER, + B_AUDIO_LOCK_FOR_DMA +}; + +enum { + B_AUDIO_ADC_SOURCE_LINE = 0, + B_AUDIO_ADC_SOURCE_CDROM, + B_AUDIO_ADC_SOURCE_MIC, + B_AUDIO_ADC_SOURCE_LOOPBACK +}; + +enum { + B_AUDIO_SAMPLE_RATE_8000 = 0, + B_AUDIO_SAMPLE_RATE_5510 = 1, + B_AUDIO_SAMPLE_RATE_16000 = 2, + B_AUDIO_SAMPLE_RATE_11025 = 3, + B_AUDIO_SAMPLE_RATE_27420 = 4, + B_AUDIO_SAMPLE_RATE_18900 = 5, + B_AUDIO_SAMPLE_RATE_32000 = 6, + B_AUDIO_SAMPLE_RATE_22050 = 7, + B_AUDIO_SAMPLE_RATE_37800 = 9, + B_AUDIO_SAMPLE_RATE_44100 = 11, + B_AUDIO_SAMPLE_RATE_48000 = 12, + B_AUDIO_SAMPLE_RATE_33075 = 13, + B_AUDIO_SAMPLE_RATE_9600 = 14, + B_AUDIO_SAMPLE_RATE_6620 = 15 +}; + +struct audio_channel { + uint32 adc_source; /* adc input source */ + char adc_gain; /* 0-15 adc gain, in 1.5 dB steps */ + char mic_gain_enable; /* non-zero enables 20 dB MIC input gain */ + char cd_mix_gain; /* 0-31 cd mix to output gain in -1.5dB steps */ + char cd_mix_mute; /* non-zero mutes cd mix */ + char aux2_mix_gain; /* unused */ + char aux2_mix_mute; /* unused */ + char line_mix_gain; /* 0-31 line mix to out gain in -1.5dB steps */ + char line_mix_mute; /* non-zero mutes line mix */ + char dac_attn; /* 0-61 dac attenuation, in -1.5 dB steps */ + char dac_mute; /* non-zero mutes dac output */ + char reserved_1; + char reserved_2; +}; + +typedef struct audio_params { + struct audio_channel left; /* left channel setup */ + struct audio_channel right; /* right channel setup */ + uint32 sample_rate; /* sample rate */ + uint32 playback_format; /* ignore (always 16bit-linear) */ + uint32 capture_format; /* ignore (always 16bit-linear) */ + char dither_enable; /* non-zero enables dither on 16 => 8 bit */ + char mic_attn; /* 0..64 mic input level */ + char mic_enable; /* non-zero enables mic input */ + char output_boost; /* ignore (always on) */ + char highpass_enable; /* ignore (always on) */ + char mono_gain; /* 0..64 mono speaker gain */ + char mono_mute; /* non-zero mutes speaker */ +} audio_params; + +typedef struct audio_buffer_header { + int32 buffer_number; + int32 subscriber_count; + bigtime_t time; + int32 reserved_1; + int32 reserved_2; + bigtime_t sample_clock; +} audio_buffer_header; + +#endif diff --git a/seal-hack/src/DOS/DPMI16/Borland/Makefile b/seal-hack/src/DOS/DPMI16/Borland/Makefile new file mode 100644 index 0000000..9ce471e --- /dev/null +++ b/seal-hack/src/DOS/DPMI16/Borland/Makefile @@ -0,0 +1,33 @@ +# Makefile for Borland C++ 4.5 (DPMI16 protected mode, large memory model) + +CC = bcc +AS = tasm +AR = tlib +CFLAGS = -ml -WX -c -w9 -3 -O2 -D__DPMI__ -D__16BIT__ +AFLAGS = -t -m -q -zi +LFLAGS = -ml -WX + +OBJS = audio.obj wavfile.obj xmfile.obj s3mfile.obj modfile.obj mtmfile.obj \ + iofile.obj modeng.obj nondrv.obj mixdrv.obj msdos.obj \ + sbdrv.obj awedrv.obj pasdrv.obj wssdrv.obj gusdrv.obj ariadrv.obj + +LIB = ..\lib\DOS\audiobcx.lib + +all : mp.exe $(LIB) clean + @echo done. + +mp.exe : mp.obj $(LIB) + $(CC) $(LFLAGS) mp.obj $(LIB) + +$(LIB) : $(OBJS) + @if exist $(LIB) del $(LIB) > nul + $(AR) $(LIB) @DOS\DPMI16\Borland\audiobcx.lnk + +.c.obj : + $(CC) $(CFLAGS) $< + +.asm.obj : + $(AS) $(AFLAGS) $< + +clean : + @if exist *.obj del *.obj > nul diff --git a/seal-hack/src/DOS/DPMI16/Borland/audiobcx.lnk b/seal-hack/src/DOS/DPMI16/Borland/audiobcx.lnk new file mode 100644 index 0000000..1d32ae4 --- /dev/null +++ b/seal-hack/src/DOS/DPMI16/Borland/audiobcx.lnk @@ -0,0 +1 @@ ++audio.obj +wavfile.obj +xmfile.obj +s3mfile.obj +modfile.obj +iofile.obj +modeng.obj +nondrv.obj +mixdrv.obj +msdos.obj +sbdrv.obj +awedrv.obj +pasdrv.obj +wssdrv.obj +gusdrv.obj +ariadrv.obj diff --git a/seal-hack/src/DOS/DPMI32/Borland/Makefile b/seal-hack/src/DOS/DPMI32/Borland/Makefile new file mode 100644 index 0000000..d181c37 --- /dev/null +++ b/seal-hack/src/DOS/DPMI32/Borland/Makefile @@ -0,0 +1,33 @@ +# Makefile for Borland C++ 4.5 (DPMI32 protected mode, flat memory model) + +CC = bcc32a +AS = tasm +AR = tlib +CFLAGS = -WX -c -w9 -5 -O2 -D__DPMI__ -D__ASM__ +AFLAGS = -t -m -q -ml -zi +LFLAGS = -WX + +OBJS = audio.obj wavfile.obj xmfile.obj s3mfile.obj modfile.obj mtmfile.obj \ + iofile.obj modeng.obj nondrv.obj mixdrv.obj _mixdrv.obj msdos.obj \ + sbdrv.obj awedrv.obj pasdrv.obj wssdrv.obj gusdrv.obj ariadrv.obj + +LIB = ..\lib\DOS\audiobcf.lib + +all : mp.exe $(LIB) clean + @echo done. + +mp.exe : mp.obj $(LIB) + $(CC) $(LFLAGS) mp.obj $(LIB) + +$(LIB) : $(OBJS) + @if exist $(LIB) del $(LIB) > nul + $(AR) $(LIB) @DOS\DPMI32\Borland\audiobcf.lnk + +.c.obj : + $(CC) $(CFLAGS) $< + +.asm.obj : + $(AS) $(AFLAGS) $< + +clean : + @if exist *.obj del *.obj > nul diff --git a/seal-hack/src/DOS/DPMI32/Borland/audiobcf.lnk b/seal-hack/src/DOS/DPMI32/Borland/audiobcf.lnk new file mode 100644 index 0000000..27f2c1c --- /dev/null +++ b/seal-hack/src/DOS/DPMI32/Borland/audiobcf.lnk @@ -0,0 +1 @@ ++audio.obj +wavfile.obj +xmfile.obj +s3mfile.obj +modfile.obj +iofile.obj +modeng.obj +nondrv.obj +mixdrv.obj +_mixdrv.obj +msdos.obj +sbdrv.obj +awedrv.obj +pasdrv.obj +wssdrv.obj +gusdrv.obj +ariadrv.obj diff --git a/seal-hack/src/DOS/DPMI32/DJGPP/Makefile b/seal-hack/src/DOS/DPMI32/DJGPP/Makefile new file mode 100644 index 0000000..ac9181b --- /dev/null +++ b/seal-hack/src/DOS/DPMI32/DJGPP/Makefile @@ -0,0 +1,39 @@ +# Makefile for DJGPP V2.0 (GO32/DPMI32 protected mode, flat memory model) + +CC = gcc +AR = ar +RANLIB = ranlib +STRIP = strip +COFF2EXE = stubify +CFLAGS = -c -Wall -mpentium -O2 -D__DPMI__ -D__ASM__ +LFLAGS = + +#OBJS = audio.o wavfile.o xmfile.o s3mfile.o modfile.o mtmfile.o \ +# iofile.o modeng.o nondrv.o mixdrv.o _mixdrv.o msdos.o \ +# sbdrv.o awedrv.o pasdrv.o wssdrv.o gusdrv.o ariadrv.o + +OBJS = audiodj.o _mixdrv.o + +LIB = ../lib/DOS/libaudio.a + +all : mp.exe $(LIB) clean + @echo done. + +mp.exe : mp.o $(LIB) + $(CC) -o mp mp.o $(LIB) $(LFLAGS) + $(STRIP) mp + $(COFF2EXE) mp + @del mp > nul + +$(LIB) : $(OBJS) + @$(AR) rc $(LIB) $(OBJS) + $(RANLIB) $(LIB) + +.c.o : + $(CC) $(CFLAGS) $< + +.s.o : + $(CC) $(CFLAGS) $*.S + +clean : + @if exist *.o del *.o > nul diff --git a/seal-hack/src/DOS/DPMI32/Watcom/Makefile b/seal-hack/src/DOS/DPMI32/Watcom/Makefile new file mode 100644 index 0000000..60a1412 --- /dev/null +++ b/seal-hack/src/DOS/DPMI32/Watcom/Makefile @@ -0,0 +1,40 @@ +# Makefile for WATCOM C/C++32 10.0 (DOS4GW protected mode, flat memory model) + +CC = wcc386 +LD = wcl386 +AS = tasm +AR = wlib -s -t -q -n +CFLAGS = -zq -zu -w9 -we -5r -s -oxt -D__DPMI__ -D__ASM__ +AFLAGS = -t -m -q -ml -zi +LFLAGS = -l=dos4g -zq + +#AS = wasm +#AFLAGS = -zq -w9 -we -5r + +OBJS = audio.obj wavfile.obj xmfile.obj s3mfile.obj modfile.obj mtmfile.obj \ + iofile.obj modeng.obj nondrv.obj mixdrv.obj _mixdrv.obj msdos.obj \ + sbdrv.obj awedrv.obj pasdrv.obj wssdrv.obj gusdrv.obj ariadrv.obj + +LIB = "..\lib\DOS\audiowcf.lib" + +all : mp.exe $(LIB) clean .SYMBOLIC + @echo done. + +mp.exe : mp.obj $(LIB) + $(LD) mp.obj $(LIB) $(LFLAGS) + +$(LIB) : $(OBJS) + @echo $(OBJS) > audiowcf.lnk + $(AR) $(LIB) @audiowcf.lnk + @del audiowcf.lnk + +.SUFFIXES: .c .asm .obj + +.c.obj : + $(CC) $(CFLAGS) $< + +.asm.obj : + $(AS) $(AFLAGS) $< + +clean : .SYMBOLIC + @if exist *.obj del *.obj > nul diff --git a/seal-hack/src/DOS/Large/Borland/Makefile b/seal-hack/src/DOS/Large/Borland/Makefile new file mode 100644 index 0000000..9326b53 --- /dev/null +++ b/seal-hack/src/DOS/Large/Borland/Makefile @@ -0,0 +1,33 @@ +# Makefile for Borland C++ 4.5 (DOS real mode, large memory model) + +CC = bcc +AS = tasm +AR = tlib +CFLAGS = -ml -c -w9 -3 -O2 -D__DOS16__ -D__16BIT__ +AFLAGS = -t -m -q -zi +LFLAGS = -ml + +OBJS = audio.obj wavfile.obj xmfile.obj s3mfile.obj modfile.obj mtmfile.obj \ + iofile.obj modeng.obj nondrv.obj mixdrv.obj msdos.obj \ + sbdrv.obj awedrv.obj pasdrv.obj wssdrv.obj gusdrv.obj ariadrv.obj + +LIB = ..\lib\DOS\audiobcl.lib + +all : mp.exe $(LIB) clean + @echo done. + +mp.exe : mp.obj $(LIB) + $(CC) $(LFLAGS) mp.obj $(LIB) + +$(LIB) : $(OBJS) + @if exist $(LIB) del $(LIB) > nul + $(AR) $(LIB) @DOS\Large\Borland\audiobcl.lnk + +.c.obj : + $(CC) $(CFLAGS) $< + +.asm.obj : + $(AS) $(AFLAGS) $< + +clean : + @if exist *.obj del *.obj > nul diff --git a/seal-hack/src/DOS/Large/Borland/audiobcl.lnk b/seal-hack/src/DOS/Large/Borland/audiobcl.lnk new file mode 100644 index 0000000..1d32ae4 --- /dev/null +++ b/seal-hack/src/DOS/Large/Borland/audiobcl.lnk @@ -0,0 +1 @@ ++audio.obj +wavfile.obj +xmfile.obj +s3mfile.obj +modfile.obj +iofile.obj +modeng.obj +nondrv.obj +mixdrv.obj +msdos.obj +sbdrv.obj +awedrv.obj +pasdrv.obj +wssdrv.obj +gusdrv.obj +ariadrv.obj diff --git a/seal-hack/src/DOS/Large/Watcom/Makefile b/seal-hack/src/DOS/Large/Watcom/Makefile new file mode 100644 index 0000000..350b04f --- /dev/null +++ b/seal-hack/src/DOS/Large/Watcom/Makefile @@ -0,0 +1,32 @@ +# Makefile for Watcom C/C++16 (DOS real mode, large memory model) + +CC = wcl +AS = tasm +AR = wlib -n -b -q +CFLAGS = -zq -zu -ml -c -w9 -we -5 -s -oxt -D__DOS16__ -D__16BIT__ +AFLAGS = -t -m -q -zi +LFLAGS = -zq -ml + +OBJS = audio.obj wavfile.obj xmfile.obj s3mfile.obj modfile.obj mtmfile.obj & + iofile.obj modeng.obj nondrv.obj mixdrv.obj msdos.obj & + sbdrv.obj awedrv.obj pasdrv.obj wssdrv.obj gusdrv.obj ariadrv.obj + +LIB = ..\lib\DOS\audiowcl.lib + +all : mp.exe $(LIB) clean .SYMBOLIC + @echo done. + +mp.exe : mp.obj $(LIB) + $(CC) $(LFLAGS) mp.obj $(LIB) + +$(LIB) : $(OBJS) + *$(AR) $(LIB) $(OBJS) + +.c.obj : + $(CC) $(CFLAGS) $< + +.asm.obj : + $(AS) $(AFLAGS) $< + +clean : .SYMBOLIC + @if exist *.obj del *.obj > nul diff --git a/seal-hack/src/FreeBSD/Makefile b/seal-hack/src/FreeBSD/Makefile new file mode 100644 index 0000000..b972237 --- /dev/null +++ b/seal-hack/src/FreeBSD/Makefile @@ -0,0 +1,30 @@ +# Makefile for FreeBSD/386 and VoxWare 2.90 or later + +CC = gcc +AR = ar +RANLIB = ranlib +STRIP = strip +CFLAGS = -c -Wall -O2 -fomit-frame-pointer -D__FREEBSD__ -D__ASM__ +LFLAGS = -L../lib/FreeBSD -laudio + +OBJS = audio.o wavfile.o xmfile.o s3mfile.o modfile.o mtmfile.o \ + iofile.o modeng.o nondrv.o mixdrv.o _mixdrv.o lnxdrv.o + +LIB = ../lib/FreeBSD/libaudio.a + +all : mp $(LIB) clean + @echo done. + +mp : mp.o $(LIB) + $(CC) -o mp mp.o $(LFLAGS) + $(STRIP) mp + +$(LIB) : $(OBJS) + $(AR) rc $(LIB) $(OBJS) + $(RANLIB) $(LIB) + +.c.o .s.o .S.o : + $(CC) $(CFLAGS) $< + +clean : + @for f in *.o; do rm -f $$f; done diff --git a/seal-hack/src/Indigo/Makefile b/seal-hack/src/Indigo/Makefile new file mode 100644 index 0000000..22301de --- /dev/null +++ b/seal-hack/src/Indigo/Makefile @@ -0,0 +1,30 @@ +# Makefile for Silicon Graphics Indigo IRIX 4.x with audio ports + +CC = gcc +AR = ar +RANLIB = ranlib +STRIP = strip +CFLAGS = -c -Wall -O2 -D__SILICON__ -D__BIGENDIAN__ +LFLAGS = -laudio -L../lib/Indigo -laudio + +OBJS = audio.o wavfile.o xmfile.o s3mfile.o modfile.o mtmfile.o \ + iofile.o modeng.o nondrv.o mixdrv.o sgidrv.o + +LIB = ../lib/Indigo/libaudio.a + +all : mp $(LIB) clean + @echo done. + +mp : mp.o $(LIB) + $(CC) -o mp mp.o $(LFLAGS) + $(STRIP) mp + +$(LIB) : $(OBJS) + $(AR) rc $(LIB) $(OBJS) + $(RANLIB) $(LIB) + +.c.o .s.o .S.o : + $(CC) $(CFLAGS) $< + +clean : + @for f in *.o; do rm -f $$f; done diff --git a/seal-hack/src/MacOSX/Makefile b/seal-hack/src/MacOSX/Makefile new file mode 100644 index 0000000..a081844 --- /dev/null +++ b/seal-hack/src/MacOSX/Makefile @@ -0,0 +1,34 @@ +# Makefile for MacOS X using SDL + +CC = clang +AR = ar +RANLIB = ranlib +STRIP = strip +CFLAGS = -c -Wall -O2 -fomit-frame-pointer -D__OSX__ `allegro-config --cflags` -arch i386 +LFLAGS = -L../lib/MacOSX -laudio `allegro-config --libs` -arch i386 + +OBJS = audio.o wavfile.o xmfile.o s3mfile.o modfile.o mtmfile.o \ + iofile.o modeng.o nondrv.o mixdrv.o allegdrv.o +#osxdrv.c +# Not supported on x86_64 platforms +#_mixdrv.o + +LIB = ../lib/MacOSX/libaudio.a + +all : mp $(LIB) clean + @echo done. + +mp : mp.o $(LIB) + $(CC) -o mp mp.o $(LFLAGS) + $(STRIP) mp + +$(LIB) : $(OBJS) + $(AR) rc $(LIB) $(OBJS) + $(RANLIB) $(LIB) + +.c.o .s.o .S.o : + @echo CC $< + @$(CC) $(CFLAGS) $< + +clean : + @for f in *.o; do rm -f $$f; done diff --git a/seal-hack/src/Makefile b/seal-hack/src/Makefile new file mode 100644 index 0000000..a9520e6 --- /dev/null +++ b/seal-hack/src/Makefile @@ -0,0 +1,34 @@ +# Makefile for Linux and SDL wrapper driver... + +CC = clang +AR = ar +RANLIB = ranlib +STRIP = strip +CFLAGS = -g -c -Wall -O2 -D__SDL__ `sdl-config --cflags` -arch i386 +LFLAGS = -L../lib/SDL -laudio `sdl-config --libs` -arch i386 + +OBJS = audio.o wavfile.o xmfile.o s3mfile.o modfile.o mtmfile.o \ + iofile.o modeng.o nondrv.o mixdrv.o sdldrv.o +#_mixdrv.o + +LIB = ../lib/SDL/libaudio.a + +all: mp $(LIB) + @echo done. + +mp : mp.o $(LIB) + $(CC) -o mp mp.o $(LFLAGS) + +$(LIB) : $(OBJS) + $(AR) rc $(LIB) $(OBJS) + $(RANLIB) $(LIB) + +.c.o: + $(CC) $(CFLAGS) $< + +.s.o .S.o : + $(CC) $(CFLAGS) $< -D__LINUX__ + +clean: + -rm -rf *.o + -rm mp diff --git a/seal-hack/src/OS2/Makefile b/seal-hack/src/OS2/Makefile new file mode 100644 index 0000000..912a640 --- /dev/null +++ b/seal-hack/src/OS2/Makefile @@ -0,0 +1,53 @@ +# Makefile for OS/2 MMPM with EMX and GCC +# +# To build an OS/2 DLL and the ModPlayer executable, +# just set the MMBASE environment variable to point to +# your MMOS2 base directory, change to the src directory +# and type make -f os2/Makefile. That's all there is +# to it! + +MMBASE=f:\mmos2 + +CC = gcc +CPP = cpp +IMPLIB = implib +CFLAGS = -c -Wall -O3 -Zsys -Zmts -fomit-frame-pointer -D__OS2__ -D__ASM__ -D __32BIT__ -D __FLAT__ + +DLL = audio.dll +LIB = ../lib/OS2/audio.lib + +OBJS = audio.o wavfile.o xmfile.o s3mfile.o modfile.o mtmfile.o \ + iofile.o modeng.o nondrv.o _mixdrv.o mixdrv.o os2drv.o + +OMFOBJS = audio.obj wavfile.obj xmfile.obj s3mfile.obj modfile.obj \ + mtmfile.obj iofile.obj modeng.obj nondrv.obj _mixdrv.obj \ + mixdrv.obj os2drv.obj + +all : mp.exe + @echo done. + +$(DLL) : $(OBJS) mdm.lib + $(CC) -Zsys -Zomf -Zmts -Zso -Zdll -o $(DLL) os2/audio.def -L. -lmdm $(OMFOBJS) + +mdm.lib: $(MMBASE)/dll/mdm.dll + $(IMPLIB) mdm.lib $(MMBASE)/dll/mdm.dll + +$(LIB): $(DLL) + $(IMPLIB) $(LIB) $(DLL) + +mp.exe : $(OBJS) mp.o $(LIB) + emxomf mp.o + $(CC) -Zsys -Zomf -Zmts -Zlinker /STACK:32768 -Zlinker /PMTYPE:VIO -o mp mp.obj -L../lib/OS2 -laudio -lmdm + +.c.o: + $(CC) $(CFLAGS) $< + emxomf $*.o + +_mixdrv.o: _mixdrv.S + $(CPP) _mixdrv.S | $(AS) -o _mixdrv.o + emxomf _mixdrv.o + +clean : + @rm -rf *.obj *.o + + \ No newline at end of file diff --git a/seal-hack/src/OS2/audio.def b/seal-hack/src/OS2/audio.def new file mode 100644 index 0000000..c1c1ceb --- /dev/null +++ b/seal-hack/src/OS2/audio.def @@ -0,0 +1,52 @@ +LIBRARY audio INITINSTANCE TERMINSTANCE +DESCRIPTION 'SEAL Audio Library 1.07 for OS/2' +EXPORTS AInitialize + AGetVersion + AGetAudioNumDevs + AGetAudioDevCaps + AGetErrorText + APingAudio + AOpenAudio + ACloseAudio + AUpdateAudio + AOpenVoices + ACloseVoices + ASetAudioCallback + ASetAudioTimerProc + ASetAudioTimerRate + AGetAudioDataAvail + ACreateAudioData + ADestroyAudioData + AWriteAudioData + ACreateAudioVoice + ADestroyAudioVoice + APlayVoice + APrimeVoice + AStartVoice + AStopVoice + ASetVoicePosition + ASetVoiceFrequency + ASetVoiceVolume + ASetVoicePanning + AGetVoicePosition + AGetVoiceFrequency + AGetVoiceVolume + AGetVoicePanning + AGetVoiceStatus + APlayModule + AStopModule + APauseModule + AResumeModule + ASetModuleVolume + ASetModulePosition + AGetModuleVolume + AGetModulePosition + AGetModuleStatus + ASetModuleCallback + ALoadModuleFile + AFreeModuleFile + ALoadWaveFile + AFreeWaveFile + AGetModuleTrack + ASetAudioMixerValue + AUpdateAudioEx diff --git a/seal-hack/src/Solaris/Makefile b/seal-hack/src/Solaris/Makefile new file mode 100644 index 0000000..1e251ae --- /dev/null +++ b/seal-hack/src/Solaris/Makefile @@ -0,0 +1,30 @@ +# Makefile for SPARC 10 Solaris 2.x with dbri or AMD ulaw audio device + +CC = gcc +AR = ar +RANLIB = ranlib +STRIP = strip +CFLAGS = -c -Wall -O2 -D__SOLARIS__ -D__BIGENDIAN__ +LFLAGS = -L../lib/Solaris -laudio + +OBJS = audio.o wavfile.o xmfile.o s3mfile.o modfile.o mtmfile.o \ + iofile.o modeng.o nondrv.o mixdrv.o sundrv.o + +LIB = ../lib/Solaris/libaudio.a + +all : mp $(LIB) clean + @echo done. + +mp : mp.o $(LIB) + $(CC) -o mp mp.o $(LFLAGS) + $(STRIP) mp + +$(LIB) : $(OBJS) + $(AR) rc $(LIB) $(OBJS) + $(RANLIB) $(LIB) + +.c.o .s.o .S.o : + $(CC) $(CFLAGS) $< + +clean : + @rm -rf *.o diff --git a/seal-hack/src/SunOS/Makefile b/seal-hack/src/SunOS/Makefile new file mode 100644 index 0000000..2208f81 --- /dev/null +++ b/seal-hack/src/SunOS/Makefile @@ -0,0 +1,30 @@ +# Makefile for SPARC 1/2/IPX/... SunOS 4.1.x with AMD ulaw audio device + +CC = gcc +AR = ar +RANLIB = ranlib +STRIP = strip +CFLAGS = -c -Wall -O2 -D__SPARC__ -D__BIGENDIAN__ +LFLAGS = -L../lib/SunOS -laudio + +OBJS = audio.o wavfile.o xmfile.o s3mfile.o modfile.o mtmfile.o \ + iofile.o modeng.o nondrv.o mixdrv.o sundrv.o + +LIB = ../lib/SunOS/libaudio.a + +all : mp $(LIB) clean + @echo done. + +mp : mp.o $(LIB) + $(CC) -o mp mp.o $(LFLAGS) + $(STRIP) mp + +$(LIB) : $(OBJS) + $(AR) rc $(LIB) $(OBJS) + $(RANLIB) $(LIB) + +.c.o .s.o .S.o : + $(CC) $(CFLAGS) $< + +clean : + @rm -rf *.o diff --git a/seal-hack/src/Windows/Win16/Borland/Makefile b/seal-hack/src/Windows/Win16/Borland/Makefile new file mode 100644 index 0000000..e881801 --- /dev/null +++ b/seal-hack/src/Windows/Win16/Borland/Makefile @@ -0,0 +1,32 @@ +# Makefile for Borland C++ 4.5 (Win16 protected mode, large memory model) + +CC = bcc +AS = tasm +AR = tlib +CFLAGS = -ml -W -c -w9 -3 -O2 -D__WINDOWS__ -D__16BIT__ +AFLAGS = -t -m -q -zi +LFLAGS = -ml -W + +OBJS = audio.obj wavfile.obj xmfile.obj s3mfile.obj modfile.obj mtmfile.obj \ + iofile.obj modeng.obj nondrv.obj mixdrv.obj windrv.obj + +LIB = ..\lib\Win16\audw16bc.lib + +all : mp.exe $(LIB) clean + @echo done. + +mp.exe : mp.obj $(LIB) + $(CC) $(LFLAGS) mp.obj $(LIB) + +$(LIB) : $(OBJS) + @if exist $(LIB) del $(LIB) > nul + $(AR) $(LIB) @Windows\Win16\Borland\audw16bc.lnk + +.c.obj : + $(CC) $(CFLAGS) $< + +.asm.obj : + $(AS) $(AFLAGS) $< + +clean : + @if exist *.obj del *.obj > nul diff --git a/seal-hack/src/Windows/Win16/Borland/audw16bc.lnk b/seal-hack/src/Windows/Win16/Borland/audw16bc.lnk new file mode 100644 index 0000000..f54c905 --- /dev/null +++ b/seal-hack/src/Windows/Win16/Borland/audw16bc.lnk @@ -0,0 +1 @@ ++audio.obj +wavfile.obj +xmfile.obj +s3mfile.obj +modfile.obj +iofile.obj +modeng.obj +nondrv.obj +mixdrv.obj +windrv.obj diff --git a/seal-hack/src/Windows/Win16/Watcom/Makefile b/seal-hack/src/Windows/Win16/Watcom/Makefile new file mode 100644 index 0000000..cf899eb --- /dev/null +++ b/seal-hack/src/Windows/Win16/Watcom/Makefile @@ -0,0 +1,31 @@ +# Makefile for WATCOM C/C++16 10.0 (Win16 protected mode, large memory model) + +CC = wcl +AS = tasm +AR = wlib -b -n -q +CFLAGS = -zq -zw -ml -c -w9 -we -5 -s -oxt -D__WINDOWS__ -D__16BIT__ +AFLAGS = -t -m -q -ml -zi +LFLAGS = -zq -zw -ml + +OBJS = audio.obj wavfile.obj xmfile.obj s3mfile.obj modfile.obj mtmfile.obj & + iofile.obj modeng.obj nondrv.obj mixdrv.obj windrv.obj + +LIB = ..\lib\Win16\audw16wc.lib + +all : mp.exe $(LIB) clean .SYMBOLIC + @echo done. + +mp.exe : mp.obj $(LIB) + $(CC) $(LFLAGS) mp.obj $(LIB) mmsystem.lib + +$(LIB) : $(OBJS) + *$(AR) $(LIB) $(OBJS) + +.c.obj : + $(CC) $(CFLAGS) $< + +.asm.obj : + $(AS) $(AFLAGS) $< + +clean : .SYMBOLIC + @if exist *.obj del *.obj > nul diff --git a/seal-hack/src/Windows/Win32/Borland/Makefile b/seal-hack/src/Windows/Win32/Borland/Makefile new file mode 100644 index 0000000..211fa73 --- /dev/null +++ b/seal-hack/src/Windows/Win32/Borland/Makefile @@ -0,0 +1,37 @@ +# Makefile for Borland C++ 4.5 (Win32 protected mode, flat memory model) + +CC = bcc32a +LD = tlink32 +IMPLIB = implib +AS = tasm +AR = tlib +CFLAGS = -WC -c -w9 -5 -O2 -DWIN32 -D__WINDOWS__ -D__ASM__ +AFLAGS = -t -m -q -ml -zi +LFLAGS = -WD +LDFLAGS = -x -Tpd +OBJS = audio.obj wavfile.obj xmfile.obj s3mfile.obj modfile.obj mtmfile.obj \ + iofile.obj modeng.obj nondrv.obj mixdrv.obj _mixdrv.obj windrv.obj \ + drdrv.obj audiow32.obj + +DLL = audiow32.dll +LIB = ..\lib\Win32\audw32bc.lib + +all : mp.exe $(DLL) $(LIB) clean + +mp.exe : mp.obj $(LIB) + $(CC) -WC mp.obj $(LIB) + +$(DLL): $(OBJS) + $(LD) $(LDFLAGS) @Windows\Win32\Borland\audiow32.lnk + +$(LIB) : $(DLL) + $(IMPLIB) $(LIB) $(DLL) + +.c.obj : + $(CC) $(CFLAGS) $< + +.asm.obj : + $(AS) $(AFLAGS) $< + +clean : + @if exist *.obj del *.obj > nul diff --git a/seal-hack/src/Windows/Win32/Borland/audiow32.def b/seal-hack/src/Windows/Win32/Borland/audiow32.def new file mode 100644 index 0000000..ff6e109 --- /dev/null +++ b/seal-hack/src/Windows/Win32/Borland/audiow32.def @@ -0,0 +1,54 @@ +LIBRARY audiow32 +DESCRIPTION 'Audio Library 1.07 for Win32' +CODE PRELOAD MOVEABLE DISCARDABLE +DATA PRELOAD MOVEABLE +EXPORTS AInitialize @100 + AGetVersion @101 + AGetAudioNumDevs @102 + AGetAudioDevCaps @103 + AGetErrorText @104 + APingAudio @105 + AOpenAudio @106 + ACloseAudio @107 + AUpdateAudio @108 + AOpenVoices @109 + ACloseVoices @110 + ASetAudioCallback @111 + ASetAudioTimerProc @112 + ASetAudioTimerRate @113 + AGetAudioDataAvail @114 + ACreateAudioData @115 + ADestroyAudioData @116 + AWriteAudioData @117 + ACreateAudioVoice @118 + ADestroyAudioVoice @119 + APlayVoice @120 + APrimeVoice @121 + AStartVoice @122 + AStopVoice @123 + ASetVoicePosition @124 + ASetVoiceFrequency @125 + ASetVoiceVolume @126 + ASetVoicePanning @127 + AGetVoicePosition @128 + AGetVoiceFrequency @129 + AGetVoiceVolume @130 + AGetVoicePanning @131 + AGetVoiceStatus @132 + APlayModule @133 + AStopModule @134 + APauseModule @135 + AResumeModule @136 + ASetModuleVolume @137 + ASetModulePosition @138 + AGetModuleVolume @139 + AGetModulePosition @140 + AGetModuleStatus @141 + ASetModuleCallback @146 + ALoadModuleFile @142 + AFreeModuleFile @143 + ALoadWaveFile @144 + AFreeWaveFile @145 + AGetModuleTrack @147 + ASetAudioMixerValue @148 + AUpdateAudioEx @149 diff --git a/seal-hack/src/Windows/Win32/Borland/audiow32.lnk b/seal-hack/src/Windows/Win32/Borland/audiow32.lnk new file mode 100644 index 0000000..46d0c10 --- /dev/null +++ b/seal-hack/src/Windows/Win32/Borland/audiow32.lnk @@ -0,0 +1,7 @@ +c0d32.obj + +audio.obj wavfile.obj xmfile.obj s3mfile.obj modfile.obj iofile.obj + +modeng.obj nondrv.obj mixdrv.obj _mixdrv.obj windrv.obj audiow32.obj +audiow32.dll +audiow32.map +cw32.lib import32.lib +Windows\Win32\Borland\audiow32.def diff --git a/seal-hack/src/Windows/Win32/VisualC/Makefile b/seal-hack/src/Windows/Win32/VisualC/Makefile new file mode 100644 index 0000000..368d5d5 --- /dev/null +++ b/seal-hack/src/Windows/Win32/VisualC/Makefile @@ -0,0 +1,48 @@ +# Makefile for Visual C++ 4.1 - 5.2 (Win32 protected mode, flat memory model) + +!if "$(MSVCDIR)"=="" +MSVCDIR = C:\VC +!endif + +!if "$(DXSDKROOT)"=="" +DXSDKROOT = $(MSVCDIR) +!endif + +CC = cl +LD = link +AS = tasm +AR = lib +CFLAGS = -nologo -G5 -Gr -MD -LD -W2 -GD -Ox -Zp4 -c -DWIN32 -D__WINDOWS__ -D__FLAT__ -D__ASM__ -D__MSC__ -I"$(DXSDKROOT)\INCLUDE" -I"$(MSVCDIR)\INCLUDE" +AFLAGS = -t -m -q -ml -zi +OBJS = audiow32.obj audio.obj wavfile.obj xmfile.obj s3mfile.obj mtmfile.obj \ + modfile.obj iofile.obj modeng.obj nondrv.obj mixdrv.obj \ + _mixdrv.obj windrv.obj dsdrv.obj dsdrv2.obj + +DLL = audiow32.dll +LIB = ..\lib\Win32\audw32vc.lib + +LIBS = "$(MSVCDIR)\LIB\msvcrt.lib" \ + "$(MSVCDIR)\LIB\kernel32.lib" "$(MSVCDIR)\LIB\winmm.lib" \ + "$(MSVCDIR)\LIB\ole32.lib" "$(MSVCDIR)\LIB\user32.lib" \ + "$(DXSDKROOT)\LIB\dsound.lib" + +LFLAGS = -NOLOGO -DLL -MACHINE:I386 -VERSION:1.07 \ + -DEF:Windows\Win32\VisualC\audiow32.def -OUT:$(DLL) -IMPLIB:$(LIB) + +all : mp.exe $(DLL) $(LIB) clean + +mp.exe : mp.obj $(LIB) + @$(LD) $(LIBS) -NOLOGO -SUBSYSTEM:CONSOLE -MACHINE:I386 -OUT:mp.exe mp.obj $(LIB) + +$(DLL) $(LIB) : $(OBJS) + $(LD) $(LIBS) $(LFLAGS) $(OBJS) + +.c.obj : + $(CC) $(CFLAGS) $< + +.asm.obj : + $(AS) $(AFLAGS) $< + +clean : + @if exist *.obj del *.obj > nul + @if exist *.exp del *.exp > nul diff --git a/seal-hack/src/Windows/Win32/VisualC/audiow32.def b/seal-hack/src/Windows/Win32/VisualC/audiow32.def new file mode 100644 index 0000000..dd4c81f --- /dev/null +++ b/seal-hack/src/Windows/Win32/VisualC/audiow32.def @@ -0,0 +1,54 @@ +LIBRARY audiow32 +DESCRIPTION 'Audio Library 1.07 for Win32' +CODE PRELOAD MOVEABLE DISCARDABLE +DATA PRELOAD MOVEABLE +EXPORTS AInitialize @100 + AGetVersion @101 + AGetAudioNumDevs @102 + AGetAudioDevCaps @103 + AGetErrorText @104 + APingAudio @105 + AOpenAudio @106 + ACloseAudio @107 + AUpdateAudio @108 + AOpenVoices @109 + ACloseVoices @110 + ASetAudioCallback @111 + ASetAudioTimerProc @112 + ASetAudioTimerRate @113 + AGetAudioDataAvail @114 + ACreateAudioData @115 + ADestroyAudioData @116 + AWriteAudioData @117 + ACreateAudioVoice @118 + ADestroyAudioVoice @119 + APlayVoice @120 + APrimeVoice @121 + AStartVoice @122 + AStopVoice @123 + ASetVoicePosition @124 + ASetVoiceFrequency @125 + ASetVoiceVolume @126 + ASetVoicePanning @127 + AGetVoicePosition @128 + AGetVoiceFrequency @129 + AGetVoiceVolume @130 + AGetVoicePanning @131 + AGetVoiceStatus @132 + APlayModule @133 + AStopModule @134 + APauseModule @135 + AResumeModule @136 + ASetModuleVolume @137 + ASetModulePosition @138 + AGetModuleVolume @139 + AGetModulePosition @140 + AGetModuleStatus @141 + ASetModuleCallback @146 + ALoadModuleFile @142 + AFreeModuleFile @143 + ALoadWaveFile @144 + AFreeWaveFile @145 + AGetModuleTrack @147 + ASetAudioMixerValue @148 + AUpdateAudioEx @149 diff --git a/seal-hack/src/Windows/Win32/Watcom/Makefile b/seal-hack/src/Windows/Win32/Watcom/Makefile new file mode 100644 index 0000000..923ed23 --- /dev/null +++ b/seal-hack/src/Windows/Win32/Watcom/Makefile @@ -0,0 +1,39 @@ +# Makefile for WATCOM C/C++32 10.0 (Win32 protected mode, flat memory model) + +CC = wcl386 +LD = wlink +AS = tasm +AR = wlib -b -n -q +CFLAGS = -zq -c -w9 -5r -s -oxt -DWIN32 -D__WINDOWS__ -D__ASM__ +AFLAGS = -q -t -m -ml -zi +LFLAGS = -zq -l=nt + +#AS = wasm +#AFLAGS = -zq -w9 -we -5r + +OBJS = audio.obj wavfile.obj xmfile.obj s3mfile.obj modfile.obj mtmfile.obj & + iofile.obj modeng.obj nondrv.obj mixdrv.obj _mixdrv.obj windrv.obj dsdrv.obj + +DLL = audiow32.dll +LIB = ..\lib\Win32\audw32wc.lib + +all : mp.exe $(DLL) clean .SYMBOLIC + @echo done. + +mp.exe : mp.obj $(LIB) + $(CC) mp.obj $(LIB) $(LFLAGS) + +$(LIB) : $(DLL) + $(AR) $(LIB) @Windows\Win32\Watcom\audiow32.lbc + +$(DLL) : $(OBJS) + $(LD) @Windows\Win32\Watcom\audiow32.lnk + +.c.obj : + $(CC) $(CFLAGS) $< + +.asm.obj : + $(AS) $(AFLAGS) $< + +clean : .SYMBOLIC + @if exist *.obj del *.obj > nul diff --git a/seal-hack/src/Windows/Win32/Watcom/audiow32.lbc b/seal-hack/src/Windows/Win32/Watcom/audiow32.lbc new file mode 100644 index 0000000..a370167 --- /dev/null +++ b/seal-hack/src/Windows/Win32/Watcom/audiow32.lbc @@ -0,0 +1,49 @@ +++'_AInitialize@0'.'AUDIOW32.DLL'..AInitialize +++'_AGetVersion@0'.'AUDIOW32.DLL'..AGetVersion +++'_AGetAudioNumDevs@0'.'AUDIOW32.DLL'..AGetAudioNumDevs +++'_AGetAudioDevCaps@8'.'AUDIOW32.DLL'..AGetAudioDevCaps +++'_AGetErrorText@12'.'AUDIOW32.DLL'..AGetErrorText +++'_APingAudio@4'.'AUDIOW32.DLL'..APingAudio +++'_AOpenAudio@4'.'AUDIOW32.DLL'..AOpenAudio +++'_ACloseAudio@0'.'AUDIOW32.DLL'..ACloseAudio +++'_AUpdateAudio@0'.'AUDIOW32.DLL'..AUpdateAudio +++'_AOpenVoices@4'.'AUDIOW32.DLL'..AOpenVoices +++'_ACloseVoices@0'.'AUDIOW32.DLL'..ACloseVoices +++'_ASetAudioCallback@4'.'AUDIOW32.DLL'..ASetAudioCallback +++'_ASetAudioTimerProc@4'.'AUDIOW32.DLL'..ASetAudioTimerProc +++'_ASetAudioTimerRate@4'.'AUDIOW32.DLL'..ASetAudioTimerRate +++'_AGetAudioDataAvail@0'.'AUDIOW32.DLL'..AGetAudioDataAvail +++'_ACreateAudioData@4'.'AUDIOW32.DLL'..ACreateAudioData +++'_ADestroyAudioData@4'.'AUDIOW32.DLL'..ADestroyAudioData +++'_AWriteAudioData@12'.'AUDIOW32.DLL'..AWriteAudioData +++'_ACreateAudioVoice@4'.'AUDIOW32.DLL'..ACreateAudioVoice +++'_ADestroyAudioVoice@4'.'AUDIOW32.DLL'..ADestroyAudioVoice +++'_APlayVoice@8'.'AUDIOW32.DLL'..APlayVoice +++'_APrimeVoice@8'.'AUDIOW32.DLL'..APrimeVoice +++'_AStartVoice@4'.'AUDIOW32.DLL'..AStartVoice +++'_AStopVoice@4'.'AUDIOW32.DLL'..AStopVoice +++'_ASetVoicePosition@8'.'AUDIOW32.DLL'..ASetVoicePosition +++'_ASetVoiceFrequency@8'.'AUDIOW32.DLL'..ASetVoiceFrequency +++'_ASetVoiceVolume@8'.'AUDIOW32.DLL'..ASetVoiceVolume +++'_ASetVoicePanning@8'.'AUDIOW32.DLL'..ASetVoicePanning +++'_AGetVoicePosition@8'.'AUDIOW32.DLL'..AGetVoicePosition +++'_AGetVoiceFrequency@8'.'AUDIOW32.DLL'..AGetVoiceFrequency +++'_AGetVoiceVolume@8'.'AUDIOW32.DLL'..AGetVoiceVolume +++'_AGetVoicePanning@8'.'AUDIOW32.DLL'..AGetVoicePanning +++'_AGetVoiceStatus@8'.'AUDIOW32.DLL'..AGetVoiceStatus +++'_APlayModule@4'.'AUDIOW32.DLL'..APlayModule +++'_AStopModule@0'.'AUDIOW32.DLL'..AStopModule +++'_APauseModule@0'.'AUDIOW32.DLL'..APauseModule +++'_AResumeModule@0'.'AUDIOW32.DLL'..AResumeModule +++'_ASetModuleVolume@4'.'AUDIOW32.DLL'..ASetModuleVolume +++'_ASetModulePosition@8'.'AUDIOW32.DLL'..ASetModulePosition +++'_AGetModuleVolume@4'.'AUDIOW32.DLL'..AGetModuleVolume +++'_AGetModulePosition@8'.'AUDIOW32.DLL'..AGetModulePosition +++'_AGetModuleStatus@4'.'AUDIOW32.DLL'..AGetModuleStatus +++'_ASetModuleCallback@4'.'AUDIOW32.DLL'..ASetModuleCallback +++'_ALoadModuleFile@12'.'AUDIOW32.DLL'..ALoadModuleFile +++'_AFreeModuleFile@4'.'AUDIOW32.DLL'..AFreeModuleFile +++'_ALoadWaveFile@12'.'AUDIOW32.DLL'..ALoadWaveFile +++'_AFreeWaveFile@4'.'AUDIOW32.DLL'..AFreeWaveFile +++'_ASetAudioMixerValue@8'.'AUDIOW32.DLL'..ASetAudioMixerValue +++'_AUpdateAudioEx@4".'AUDIOW32.DLL'..AUpdateAudioEx diff --git a/seal-hack/src/Windows/Win32/Watcom/audiow32.lnk b/seal-hack/src/Windows/Win32/Watcom/audiow32.lnk new file mode 100644 index 0000000..1db8f03 --- /dev/null +++ b/seal-hack/src/Windows/Win32/Watcom/audiow32.lnk @@ -0,0 +1,57 @@ +NAME AUDIOW32.DLL +SYSTEM nt_dll +OPTION MODNAME='AudioW32', VERSION=1.07 +OPTION DESCRIPTION 'Audio Library 1.07 for Win32' +FILE AUDIO.OBJ, WAVFILE.OBJ, XMFILE.OBJ, S3MFILE.OBJ, + MODFILE.OBJ, IOFILE.OBJ, MODENG.OBJ, NONDRV.OBJ, + MIXDRV.OBJ, _MIXDRV.OBJ, WINDRV.OBJ +EXPORT AInitialize.100, + AGetVersion.101, + AGetAudioNumDevs.102, + AGetAudioDevCaps.103, + AGetErrorText.104, + APingAudio.105, + AOpenAudio.106, + ACloseAudio.107, + AUpdateAudio.108, + AOpenVoices.109, + ACloseVoices.110, + ASetAudioCallback.111, + ASetAudioTimerProc.112, + ASetAudioTimerRate.113, + AGetAudioDataAvail.114, + ACreateAudioData.115, + ADestroyAudioData.116, + AWriteAudioData.117, + ACreateAudioVoice.118, + ADestroyAudioVoice.119, + APlayVoice.120, + APrimeVoice.121, + AStartVoice.122, + AStopVoice.123, + ASetVoicePosition.124, + ASetVoiceFrequency.125, + ASetVoiceVolume.126, + ASetVoicePanning.127, + AGetVoicePosition.128, + AGetVoiceFrequency.129, + AGetVoiceVolume.130, + AGetVoicePanning.131, + AGetVoiceStatus.132, + APlayModule.133, + AStopModule.134, + APauseModule.135, + AResumeModule.136, + ASetModuleVolume.137, + ASetModulePosition.138, + AGetModuleVolume.139, + AGetModulePosition.140, + AGetModuleStatus.141, + ASetModuleCallback.146, + ALoadModuleFile.142, + AFreeModuleFile.143, + ALoadWaveFile.144, + AFreeWaveFile.145, + AGetModuleTrack.147 + ASetAudioMixerValue.148 + AUpdateAudioEx.149 diff --git a/seal-hack/src/_mixdrv.S b/seal-hack/src/_mixdrv.S new file mode 100644 index 0000000..b043bef --- /dev/null +++ b/seal-hack/src/_mixdrv.S @@ -0,0 +1,2202 @@ +/* + * $Id: _mixdrv.S 1.8 1996/08/15 02:33:23 chasan released $ + * 1.9 1998/10/25 15:46:38 chasan released (BeOS port) + * + * Low-level assembly resamplation and quantization routines. + * Optimized for superscalar architecture of Pentium processors. + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + + .file "_mixdrv" + +/* assembly linkage macros */ +#ifdef __LINUX__ +#define __ASSEMBLY__ +#include +#else +#ifdef __BEOS__ +#define ALIGN .align 4,0x90 +#define SYMBOL_NAME(name) name +#define SYMBOL_NAME_LABEL(name) name##: +#define ENTRY(name) .globl SYMBOL_NAME(name); ALIGN; SYMBOL_NAME_LABEL(name) +#else +#define ALIGN .align 4,0x90 +#define SYMBOL_NAME(name) _##name +#define SYMBOL_NAME_LABEL(name) _##name##: +#define ENTRY(name) .globl SYMBOL_NAME(name); ALIGN; SYMBOL_NAME_LABEL(name) +#endif +#endif + +/* voice structure field offsets */ +DATA = 0x00 /* data pointer */ +ACCUM = 0x04 /* accumulator */ +PITCH = 0x08 /* pitch shift */ +LOOPSTART = 0x0C /* loop start point */ +LOOPEND = 0x10 /* loop end point */ +VOLUME = 0x14 /* volume */ +PANNING = 0x15 /* panning */ +CONTROL = 0x16 /* control bits */ +RESERVED = 0x17 /* filter sample data */ + +/* pitch shift accuracy */ +ACCURACY = 12 + + .data + + .globl SYMBOL_NAME(lpVolumeTable) + .globl SYMBOL_NAME(lpFilterTable) + + ALIGN +nCount: .long 0 +nStepLo: .long 0 +nStepHi: .long 0 + + .text + +/* + * VOID QuantAudioData08(LPVOID lpBuffer, LPLONG lpData, UINT nCount) + */ +ENTRY(QuantAudioData08) + pushl %ebp + movl %esp,%ebp + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushl %esi + pushl %edi + movl 0x08(%ebp),%edi + movl 0x0c(%ebp),%esi + movl 0x10(%ebp),%ecx + movl $0x8000,%ebx + movl $0xffff,%edx + decl %edi + ALIGN +1: movl (%esi),%eax /* 5 cycles/sample */ + incl %edi + addl %ebx,%eax + jl 3f + cmp %edx,%eax + jg 4f +2: add $4,%esi + movb %ah,(%edi) + decl %ecx + jg 1b + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + popl %ebp + ret + ALIGN +3: xorl %eax,%eax + jmp 2b + ALIGN +4: movl %edx,%eax + jmp 2b + +/* + * VOID QuantAudioData16(LPVOID lpBuffer, LPLONG lpData, UINT nCount) + */ +ENTRY(QuantAudioData16) + pushl %ebp + movl %esp,%ebp + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushl %esi + pushl %edi + movl 0x08(%ebp),%edi + movl 0x0c(%ebp),%esi + movl 0x10(%ebp),%ecx + movl $-32768,%ebx + movl $+32767,%edx + subl $2,%edi + ALIGN +1: movl (%esi),%eax /* 5 cycles/sample */ + addl $2,%edi + cmpl %ebx,%eax + jl 3f + cmpl %edx,%eax + jg 4f +2: addl $4,%esi + movw %ax,(%edi) + decl %ecx + jg 1b + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + popl %ebp + ret + ALIGN +3: movl %ebx,%eax + jmp 2b + ALIGN +4: movl %edx,%eax + jmp 2b + + +/*------------------------- 8 bit mixing routines --------------------------*/ + +/* + * VOID MixAudioData08M(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) + */ +ENTRY(MixAudioData08M) + pushl %ebp + movl %esp,%ebp + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushl %esi + pushl %edi + + movl 0x0C(%ebp),%ecx /* get parameters */ + movl 0x08(%ebp),%edi + movl 0x10(%ebp),%esi + +__MixAudioData08M: + movl %ecx,nCount /* save counter */ + pushl %esi + movl ACCUM(%esi),%ecx /* get accumulator */ + movl PITCH(%esi),%ebp /* get pitch */ + movzbl VOLUME(%esi),%ebx /* get volume */ + movl DATA(%esi),%esi /* get data address */ + shll $10,%ebx /* get table offset */ + pushl %esi + movl %ecx,%eax /* get volume table address */ + addl SYMBOL_NAME(lpVolumeTable),%ebx /* accum to 32.32 fixed-point */ + sarl $ACCURACY,%eax /* pitch to 32.32 fixed-point */ + shrl $2,%ebx + shll $(32-ACCURACY),%ecx + movl %ebp,%edx + addl %eax,%esi + sarl $ACCURACY,%edx + shll $(32-ACCURACY),%ebp + mov %edx,nStepHi + + mov (%esi),%bl /* get first sample, and */ + movl nStepHi,%edx /* advance one step */ + addl %ebp,%ecx + adcl %edx,%esi + + movl nCount,%eax /* jump into the inner */ + movl %eax,%edx /* of the unrolled loop */ + andl $0x0F,%eax + shrl $4,%edx + leal -0x40(%edi,%eax,4),%edi + movl %edx,nCount + jmpl *18f(,%eax,4) + +#define RESAMPLE(OFF) \ + movl OFF(%edi),%edx; \ + movl (,%ebx,4),%eax; \ + addl %edx,%eax; \ + addl %ebp,%ecx; \ + movb (%esi),%bl; \ + movl nStepHi,%edx; \ + adcl %edx,%esi; \ + movl %eax,OFF(%edi); + + ALIGN +1: RESAMPLE(0x00) /* 4 cycles/sample */ +2: RESAMPLE(0x04) +3: RESAMPLE(0x08) +4: RESAMPLE(0x0C) +5: RESAMPLE(0x10) +6: RESAMPLE(0x14) +7: RESAMPLE(0x18) +8: RESAMPLE(0x1C) +9: RESAMPLE(0x20) +10: RESAMPLE(0x24) +11: RESAMPLE(0x28) +12: RESAMPLE(0x2C) +13: RESAMPLE(0x30) +14: RESAMPLE(0x34) +15: RESAMPLE(0x38) +16: RESAMPLE(0x3C) +17: addl $0x40,%edi + decl nCount + jge 1b + +#undef RESAMPLE + + movl nStepHi,%eax /* go back one step */ + subl %ebp,%ecx + sbbl %eax,%esi + popl %eax + subl %eax,%esi /* get accumulator */ + shrdl $(32-ACCURACY),%esi,%ecx + popl %esi + movl %ecx,ACCUM(%esi) /* save accumulator */ + movb %bl,RESERVED(%esi) /* save last sample */ + + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + popl %ebp + ret + + ALIGN +18: .long 17b + .long 16b + .long 15b + .long 14b + .long 13b + .long 12b + .long 11b + .long 10b + .long 9b + .long 8b + .long 7b + .long 6b + .long 5b + .long 4b + .long 3b + .long 2b + + +/* + * VOID MixAudioData08S(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) + */ +ENTRY(MixAudioData08S) + pushl %ebp + movl %esp,%ebp + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushl %esi + pushl %edi + + movl 0x08(%ebp),%edi /* get parameters */ + movl 0x0C(%ebp),%ecx + movl 0x10(%ebp),%esi + +__MixAudioData08S: + movb PANNING(%esi),%al /* select panning routine */ + cmpb $0x10,%al + jb MixAudioLeft08S /* full left panned? */ + cmpb $0x78,%al + jb MixAudioPan08S /* left panned? */ + cmpb $0x88,%al + jb MixAudioMiddle08S /* middle panned? */ + cmpb $0xF0,%al + jae MixAudioRight08S /* full right panned? */ + + +/* + * 8-bit general stereo mixing routine + */ + ALIGN +MixAudioPan08S: + movl %ecx,nCount /* save counter */ + pushl %esi + movl ACCUM(%esi),%ebp /* get accumulator */ + movl PITCH(%esi),%edx /* get pitch */ + movzbl VOLUME(%esi),%ebx /* get volume */ + movzbl PANNING(%esi),%ecx /* get panning */ + movl DATA(%esi),%esi /* get data pointer */ + + pushl %esi + imull %ebx,%ecx /* get volume tables */ + shrl $8,%ecx + subl %ecx,%ebx + shll $10,%ebx + shll $10,%ecx + addl SYMBOL_NAME(lpVolumeTable),%ebx + addl SYMBOL_NAME(lpVolumeTable),%ecx + shrl $2,%ebx + shrl $2,%ecx + + movl %ebp,%eax /* accum to 32.32 fixed point */ + sarl $ACCURACY,%eax + shll $(32-ACCURACY),%ebp + addl %eax,%esi + + movl %edx,%eax /* pitch to 32.32 fixed point */ + sarl $ACCURACY,%edx + shll $(32-ACCURACY),%eax + movl %eax,nStepLo + movl %edx,nStepHi + + movb (%esi),%bl /* get first sample, and */ + addl %eax,%ebp /* advance one step */ + adcl %edx,%esi + movb %bl,%cl + + movl nCount,%eax /* jump into the inner */ + movl %eax,%edx /* of the unrolled loop */ + andl $0x0F,%eax + shrl $4,%edx + leal -0x80(%edi,%eax,8),%edi + movl %edx,nCount + jmpl *18f(,%eax,4) + +#define RESAMPLE(OFF) \ + movl (,%ebx,4),%eax; \ + movl OFF+0(%edi),%edx; \ + addl %edx,%eax; \ + movl OFF+4(%edi),%edx; \ + movl %eax,OFF+0(%edi); \ + movl (,%ecx,4),%eax; \ + addl %edx,%eax; \ + movb (%esi),%bl; \ + movl %eax,OFF+4(%edi); \ + movl nStepLo,%eax; \ + addl %eax,%ebp; \ + movl nStepHi,%edx; \ + adcl %edx,%esi; \ + movb %bl,%cl; + + ALIGN +1: RESAMPLE(0x00) /* 7 cycles/sample */ +2: RESAMPLE(0x08) +3: RESAMPLE(0x10) +4: RESAMPLE(0x18) +5: RESAMPLE(0x20) +6: RESAMPLE(0x28) +7: RESAMPLE(0x30) +8: RESAMPLE(0x38) +9: RESAMPLE(0x40) +10: RESAMPLE(0x48) +11: RESAMPLE(0x50) +12: RESAMPLE(0x58) +13: RESAMPLE(0x60) +14: RESAMPLE(0x68) +15: RESAMPLE(0x70) +16: RESAMPLE(0x78) +17: addl $0x80,%edi + decl nCount + jge 1b + +#undef RESAMPLE + + movl nStepLo,%eax /* go back one step */ + movl nStepHi,%edx + subl %eax,%ebp + sbbl %edx,%esi + popl %eax /* get accumulator */ + subl %eax,%esi + shrdl $(32-ACCURACY),%esi,%ebp + popl %esi + movl %ebp,ACCUM(%esi) /* save accumulator */ + movb %bl,RESERVED(%esi) /* save last sample */ + + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + popl %ebp + ret + + ALIGN +18: .long 17b + .long 16b + .long 15b + .long 14b + .long 13b + .long 12b + .long 11b + .long 10b + .long 9b + .long 8b + .long 7b + .long 6b + .long 5b + .long 4b + .long 3b + .long 2b + +/* + * 8-bit full right stereo mixing routine + */ + ALIGN +MixAudioRight08S: + addl $4,%edi + +/* + * 8-bit full left stereo mixing routine + */ + ALIGN +MixAudioLeft08S: + movl %ecx,nCount /* save counter */ + pushl %esi + movl ACCUM(%esi),%ecx /* get accumulator */ + movl PITCH(%esi),%ebp /* get pitch */ + movzbl VOLUME(%esi),%ebx /* get volume */ + movl DATA(%esi),%esi /* get data address */ + shll $10,%ebx /* get table offset */ + pushl %esi + movl %ecx,%eax /* get volume table address */ + addl SYMBOL_NAME(lpVolumeTable),%ebx /* accum to 32.32 fixed-point */ + sarl $ACCURACY,%eax /* pitch to 32.32 fixed-point */ + shrl $2,%ebx + shll $(32-ACCURACY),%ecx + movl %ebp,%edx + addl %eax,%esi + sarl $ACCURACY,%edx + shll $(32-ACCURACY),%ebp + mov %edx,nStepHi + + mov (%esi),%bl /* get first sample, and */ + movl nStepHi,%edx /* advance one step */ + addl %ebp,%ecx + adcl %edx,%esi + + movl nCount,%eax /* jump into the inner */ + movl %eax,%edx /* of the unrolled loop */ + andl $0x0F,%eax + shrl $4,%edx + leal -0x80(%edi,%eax,8),%edi + movl %edx,nCount + jmpl *18f(,%eax,4) + +#define RESAMPLE(OFF) \ + movl OFF(%edi),%edx; \ + movl (,%ebx,4),%eax; \ + addl %edx,%eax; \ + addl %ebp,%ecx; \ + movb (%esi),%bl; \ + movl nStepHi,%edx; \ + adcl %edx,%esi; \ + movl %eax,OFF(%edi); + + ALIGN +1: RESAMPLE(0x00) /* 4 cycles/sample */ +2: RESAMPLE(0x08) +3: RESAMPLE(0x10) +4: RESAMPLE(0x18) +5: RESAMPLE(0x20) +6: RESAMPLE(0x28) +7: RESAMPLE(0x30) +8: RESAMPLE(0x38) +9: RESAMPLE(0x40) +10: RESAMPLE(0x48) +11: RESAMPLE(0x50) +12: RESAMPLE(0x58) +13: RESAMPLE(0x60) +14: RESAMPLE(0x68) +15: RESAMPLE(0x70) +16: RESAMPLE(0x78) +17: addl $0x80,%edi + decl nCount + jge 1b + +#undef RESAMPLE + + movl nStepHi,%eax /* go back one step */ + subl %ebp,%ecx + sbbl %eax,%esi + popl %eax + subl %eax,%esi /* get accumulator */ + shrdl $(32-ACCURACY),%esi,%ecx + popl %esi + movl %ecx,ACCUM(%esi) /* save accum */ + movb %bl,RESERVED(%esi) /* save last sample */ + + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + popl %ebp + ret + + ALIGN +18: .long 17b + .long 16b + .long 15b + .long 14b + .long 13b + .long 12b + .long 11b + .long 10b + .long 9b + .long 8b + .long 7b + .long 6b + .long 5b + .long 4b + .long 3b + .long 2b + +/* + * 8-bit middle stereo mixing routine + */ + ALIGN +MixAudioMiddle08S: + movl %ecx,nCount /* save counter */ + pushl %esi + movl ACCUM(%esi),%ecx /* get accumulator */ + movl PITCH(%esi),%ebp /* get pitch */ + movzbl VOLUME(%esi),%ebx /* get volume */ + movl DATA(%esi),%esi /* get data address */ + shrl $1,%ebx + shll $10,%ebx /* get table offset */ + pushl %esi + movl %ecx,%eax /* get volume table address */ + addl SYMBOL_NAME(lpVolumeTable),%ebx /* accum to 32.32 fixed-point */ + sarl $ACCURACY,%eax /* pitch to 32.32 fixed-point */ + shrl $2,%ebx + shll $(32-ACCURACY),%ecx + movl %ebp,%edx + addl %eax,%esi + sarl $ACCURACY,%edx + shll $(32-ACCURACY),%ebp + mov %edx,nStepHi + + mov (%esi),%bl /* get first sample, and */ + movl nStepHi,%edx /* advance one step */ + addl %ebp,%ecx + adcl %edx,%esi + + movl nCount,%eax /* jump into the inner */ + movl %eax,%edx /* of the unrolled loop */ + andl $0x0F,%eax + shrl $4,%edx + leal -0x80(%edi,%eax,8),%edi + movl %edx,nCount + jmpl *18f(,%eax,4) + +#define RESAMPLE(OFF) \ + movl OFF+0(%edi),%edx; \ + movl (,%ebx,4),%eax; \ + addl %eax,%edx; \ + movb (%esi),%bl; \ + movl %edx,OFF+0(%edi); \ + movl OFF+4(%edi),%edx; \ + addl %eax,%edx; \ + movl nStepHi,%eax; \ + movl %edx,OFF+4(%edi); \ + addl %ebp,%ecx; \ + adcl %eax,%esi; + + ALIGN +1: RESAMPLE(0x00) /* 6 cycles/sample */ +2: RESAMPLE(0x08) +3: RESAMPLE(0x10) +4: RESAMPLE(0x18) +5: RESAMPLE(0x20) +6: RESAMPLE(0x28) +7: RESAMPLE(0x30) +8: RESAMPLE(0x38) +9: RESAMPLE(0x40) +10: RESAMPLE(0x48) +11: RESAMPLE(0x50) +12: RESAMPLE(0x58) +13: RESAMPLE(0x60) +14: RESAMPLE(0x68) +15: RESAMPLE(0x70) +16: RESAMPLE(0x78) +17: addl $0x80,%edi + decl nCount + jge 1b + +#undef RESAMPLE + + movl nStepHi,%eax /* go back one step */ + subl %ebp,%ecx + sbbl %eax,%esi + popl %eax + subl %eax,%esi /* get accumulator */ + shrdl $(32-ACCURACY),%esi,%ecx + popl %esi + movl %ecx,ACCUM(%esi) /* save accum */ + movb %bl,RESERVED(%esi) /* save last sample */ + + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + popl %ebp + ret + + ALIGN +18: .long 17b + .long 16b + .long 15b + .long 14b + .long 13b + .long 12b + .long 11b + .long 10b + .long 9b + .long 8b + .long 7b + .long 6b + .long 5b + .long 4b + .long 3b + .long 2b + + +/* + * VOID MixAudioData08MI(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) + */ +ENTRY(MixAudioData08MI) + pushl %ebp + movl %esp,%ebp + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushl %esi + pushl %edi + + movl 0x0C(%ebp),%ecx /* get parameters */ + movl 0x08(%ebp),%edi + movl 0x10(%ebp),%esi + + movl PITCH(%esi),%eax /* select mixing routine */ + cmpl $(+1 << ACCURACY),%eax + jge __MixAudioData08M + cmpl $(-1 << ACCURACY),%eax + jle __MixAudioData08M + + movl %ecx,nCount /* save counter */ + pushl %esi + movl ACCUM(%esi),%ebp /* get accumulator */ + movl PITCH(%esi),%ecx /* get pitch */ + movzbl VOLUME(%esi),%ebx /* get volume */ + movb RESERVED(%esi),%dl /* get last sample */ + movl DATA(%esi),%esi /* get data address */ + pushl %esi + + shll $10,%ebx /* get volume table address */ + addl SYMBOL_NAME(lpVolumeTable),%ebx + shrl $2,%ebx + movb %dl,%bl /* save sample for filtering */ + + movl %ebp,%eax /* convert accumulator */ + sarl $ACCURACY,%eax + shll $(32-ACCURACY),%ebp + addl %eax,%esi + + movl %ecx,%edx /* get filter table address */ + movl %ecx,%eax /* and convert pitch */ + shll $(32-ACCURACY),%ecx + sarl $ACCURACY,%eax + movl %eax,nStepHi + testl %edx,%edx + jge 1f + neg %edx +1: shrl $(ACCURACY-5),%edx + shll $8,%edx + addl SYMBOL_NAME(lpFilterTable),%edx + + movl nCount,%eax /* jump inside of the loop */ + andl $0x0F,%eax + leal -0x40(%edi,%eax,4),%edi + shrl $4,nCount + jmpl *18f(,%eax,4) + +#define RESAMPLE(OFF) \ + movb %bl,%dl; \ + subb (%edx),%bl; \ + movb (%esi),%dl; \ + movb (%edx),%dl; \ + movl nStepHi,%eax; \ + addb %dl,%bl; \ + addl %ecx,%ebp; \ + adcl %eax,%esi; \ + movl (,%ebx,4),%eax; \ + addl %eax,OFF(%edi); + + ALIGN +1: RESAMPLE(0x00) /* ~11 cycles/sample */ +2: RESAMPLE(0x04) +3: RESAMPLE(0x08) +4: RESAMPLE(0x0C) +5: RESAMPLE(0x10) +6: RESAMPLE(0x14) +7: RESAMPLE(0x18) +8: RESAMPLE(0x1C) +9: RESAMPLE(0x20) +10: RESAMPLE(0x24) +11: RESAMPLE(0x28) +12: RESAMPLE(0x2C) +13: RESAMPLE(0x30) +14: RESAMPLE(0x34) +15: RESAMPLE(0x38) +16: RESAMPLE(0x3C) +17: addl $0x40,%edi + decl nCount + jge 1b + +#undef RESAMPLE + + popl %eax + subl %eax,%esi /* get and save accumulator */ + shrdl $(32-ACCURACY),%esi,%ebp + popl %esi + movl %ebp,ACCUM(%esi) + movb %bl,RESERVED(%esi) /* save sample for filtering */ + + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + popl %ebp + ret + + ALIGN +18: .long 17b + .long 16b + .long 15b + .long 14b + .long 13b + .long 12b + .long 11b + .long 10b + .long 9b + .long 8b + .long 7b + .long 6b + .long 5b + .long 4b + .long 3b + .long 2b + + +/* + * VOID MixAudioData08SI(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) + */ +ENTRY(MixAudioData08SI) + pushl %ebp + movl %esp,%ebp + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushl %esi + pushl %edi + + movl 0x08(%ebp),%edi /* get parameters */ + movl 0x0C(%ebp),%ecx + movl 0x10(%ebp),%esi + + movl PITCH(%esi),%eax /* select mixing routine */ + cmpl $(+1 << ACCURACY),%eax + jge __MixAudioData08S + cmpl $(-1 << ACCURACY),%eax + jle __MixAudioData08S + + movb PANNING(%esi),%al /* select panning routine */ + cmpb $0x10,%al + jb MixAudioLeft08SI /* full left panned? */ + cmpb $0x78,%al + jb MixAudioPan08SI /* left panned? */ + cmpb $0x88,%al + jb MixAudioMiddle08SI /* middle panned? */ + cmpb $0xF0,%al + jae MixAudioRight08SI /* full right panned? */ + + +/* + * 8-bit general stereo mixing routine + */ + ALIGN +MixAudioPan08SI: + movl %ecx,nCount /* save counter */ + pushl %esi + movl ACCUM(%esi),%ebp /* get accumulator */ + movl PITCH(%esi),%edx /* get pitch */ + movzbl VOLUME(%esi),%ebx /* get volume */ + movzbl PANNING(%esi),%ecx /* get panning */ + movb RESERVED(%esi),%al /* get last sample */ + movl DATA(%esi),%esi /* get data pointer */ + + pushl %esi + imull %ebx,%ecx /* get volume tables */ + shrl $8,%ecx + subl %ecx,%ebx + shll $10,%ebx + shll $10,%ecx + addl SYMBOL_NAME(lpVolumeTable),%ebx + addl SYMBOL_NAME(lpVolumeTable),%ecx + shrl $2,%ebx + shrl $2,%ecx + movb %al,%bl /* save sample for filtering */ + + movl %ebp,%eax /* accum to 32.32 fixed point */ + sarl $ACCURACY,%eax + shll $(32-ACCURACY),%ebp + addl %eax,%esi + + movl %edx,%eax /* pitch to 32.32 fixed point */ + testl %edx,%edx + jge 1f + neg %edx +1: shrl $(ACCURACY-5),%edx + shll $8,%edx + addl SYMBOL_NAME(lpFilterTable),%edx + pushl %eax + shll $(32-ACCURACY),%eax + movl %eax,nStepLo + popl %eax + sarl $ACCURACY,%eax + movl %eax,nStepHi + + movl nCount,%eax /* jump inside of the loop */ + andl $0x0F,%eax + leal -0x80(%edi,%eax,8),%edi + shrl $4,nCount + jmpl *18f(,%eax,4) + +#define RESAMPLE(OFF) \ + movb %bl,%dl; \ + subb (%edx),%bl; \ + movb (%esi),%dl; \ + movb (%edx),%dl; \ + movl nStepLo,%eax; \ + addb %dl,%bl; \ + addl %eax,%ebp; \ + movb %bl,%cl; \ + movl nStepHi,%eax; \ + adcl %eax,%esi; \ + movl (,%ebx,4),%eax; \ + addl %eax,OFF(%edi); \ + movl (,%ecx,4),%eax; \ + addl %eax,OFF+4(%edi); + + ALIGN +1: RESAMPLE(0x00) /* ~15 cycles/sample */ +2: RESAMPLE(0x08) +3: RESAMPLE(0x10) +4: RESAMPLE(0x18) +5: RESAMPLE(0x20) +6: RESAMPLE(0x28) +7: RESAMPLE(0x30) +8: RESAMPLE(0x38) +9: RESAMPLE(0x40) +10: RESAMPLE(0x48) +11: RESAMPLE(0x50) +12: RESAMPLE(0x58) +13: RESAMPLE(0x60) +14: RESAMPLE(0x68) +15: RESAMPLE(0x70) +16: RESAMPLE(0x78) +17: addl $0x80,%edi + decl nCount + jge 1b + +#undef RESAMPLE + + popl %eax /* get accumulator */ + subl %eax,%esi + shrdl $(32-ACCURACY),%esi,%ebp + popl %esi + movl %ebp,ACCUM(%esi) /* save accumulator */ + movb %bl,RESERVED(%esi) /* save last sample */ + + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + popl %ebp + ret + + ALIGN +18: .long 17b + .long 16b + .long 15b + .long 14b + .long 13b + .long 12b + .long 11b + .long 10b + .long 9b + .long 8b + .long 7b + .long 6b + .long 5b + .long 4b + .long 3b + .long 2b + +/* + * 8-bit full right stereo mixing routine + */ + ALIGN +MixAudioRight08SI: + addl $4,%edi + +/* + * 8-bit full left stereo mixing routine + */ + ALIGN +MixAudioLeft08SI: + movl %ecx,nCount /* save counter */ + pushl %esi + movl ACCUM(%esi),%ebp /* get accumulator */ + movl PITCH(%esi),%ecx /* get pitch */ + movzbl VOLUME(%esi),%ebx /* get volume */ + movb RESERVED(%esi),%dl /* get last sample */ + movl DATA(%esi),%esi /* get data address */ + pushl %esi + + shll $10,%ebx /* get volume table address */ + addl SYMBOL_NAME(lpVolumeTable),%ebx + shrl $2,%ebx + movb %dl,%bl /* save sample for filtering */ + + movl %ebp,%eax /* convert accumulator */ + sarl $ACCURACY,%eax + shll $(32-ACCURACY),%ebp + addl %eax,%esi + + movl %ecx,%edx /* get filter table address */ + movl %ecx,%eax /* and convert pitch */ + sarl $ACCURACY,%eax + shll $(32-ACCURACY),%ecx + movl %eax,nStepHi + testl %edx,%edx + jge 1f + neg %edx +1: shrl $(ACCURACY-5),%edx + shll $8,%edx + addl SYMBOL_NAME(lpFilterTable),%edx + + movl nCount,%eax /* jump inside of the loop */ + andl $0x0F,%eax + leal -0x80(%edi,%eax,8),%edi + shrl $4,nCount + jmpl *18f(,%eax,4) + +#define RESAMPLE(OFF) \ + movb %bl,%dl; \ + subb (%edx),%bl; \ + movb (%esi),%dl; \ + movb (%edx),%dl; \ + movl nStepHi,%eax; \ + addb %dl,%bl; \ + addl %ecx,%ebp; \ + adcl %eax,%esi; \ + movl (,%ebx,4),%eax; \ + addl %eax,OFF(%edi); + + ALIGN +1: RESAMPLE(0x00) /* ~11 cycles/sample */ +2: RESAMPLE(0x08) +3: RESAMPLE(0x10) +4: RESAMPLE(0x18) +5: RESAMPLE(0x20) +6: RESAMPLE(0x28) +7: RESAMPLE(0x30) +8: RESAMPLE(0x38) +9: RESAMPLE(0x40) +10: RESAMPLE(0x48) +11: RESAMPLE(0x50) +12: RESAMPLE(0x58) +13: RESAMPLE(0x60) +14: RESAMPLE(0x68) +15: RESAMPLE(0x70) +16: RESAMPLE(0x78) +17: addl $0x80,%edi + decl nCount + jge 1b + +#undef RESAMPLE + + popl %eax + subl %eax,%esi /* get and save accumulator */ + shrdl $(32-ACCURACY),%esi,%ebp + popl %esi + movl %ebp,ACCUM(%esi) + movb %bl,RESERVED(%esi) /* save sample for filtering */ + + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + popl %ebp + ret + + ALIGN +18: .long 17b + .long 16b + .long 15b + .long 14b + .long 13b + .long 12b + .long 11b + .long 10b + .long 9b + .long 8b + .long 7b + .long 6b + .long 5b + .long 4b + .long 3b + .long 2b + +/* + * 8-bit middle stereo mixing routine + */ + ALIGN +MixAudioMiddle08SI: + movl %ecx,nCount /* save counter */ + pushl %esi + movl ACCUM(%esi),%ebp /* get accumulator */ + movl PITCH(%esi),%ecx /* get pitch */ + movzbl VOLUME(%esi),%ebx /* get volume */ + movb RESERVED(%esi),%dl /* get last sample */ + movl DATA(%esi),%esi /* get data address */ + pushl %esi + + shrl $1,%ebx /* get volume table address */ + shll $10,%ebx + addl SYMBOL_NAME(lpVolumeTable),%ebx + shrl $2,%ebx + movb %dl,%bl /* save sample for filtering */ + + movl %ebp,%eax /* convert accumulator */ + sarl $ACCURACY,%eax + shll $(32-ACCURACY),%ebp + addl %eax,%esi + + movl %ecx,%edx /* get filter table address */ + movl %ecx,%eax /* and convert pitch */ + sarl $ACCURACY,%eax + shll $(32-ACCURACY),%ecx + movl %eax,nStepHi + testl %edx,%edx + jge 1f + neg %edx +1: shrl $(ACCURACY-5),%edx + shll $8,%edx + addl SYMBOL_NAME(lpFilterTable),%edx + + movl nCount,%eax /* jump inside of the loop */ + andl $0x0F,%eax + leal -0x80(%edi,%eax,8),%edi + shrl $4,nCount + jmpl *18f(,%eax,4) + +#define RESAMPLE(OFF) \ + movb %bl,%dl; \ + subb (%edx),%bl; \ + movb (%esi),%dl; \ + movb (%edx),%dl; \ + movl nStepHi,%eax; \ + addb %dl,%bl; \ + addl %ecx,%ebp; \ + adcl %eax,%esi; \ + movl (,%ebx,4),%eax; \ + addl %eax,OFF(%edi); \ + addl %eax,OFF+4(%edi); + + ALIGN +1: RESAMPLE(0x00) /* ~14 cycles/sample */ +2: RESAMPLE(0x08) +3: RESAMPLE(0x10) +4: RESAMPLE(0x18) +5: RESAMPLE(0x20) +6: RESAMPLE(0x28) +7: RESAMPLE(0x30) +8: RESAMPLE(0x38) +9: RESAMPLE(0x40) +10: RESAMPLE(0x48) +11: RESAMPLE(0x50) +12: RESAMPLE(0x58) +13: RESAMPLE(0x60) +14: RESAMPLE(0x68) +15: RESAMPLE(0x70) +16: RESAMPLE(0x78) +17: addl $0x80,%edi + decl nCount + jge 1b + +#undef RESAMPLE + + popl %eax + subl %eax,%esi /* get and save accumulator */ + shrdl $(32-ACCURACY),%esi,%ebp + popl %esi + movl %ebp,ACCUM(%esi) + movb %bl,RESERVED(%esi) /* save sample for filtering */ + + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + popl %ebp + ret + + ALIGN +18: .long 17b + .long 16b + .long 15b + .long 14b + .long 13b + .long 12b + .long 11b + .long 10b + .long 9b + .long 8b + .long 7b + .long 6b + .long 5b + .long 4b + .long 3b + .long 2b + +/*---------------------- fake 16 bit mixing routines -----------------------*/ + +/* + * VOID MixAudioData16M(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) + */ +ENTRY(MixAudioData16M) + pushl %ebp + movl %esp,%ebp + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushl %esi + pushl %edi + + movl 0x0C(%ebp),%ecx /* get parameters */ + movl 0x08(%ebp),%edi + movl 0x10(%ebp),%esi + +__MixAudioData16M: + movl %ecx,nCount /* save counter */ + pushl %esi + movl ACCUM(%esi),%ecx /* get accumulator */ + movl PITCH(%esi),%ebp /* get pitch */ + movzbl VOLUME(%esi),%ebx /* get volume */ + movl DATA(%esi),%esi /* get data address */ + shrl $1,%esi + shll $10,%ebx /* get table offset */ + pushl %esi + movl %ecx,%eax /* get volume table address */ + addl SYMBOL_NAME(lpVolumeTable),%ebx /* accum to 32.32 fixed-point */ + sarl $ACCURACY,%eax /* pitch to 32.32 fixed-point */ + shrl $2,%ebx + shll $(32-ACCURACY),%ecx + movl %ebp,%edx + addl %eax,%esi + sarl $ACCURACY,%edx + shll $(32-ACCURACY),%ebp + mov %edx,nStepHi + + mov 1(,%esi,2),%bl /* get first sample, and */ + movl nStepHi,%edx /* advance one step */ + addl %ebp,%ecx + adcl %edx,%esi + + movl nCount,%eax /* jump into the inner */ + movl %eax,%edx /* of the unrolled loop */ + andl $0x0F,%eax + shrl $4,%edx + leal -0x40(%edi,%eax,4),%edi + movl %edx,nCount + jmpl *18f(,%eax,4) + +#define RESAMPLE(OFF) \ + movl OFF(%edi),%edx; \ + movl (,%ebx,4),%eax; \ + addl %edx,%eax; \ + addl %ebp,%ecx; \ + movb 1(,%esi,2),%bl; \ + movl nStepHi,%edx; \ + adcl %edx,%esi; \ + movl %eax,OFF(%edi); + + ALIGN +1: RESAMPLE(0x00) /* 4 cycles/sample */ +2: RESAMPLE(0x04) +3: RESAMPLE(0x08) +4: RESAMPLE(0x0C) +5: RESAMPLE(0x10) +6: RESAMPLE(0x14) +7: RESAMPLE(0x18) +8: RESAMPLE(0x1C) +9: RESAMPLE(0x20) +10: RESAMPLE(0x24) +11: RESAMPLE(0x28) +12: RESAMPLE(0x2C) +13: RESAMPLE(0x30) +14: RESAMPLE(0x34) +15: RESAMPLE(0x38) +16: RESAMPLE(0x3C) +17: addl $0x40,%edi + decl nCount + jge 1b + +#undef RESAMPLE + + movl nStepHi,%eax /* go back one step */ + subl %ebp,%ecx + sbbl %eax,%esi + popl %eax + subl %eax,%esi /* get accumulator */ + shrdl $(32-ACCURACY),%esi,%ecx + popl %esi + movl %ecx,ACCUM(%esi) /* save accumulator */ + movb %bl,RESERVED(%esi) /* save last sample */ + + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + popl %ebp + ret + + ALIGN +18: .long 17b + .long 16b + .long 15b + .long 14b + .long 13b + .long 12b + .long 11b + .long 10b + .long 9b + .long 8b + .long 7b + .long 6b + .long 5b + .long 4b + .long 3b + .long 2b + + +/* + * VOID MixAudioData16S(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) + */ +ENTRY(MixAudioData16S) + pushl %ebp + movl %esp,%ebp + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushl %esi + pushl %edi + + movl 0x08(%ebp),%edi /* get parameters */ + movl 0x0C(%ebp),%ecx + movl 0x10(%ebp),%esi + +__MixAudioData16S: + movb PANNING(%esi),%al /* select panning routine */ + cmpb $0x10,%al + jb MixAudioLeft16S /* full left panned? */ + cmpb $0x78,%al + jb MixAudioPan16S /* left panned? */ + cmpb $0x88,%al + jb MixAudioMiddle16S /* middle panned? */ + cmpb $0xF0,%al + jae MixAudioRight16S /* full right panned? */ + + +/* + * 16-bit general stereo mixing routine + */ + ALIGN +MixAudioPan16S: + movl %ecx,nCount /* save counter */ + pushl %esi + movl ACCUM(%esi),%ebp /* get accumulator */ + movl PITCH(%esi),%edx /* get pitch */ + movzbl VOLUME(%esi),%ebx /* get volume */ + movzbl PANNING(%esi),%ecx /* get panning */ + movl DATA(%esi),%esi /* get data pointer */ + shrl $1,%esi + + pushl %esi + imull %ebx,%ecx /* get volume tables */ + shrl $8,%ecx + subl %ecx,%ebx + shll $10,%ebx + shll $10,%ecx + addl SYMBOL_NAME(lpVolumeTable),%ebx + addl SYMBOL_NAME(lpVolumeTable),%ecx + shrl $2,%ebx + shrl $2,%ecx + + movl %ebp,%eax /* accum to 32.32 fixed point */ + sarl $ACCURACY,%eax + shll $(32-ACCURACY),%ebp + addl %eax,%esi + + movl %edx,%eax /* pitch to 32.32 fixed point */ + sarl $ACCURACY,%edx + shll $(32-ACCURACY),%eax + movl %eax,nStepLo + movl %edx,nStepHi + + movb 1(,%esi,2),%bl /* get first sample, and */ + addl %eax,%ebp /* advance one step */ + adcl %edx,%esi + movb %bl,%cl + + movl nCount,%eax /* jump into the inner */ + movl %eax,%edx /* of the unrolled loop */ + andl $0x0F,%eax + shrl $4,%edx + leal -0x80(%edi,%eax,8),%edi + movl %edx,nCount + jmpl *18f(,%eax,4) + +#define RESAMPLE(OFF) \ + movl (,%ebx,4),%eax; \ + movl OFF+0(%edi),%edx; \ + addl %edx,%eax; \ + movl OFF+4(%edi),%edx; \ + movl %eax,OFF+0(%edi); \ + movl (,%ecx,4),%eax; \ + addl %edx,%eax; \ + movb 1(,%esi,2),%bl; \ + movl %eax,OFF+4(%edi); \ + movl nStepLo,%eax; \ + addl %eax,%ebp; \ + movl nStepHi,%edx; \ + adcl %edx,%esi; \ + movb %bl,%cl; + + ALIGN +1: RESAMPLE(0x00) /* 7 cycles/sample */ +2: RESAMPLE(0x08) +3: RESAMPLE(0x10) +4: RESAMPLE(0x18) +5: RESAMPLE(0x20) +6: RESAMPLE(0x28) +7: RESAMPLE(0x30) +8: RESAMPLE(0x38) +9: RESAMPLE(0x40) +10: RESAMPLE(0x48) +11: RESAMPLE(0x50) +12: RESAMPLE(0x58) +13: RESAMPLE(0x60) +14: RESAMPLE(0x68) +15: RESAMPLE(0x70) +16: RESAMPLE(0x78) +17: addl $0x80,%edi + decl nCount + jge 1b + +#undef RESAMPLE + + movl nStepLo,%eax /* go back one step */ + movl nStepHi,%edx + subl %eax,%ebp + sbbl %edx,%esi + popl %eax /* get accumulator */ + subl %eax,%esi + shrdl $(32-ACCURACY),%esi,%ebp + popl %esi + movl %ebp,ACCUM(%esi) /* save accumulator */ + movb %bl,RESERVED(%esi) /* save last sample */ + + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + popl %ebp + ret + + ALIGN +18: .long 17b + .long 16b + .long 15b + .long 14b + .long 13b + .long 12b + .long 11b + .long 10b + .long 9b + .long 8b + .long 7b + .long 6b + .long 5b + .long 4b + .long 3b + .long 2b + +/* + * 16-bit full right stereo mixing routine + */ + ALIGN +MixAudioRight16S: + addl $4,%edi + +/* + * 16-bit full left stereo mixing routine + */ + ALIGN +MixAudioLeft16S: + movl %ecx,nCount /* save counter */ + pushl %esi + movl ACCUM(%esi),%ecx /* get accumulator */ + movl PITCH(%esi),%ebp /* get pitch */ + movzbl VOLUME(%esi),%ebx /* get volume */ + movl DATA(%esi),%esi /* get data address */ + shrl $1,%esi + shll $10,%ebx /* get table offset */ + pushl %esi + movl %ecx,%eax /* get volume table address */ + addl SYMBOL_NAME(lpVolumeTable),%ebx /* accum to 32.32 fixed-point */ + sarl $ACCURACY,%eax /* pitch to 32.32 fixed-point */ + shrl $2,%ebx + shll $(32-ACCURACY),%ecx + movl %ebp,%edx + addl %eax,%esi + sarl $ACCURACY,%edx + shll $(32-ACCURACY),%ebp + mov %edx,nStepHi + + mov 1(,%esi,2),%bl /* get first sample, and */ + movl nStepHi,%edx /* advance one step */ + addl %ebp,%ecx + adcl %edx,%esi + + movl nCount,%eax /* jump into the inner */ + movl %eax,%edx /* of the unrolled loop */ + andl $0x0F,%eax + shrl $4,%edx + leal -0x80(%edi,%eax,8),%edi + movl %edx,nCount + jmpl *18f(,%eax,4) + +#define RESAMPLE(OFF) \ + movl OFF(%edi),%edx; \ + movl (,%ebx,4),%eax; \ + addl %edx,%eax; \ + addl %ebp,%ecx; \ + movb 1(,%esi,2),%bl; \ + movl nStepHi,%edx; \ + adcl %edx,%esi; \ + movl %eax,OFF(%edi); + + ALIGN +1: RESAMPLE(0x00) /* 4 cycles/sample */ +2: RESAMPLE(0x08) +3: RESAMPLE(0x10) +4: RESAMPLE(0x18) +5: RESAMPLE(0x20) +6: RESAMPLE(0x28) +7: RESAMPLE(0x30) +8: RESAMPLE(0x38) +9: RESAMPLE(0x40) +10: RESAMPLE(0x48) +11: RESAMPLE(0x50) +12: RESAMPLE(0x58) +13: RESAMPLE(0x60) +14: RESAMPLE(0x68) +15: RESAMPLE(0x70) +16: RESAMPLE(0x78) +17: addl $0x80,%edi + decl nCount + jge 1b + +#undef RESAMPLE + + movl nStepHi,%eax /* go back one step */ + subl %ebp,%ecx + sbbl %eax,%esi + popl %eax + subl %eax,%esi /* get accumulator */ + shrdl $(32-ACCURACY),%esi,%ecx + popl %esi + movl %ecx,ACCUM(%esi) /* save accum */ + movb %bl,RESERVED(%esi) /* save last sample */ + + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + popl %ebp + ret + + ALIGN +18: .long 17b + .long 16b + .long 15b + .long 14b + .long 13b + .long 12b + .long 11b + .long 10b + .long 9b + .long 8b + .long 7b + .long 6b + .long 5b + .long 4b + .long 3b + .long 2b + +/* + * 16-bit middle stereo mixing routine + */ + ALIGN +MixAudioMiddle16S: + movl %ecx,nCount /* save counter */ + pushl %esi + movl ACCUM(%esi),%ecx /* get accumulator */ + movl PITCH(%esi),%ebp /* get pitch */ + movzbl VOLUME(%esi),%ebx /* get volume */ + movl DATA(%esi),%esi /* get data address */ + shrl $1,%esi + shrl $1,%ebx + shll $10,%ebx /* get table offset */ + pushl %esi + movl %ecx,%eax /* get volume table address */ + addl SYMBOL_NAME(lpVolumeTable),%ebx /* accum to 32.32 fixed-point */ + sarl $ACCURACY,%eax /* pitch to 32.32 fixed-point */ + shrl $2,%ebx + shll $(32-ACCURACY),%ecx + movl %ebp,%edx + addl %eax,%esi + sarl $ACCURACY,%edx + shll $(32-ACCURACY),%ebp + mov %edx,nStepHi + + mov 1(,%esi,2),%bl /* get first sample, and */ + movl nStepHi,%edx /* advance one step */ + addl %ebp,%ecx + adcl %edx,%esi + + movl nCount,%eax /* jump into the inner */ + movl %eax,%edx /* of the unrolled loop */ + andl $0x0F,%eax + shrl $4,%edx + leal -0x80(%edi,%eax,8),%edi + movl %edx,nCount + jmpl *18f(,%eax,4) + +#define RESAMPLE(OFF) \ + movl OFF+0(%edi),%edx; \ + movl (,%ebx,4),%eax; \ + addl %eax,%edx; \ + movb 1(,%esi,2),%bl; \ + movl %edx,OFF+0(%edi); \ + movl OFF+4(%edi),%edx; \ + addl %eax,%edx; \ + movl nStepHi,%eax; \ + movl %edx,OFF+4(%edi); \ + addl %ebp,%ecx; \ + adcl %eax,%esi; + + ALIGN +1: RESAMPLE(0x00) /* 6 cycles/sample */ +2: RESAMPLE(0x08) +3: RESAMPLE(0x10) +4: RESAMPLE(0x18) +5: RESAMPLE(0x20) +6: RESAMPLE(0x28) +7: RESAMPLE(0x30) +8: RESAMPLE(0x38) +9: RESAMPLE(0x40) +10: RESAMPLE(0x48) +11: RESAMPLE(0x50) +12: RESAMPLE(0x58) +13: RESAMPLE(0x60) +14: RESAMPLE(0x68) +15: RESAMPLE(0x70) +16: RESAMPLE(0x78) +17: addl $0x80,%edi + decl nCount + jge 1b + +#undef RESAMPLE + + movl nStepHi,%eax /* go back one step */ + subl %ebp,%ecx + sbbl %eax,%esi + popl %eax + subl %eax,%esi /* get accumulator */ + shrdl $(32-ACCURACY),%esi,%ecx + popl %esi + movl %ecx,ACCUM(%esi) /* save accum */ + movb %bl,RESERVED(%esi) /* save last sample */ + + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + popl %ebp + ret + + ALIGN +18: .long 17b + .long 16b + .long 15b + .long 14b + .long 13b + .long 12b + .long 11b + .long 10b + .long 9b + .long 8b + .long 7b + .long 6b + .long 5b + .long 4b + .long 3b + .long 2b + + +/* + * VOID MixAudioData16MI(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) + */ +ENTRY(MixAudioData16MI) + pushl %ebp + movl %esp,%ebp + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushl %esi + pushl %edi + + movl 0x0C(%ebp),%ecx /* get parameters */ + movl 0x08(%ebp),%edi + movl 0x10(%ebp),%esi + + movl PITCH(%esi),%eax /* select mixing routine */ + cmpl $(+1 << ACCURACY),%eax + jge __MixAudioData16M + cmpl $(-1 << ACCURACY),%eax + jle __MixAudioData16M + + movl %ecx,nCount /* save counter */ + pushl %esi + movl ACCUM(%esi),%ebp /* get accumulator */ + movl PITCH(%esi),%ecx /* get pitch */ + movzbl VOLUME(%esi),%ebx /* get volume */ + movb RESERVED(%esi),%dl /* get last sample */ + movl DATA(%esi),%esi /* get data address */ + shrl $1,%esi + pushl %esi + + shll $10,%ebx /* get volume table address */ + addl SYMBOL_NAME(lpVolumeTable),%ebx + shrl $2,%ebx + movb %dl,%bl /* save sample for filtering */ + + movl %ebp,%eax /* convert accumulator */ + sarl $ACCURACY,%eax + shll $(32-ACCURACY),%ebp + addl %eax,%esi + + movl %ecx,%edx /* get filter table address */ + movl %ecx,%eax /* and convert pitch */ + shll $(32-ACCURACY),%ecx + sarl $ACCURACY,%eax + movl %eax,nStepHi + testl %edx,%edx + jge 1f + neg %edx +1: shrl $(ACCURACY-5),%edx + shll $8,%edx + addl SYMBOL_NAME(lpFilterTable),%edx + + movl nCount,%eax /* jump inside of the loop */ + andl $0x0F,%eax + leal -0x40(%edi,%eax,4),%edi + shrl $4,nCount + jmpl *18f(,%eax,4) + +#define RESAMPLE(OFF) \ + movb %bl,%dl; \ + subb (%edx),%bl; \ + movb 1(,%esi,2),%dl; \ + movb (%edx),%dl; \ + movl nStepHi,%eax; \ + addb %dl,%bl; \ + addl %ecx,%ebp; \ + adcl %eax,%esi; \ + movl (,%ebx,4),%eax; \ + addl %eax,OFF(%edi); + + ALIGN +1: RESAMPLE(0x00) /* ~11 cycles/sample */ +2: RESAMPLE(0x04) +3: RESAMPLE(0x08) +4: RESAMPLE(0x0C) +5: RESAMPLE(0x10) +6: RESAMPLE(0x14) +7: RESAMPLE(0x18) +8: RESAMPLE(0x1C) +9: RESAMPLE(0x20) +10: RESAMPLE(0x24) +11: RESAMPLE(0x28) +12: RESAMPLE(0x2C) +13: RESAMPLE(0x30) +14: RESAMPLE(0x34) +15: RESAMPLE(0x38) +16: RESAMPLE(0x3C) +17: addl $0x40,%edi + decl nCount + jge 1b + +#undef RESAMPLE + + popl %eax + subl %eax,%esi /* get and save accumulator */ + shrdl $(32-ACCURACY),%esi,%ebp + popl %esi + movl %ebp,ACCUM(%esi) + movb %bl,RESERVED(%esi) /* save sample for filtering */ + + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + popl %ebp + ret + + ALIGN +18: .long 17b + .long 16b + .long 15b + .long 14b + .long 13b + .long 12b + .long 11b + .long 10b + .long 9b + .long 8b + .long 7b + .long 6b + .long 5b + .long 4b + .long 3b + .long 2b + + +/* + * VOID MixAudioData16SI(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) + */ +ENTRY(MixAudioData16SI) + pushl %ebp + movl %esp,%ebp + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushl %esi + pushl %edi + + movl 0x08(%ebp),%edi /* get parameters */ + movl 0x0C(%ebp),%ecx + movl 0x10(%ebp),%esi + + movl PITCH(%esi),%eax /* select mixing routine */ + cmpl $(+1 << ACCURACY),%eax + jge __MixAudioData16S + cmpl $(-1 << ACCURACY),%eax + jle __MixAudioData16S + + movb PANNING(%esi),%al /* select panning routine */ + cmpb $0x10,%al + jb MixAudioLeft16SI /* full left panned? */ + cmpb $0x78,%al + jb MixAudioPan16SI /* left panned? */ + cmpb $0x88,%al + jb MixAudioMiddle16SI /* middle panned? */ + cmpb $0xF0,%al + jae MixAudioRight16SI /* full right panned? */ + + +/* + * 16-bit general stereo mixing routine + */ + ALIGN +MixAudioPan16SI: + movl %ecx,nCount /* save counter */ + pushl %esi + movl ACCUM(%esi),%ebp /* get accumulator */ + movl PITCH(%esi),%edx /* get pitch */ + movzbl VOLUME(%esi),%ebx /* get volume */ + movzbl PANNING(%esi),%ecx /* get panning */ + movb RESERVED(%esi),%al /* get last sample */ + movl DATA(%esi),%esi /* get data pointer */ + shrl $1,%esi + + pushl %esi + imull %ebx,%ecx /* get volume tables */ + shrl $8,%ecx + subl %ecx,%ebx + shll $10,%ebx + shll $10,%ecx + addl SYMBOL_NAME(lpVolumeTable),%ebx + addl SYMBOL_NAME(lpVolumeTable),%ecx + shrl $2,%ebx + shrl $2,%ecx + movb %al,%bl /* save sample for filtering */ + + movl %ebp,%eax /* accum to 32.32 fixed point */ + sarl $ACCURACY,%eax + shll $(32-ACCURACY),%ebp + addl %eax,%esi + + movl %edx,%eax /* pitch to 32.32 fixed point */ + testl %edx,%edx + jge 1f + neg %edx +1: shrl $(ACCURACY-5),%edx + shll $8,%edx + addl SYMBOL_NAME(lpFilterTable),%edx + pushl %eax + shll $(32-ACCURACY),%eax + movl %eax,nStepLo + popl %eax + sarl $ACCURACY,%eax + movl %eax,nStepHi + + movl nCount,%eax /* jump inside of the loop */ + andl $0x0F,%eax + leal -0x80(%edi,%eax,8),%edi + shrl $4,nCount + jmpl *18f(,%eax,4) + +#define RESAMPLE(OFF) \ + movb %bl,%dl; \ + subb (%edx),%bl; \ + movb 1(,%esi,2),%dl; \ + movb (%edx),%dl; \ + movl nStepLo,%eax; \ + addb %dl,%bl; \ + addl %eax,%ebp; \ + movb %bl,%cl; \ + movl nStepHi,%eax; \ + adcl %eax,%esi; \ + movl (,%ebx,4),%eax; \ + addl %eax,OFF(%edi); \ + movl (,%ecx,4),%eax; \ + addl %eax,OFF+4(%edi); + + ALIGN +1: RESAMPLE(0x00) /* ~15 cycles/sample */ +2: RESAMPLE(0x08) +3: RESAMPLE(0x10) +4: RESAMPLE(0x18) +5: RESAMPLE(0x20) +6: RESAMPLE(0x28) +7: RESAMPLE(0x30) +8: RESAMPLE(0x38) +9: RESAMPLE(0x40) +10: RESAMPLE(0x48) +11: RESAMPLE(0x50) +12: RESAMPLE(0x58) +13: RESAMPLE(0x60) +14: RESAMPLE(0x68) +15: RESAMPLE(0x70) +16: RESAMPLE(0x78) +17: addl $0x80,%edi + decl nCount + jge 1b + +#undef RESAMPLE + + popl %eax /* get accumulator */ + subl %eax,%esi + shrdl $(32-ACCURACY),%esi,%ebp + popl %esi + movl %ebp,ACCUM(%esi) /* save accumulator */ + movb %bl,RESERVED(%esi) /* save last sample */ + + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + popl %ebp + ret + + ALIGN +18: .long 17b + .long 16b + .long 15b + .long 14b + .long 13b + .long 12b + .long 11b + .long 10b + .long 9b + .long 8b + .long 7b + .long 6b + .long 5b + .long 4b + .long 3b + .long 2b + +/* + * 16-bit full right stereo mixing routine + */ + ALIGN +MixAudioRight16SI: + addl $4,%edi + +/* + * 16-bit full left stereo mixing routine + */ + ALIGN +MixAudioLeft16SI: + movl %ecx,nCount /* save counter */ + pushl %esi + movl ACCUM(%esi),%ebp /* get accumulator */ + movl PITCH(%esi),%ecx /* get pitch */ + movzbl VOLUME(%esi),%ebx /* get volume */ + movb RESERVED(%esi),%dl /* get last sample */ + movl DATA(%esi),%esi /* get data address */ + shrl $1,%esi + pushl %esi + + shll $10,%ebx /* get volume table address */ + addl SYMBOL_NAME(lpVolumeTable),%ebx + shrl $2,%ebx + movb %dl,%bl /* save sample for filtering */ + + movl %ebp,%eax /* convert accumulator */ + sarl $ACCURACY,%eax + shll $(32-ACCURACY),%ebp + addl %eax,%esi + + movl %ecx,%edx /* get filter table address */ + movl %ecx,%eax /* and convert pitch */ + sarl $ACCURACY,%eax + shll $(32-ACCURACY),%ecx + movl %eax,nStepHi + testl %edx,%edx + jge 1f + neg %edx +1: shrl $(ACCURACY-5),%edx + shll $8,%edx + addl SYMBOL_NAME(lpFilterTable),%edx + + movl nCount,%eax /* jump inside of the loop */ + andl $0x0F,%eax + leal -0x80(%edi,%eax,8),%edi + shrl $4,nCount + jmpl *18f(,%eax,4) + +#define RESAMPLE(OFF) \ + movb %bl,%dl; \ + subb (%edx),%bl; \ + movb 1(,%esi,2),%dl; \ + movb (%edx),%dl; \ + movl nStepHi,%eax; \ + addb %dl,%bl; \ + addl %ecx,%ebp; \ + adcl %eax,%esi; \ + movl (,%ebx,4),%eax; \ + addl %eax,OFF(%edi); + + ALIGN +1: RESAMPLE(0x00) /* ~11 cycles/sample */ +2: RESAMPLE(0x08) +3: RESAMPLE(0x10) +4: RESAMPLE(0x18) +5: RESAMPLE(0x20) +6: RESAMPLE(0x28) +7: RESAMPLE(0x30) +8: RESAMPLE(0x38) +9: RESAMPLE(0x40) +10: RESAMPLE(0x48) +11: RESAMPLE(0x50) +12: RESAMPLE(0x58) +13: RESAMPLE(0x60) +14: RESAMPLE(0x68) +15: RESAMPLE(0x70) +16: RESAMPLE(0x78) +17: addl $0x80,%edi + decl nCount + jge 1b + +#undef RESAMPLE + + popl %eax + subl %eax,%esi /* get and save accumulator */ + shrdl $(32-ACCURACY),%esi,%ebp + popl %esi + movl %ebp,ACCUM(%esi) + movb %bl,RESERVED(%esi) /* save sample for filtering */ + + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + popl %ebp + ret + + ALIGN +18: .long 17b + .long 16b + .long 15b + .long 14b + .long 13b + .long 12b + .long 11b + .long 10b + .long 9b + .long 8b + .long 7b + .long 6b + .long 5b + .long 4b + .long 3b + .long 2b + +/* + * 16-bit middle stereo mixing routine + */ + ALIGN +MixAudioMiddle16SI: + movl %ecx,nCount /* save counter */ + pushl %esi + movl ACCUM(%esi),%ebp /* get accumulator */ + movl PITCH(%esi),%ecx /* get pitch */ + movzbl VOLUME(%esi),%ebx /* get volume */ + movb RESERVED(%esi),%dl /* get last sample */ + movl DATA(%esi),%esi /* get data address */ + shrl $1,%esi + pushl %esi + + shrl $1,%ebx /* get volume table address */ + shll $10,%ebx + addl SYMBOL_NAME(lpVolumeTable),%ebx + shrl $2,%ebx + movb %dl,%bl /* save sample for filtering */ + + movl %ebp,%eax /* convert accumulator */ + sarl $ACCURACY,%eax + shll $(32-ACCURACY),%ebp + addl %eax,%esi + + movl %ecx,%edx /* get filter table address */ + movl %ecx,%eax /* and convert pitch */ + sarl $ACCURACY,%eax + shll $(32-ACCURACY),%ecx + movl %eax,nStepHi + testl %edx,%edx + jge 1f + neg %edx +1: shrl $(ACCURACY-5),%edx + shll $8,%edx + addl SYMBOL_NAME(lpFilterTable),%edx + + movl nCount,%eax /* jump inside of the loop */ + andl $0x0F,%eax + leal -0x80(%edi,%eax,8),%edi + shrl $4,nCount + jmpl *18f(,%eax,4) + +#define RESAMPLE(OFF) \ + movb %bl,%dl; \ + subb (%edx),%bl; \ + movb 1(,%esi,2),%dl; \ + movb (%edx),%dl; \ + movl nStepHi,%eax; \ + addb %dl,%bl; \ + addl %ecx,%ebp; \ + adcl %eax,%esi; \ + movl (,%ebx,4),%eax; \ + addl %eax,OFF(%edi); \ + addl %eax,OFF+4(%edi); + + ALIGN +1: RESAMPLE(0x00) /* ~14 cycles/sample */ +2: RESAMPLE(0x08) +3: RESAMPLE(0x10) +4: RESAMPLE(0x18) +5: RESAMPLE(0x20) +6: RESAMPLE(0x28) +7: RESAMPLE(0x30) +8: RESAMPLE(0x38) +9: RESAMPLE(0x40) +10: RESAMPLE(0x48) +11: RESAMPLE(0x50) +12: RESAMPLE(0x58) +13: RESAMPLE(0x60) +14: RESAMPLE(0x68) +15: RESAMPLE(0x70) +16: RESAMPLE(0x78) +17: addl $0x80,%edi + decl nCount + jge 1b + +#undef RESAMPLE + + popl %eax + subl %eax,%esi /* get and save accumulator */ + shrdl $(32-ACCURACY),%esi,%ebp + popl %esi + movl %ebp,ACCUM(%esi) + movb %bl,RESERVED(%esi) /* save sample for filtering */ + + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + popl %ebp + ret + + ALIGN +18: .long 17b + .long 16b + .long 15b + .long 14b + .long 13b + .long 12b + .long 11b + .long 10b + .long 9b + .long 8b + .long 7b + .long 6b + .long 5b + .long 4b + .long 3b + .long 2b + diff --git a/seal-hack/src/_mixdrv.asm b/seal-hack/src/_mixdrv.asm new file mode 100644 index 0000000..4b9e585 --- /dev/null +++ b/seal-hack/src/_mixdrv.asm @@ -0,0 +1,2269 @@ +;* +;* $Id: _mixdrv.asm 1.8 1996/08/15 02:33:23 chasan released $ +;* +;* Low-level assembly resampling and quantization routines. +;* Optimized for superscalar architecture of Pentium processors. +;* +;* Copyright (C) 1995-1999 Carlos Hasan +;* +;* This program is free software; you can redistribute it and/or modify +;* it under the terms of the GNU Lesser General Public License as published +;* by the Free Software Foundation; either version 2 of the License, or +;* (at your option) any later version. +;* + + .386p + .model flat + +; voice structure field offsets +Voice struc +LPDATA dd ? +ACCUM dd ? +PITCH dd ? +LOOPSTART dd ? +LOOPEND dd ? +VOLUME db ? +PANNING db ? +CONTROL db ? +RESERVED db ? +Voice ends + + +; pitch shift accuracy +ACCURACY equ 0ch + + .data + + extrn _lpVolumeTable:dword + extrn _lpFilterTable:dword + + align 4 +nCount dd ? +nStepLo dd ? +nStepHi dd ? + + .code + +; Borland C++ 4.5 calling convention + public QuantAudioData08 + public QuantAudioData16 + public MixAudioData08M + public MixAudioData08S + public MixAudioData08MI + public MixAudioData08SI + public MixAudioData16M + public MixAudioData16S + public MixAudioData16MI + public MixAudioData16SI + +; WATCOM C/C++ 10.0 calling convention + public _QuantAudioData08 + public _QuantAudioData16 + public _MixAudioData08M + public _MixAudioData08S + public _MixAudioData08MI + public _MixAudioData08SI + public _MixAudioData16M + public _MixAudioData16S + public _MixAudioData16MI + public _MixAudioData16SI + +; Visual C++ 4.1 calling convention + public _QuantAudioData08@12 + public _QuantAudioData16@12 + public _MixAudioData08M@12 + public _MixAudioData08S@12 + public _MixAudioData08MI@12 + public _MixAudioData08SI@12 + public _MixAudioData16M@12 + public _MixAudioData16S@12 + public _MixAudioData16MI@12 + public _MixAudioData16SI@12 + + +; +; VOID cdecl QuantAudioData08(LPVOID lpBuffer, LPLONG lpData, UINT nCount) +; + align 4 + +QuantAudioData08 proc +_QuantAudioData08: +_QuantAudioData08@12: + push ebp + mov ebp,esp + push eax + push ebx + push ecx + push edx + push esi + push edi + mov edi,[ebp+08h] ; get parameters + mov esi,[ebp+0ch] + mov ecx,[ebp+10h] + mov ebx,08000h + mov edx,0ffffh + dec edi + align 4 +L1: mov eax,[esi] ; 5 cycles/sample + inc edi + add eax,ebx + jl L3 + cmp eax,edx + jg L4 +L2: add esi,4 + mov [edi],ah + dec ecx + jg L1 + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + pop ebp + ret + align 4 +L3: xor eax,eax + jmp L2 + align 4 +L4: mov eax,edx + jmp L2 +QuantAudioData08 endp + + +; +; VOID cdecl QuantAudioData16(LPVOID lpBuffer, LPLONG lpData, UINT nCount) +; + align 4 +QuantAudioData16 proc +_QuantAudioData16: +_QuantAudioData16@12: + push ebp + mov ebp,esp + push eax + push ebx + push ecx + push edx + push esi + push edi + mov edi,[ebp+08h] ; get parameters + mov esi,[ebp+0ch] + mov ecx,[ebp+10h] + mov ebx,-32768 + mov edx,+32767 + sub edi,2 + align 4 +L5: mov eax,[esi] ; 5 cycles/sample + add edi,2 + cmp eax,ebx + jl L7 + cmp eax,edx + jg L8 +L6: add esi,4 + mov [edi],ax + dec ecx + jg L5 + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + pop ebp + ret + align 4 +L7: mov eax,ebx + jmp L6 + align 4 +L8: mov eax,edx + jmp L6 +QuantAudioData16 endp + + +;=========================== 8 bit mixing routines =========================== + +; +; VOID cdecl MixAudioData08M(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) +; + align 4 +MixAudioData08M proc +_MixAudioData08M: +_MixAudioData08M@12: + push ebp + mov ebp,esp + push eax + push ebx + push ecx + push edx + push esi + push edi + + mov edi,[ebp+08h] ; get parameters + mov ecx,[ebp+0ch] + mov esi,[ebp+10h] + +__MixAudioData08M: + mov [nCount],ecx ; save counter + push esi + mov ecx,[esi+ACCUM] ; get voice parameters + mov ebp,[esi+PITCH] + movzx ebx,[esi+VOLUME] + mov esi,[esi+LPDATA] + shl ebx,10 ; get volume table address + push esi + mov eax,ecx + add ebx,[_lpVolumeTable] ; convert accumulator and pitch + sar eax,ACCURACY ; to 32.32 fixed point + shr ebx,2 + shl ecx,32-ACCURACY + mov edx,ebp + add esi,eax + sar edx,ACCURACY + shl ebp,32-ACCURACY + mov [nStepHi],edx + + mov bl,[esi] ; get first sample and advance + add ecx,ebp + adc esi,edx + + mov eax,[nCount] ; jump inside of the unrolled loop + mov edx,eax + and eax,0fh + shr edx,4 + lea edi,[edi+eax*4+(-40h)] + mov [nCount],edx + jmp dword ptr [TBL08M+eax*4] + +RESAMPLE08M macro disp + mov edx,[edi+4*disp] ; 4 cycles/sample + mov eax,[ebx*4] + add eax,edx + add ecx,ebp + mov bl,[esi] + mov edx,[nStepHi] + adc esi,edx + mov [edi+4*disp],eax +E08M&disp: + endm + + align 4 +L08M: RESAMPLE08M 0 + RESAMPLE08M 1 + RESAMPLE08M 2 + RESAMPLE08M 3 + RESAMPLE08M 4 + RESAMPLE08M 5 + RESAMPLE08M 6 + RESAMPLE08M 7 + RESAMPLE08M 8 + RESAMPLE08M 9 + RESAMPLE08M 10 + RESAMPLE08M 11 + RESAMPLE08M 12 + RESAMPLE08M 13 + RESAMPLE08M 14 + RESAMPLE08M 15 + add edi,40h + dec [nCount] + jge L08M + + mov eax,[nStepHi] ; go back one step + sub ecx,ebp + sbb esi,eax + pop eax + sub esi,eax ; get and save accumulator + shrd ecx,esi,32-ACCURACY + pop esi + mov [esi+ACCUM],ecx + mov [esi+RESERVED],bl + + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + pop ebp + ret + + align 4 +TBL08M dd offset E08M15 + dd offset E08M14 + dd offset E08M13 + dd offset E08M12 + dd offset E08M11 + dd offset E08M10 + dd offset E08M9 + dd offset E08M8 + dd offset E08M7 + dd offset E08M6 + dd offset E08M5 + dd offset E08M4 + dd offset E08M3 + dd offset E08M2 + dd offset E08M1 + dd offset E08M0 +MixAudioData08M endp + + +; +; VOID cdecl MixAudioData08S(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) +; + align 4 +MixAudioData08S proc +_MixAudioData08S: +_MixAudioData08S@12: + push ebp + mov ebp,esp + push eax + push ebx + push ecx + push edx + push esi + push edi + + mov edi,[ebp+08h] ; get parameters + mov ecx,[ebp+0ch] + mov esi,[ebp+10h] + +__MixAudioData08S: + mov al,[esi+PANNING] ; get panning + cmp al,10h + jb MixAudioLeft08S ; full left? + cmp al,78h + jb MixAudioPan08S ; left? + cmp al,88h + jb MixAudioMiddle08S ; center? + cmp al,0f0h + jae MixAudioRight08S ; full right? +MixAudioData08S endp + +; +; 8-bit general stereo mixing routine +; + align 4 +MixAudioPan08S proc + mov [nCount],ecx ; save counter + push esi + mov ebp,[esi+ACCUM] ; get voice parameters + mov edx,[esi+PITCH] + movzx ebx,[esi+VOLUME] + movzx ecx,[esi+PANNING] + mov esi,[esi+LPDATA] + + push esi ; get volume table addresses + imul ecx,ebx + shr ecx,8 + sub ebx,ecx + shl ebx,10 + shl ecx,10 + add ebx,[_lpVolumeTable] + add ecx,[_lpVolumeTable] + shr ebx,2 + shr ecx,2 + + mov eax,ebp ; convert accumulator and pitch + sar eax,ACCURACY ; to 32.32 fixed point + shl ebp,32-ACCURACY + add esi,eax + mov eax,edx + sar edx,ACCURACY + shl eax,32-ACCURACY + mov [nStepLo],eax + mov [nStepHi],edx + + mov bl,[esi] ; get first sample and advance + add ebp,eax + adc esi,edx + mov cl,bl + + mov eax,[nCount] ; jump inside of the unrolled loop + mov edx,eax + and eax,0fh + shr edx,4 + lea edi,[edi+eax*8+(-80h)] + mov [nCount],edx + jmp dword ptr [TBL08S+eax*4] + +RESAMPLE08S macro disp + mov eax,[ebx*4] ; 7 cycles/sample + mov edx,[edi+8*disp] + add eax,edx + mov edx,[edi+8*disp+4] + mov [edi+8*disp],eax + mov eax,[ecx*4] + add eax,edx + mov bl,[esi] + mov [edi+8*disp+4],eax + mov eax,[nStepLo] + add ebp,eax + mov edx,[nStepHi] + adc esi,edx + mov cl,bl +E08S&disp: + endm + + align 4 +L08S: RESAMPLE08S 0 + RESAMPLE08S 1 + RESAMPLE08S 2 + RESAMPLE08S 3 + RESAMPLE08S 4 + RESAMPLE08S 5 + RESAMPLE08S 6 + RESAMPLE08S 7 + RESAMPLE08S 8 + RESAMPLE08S 9 + RESAMPLE08S 10 + RESAMPLE08S 11 + RESAMPLE08S 12 + RESAMPLE08S 13 + RESAMPLE08S 14 + RESAMPLE08S 15 + add edi,80h + dec [nCount] + jge L08S + + mov eax,[nStepLo] ; go back one step + mov edx,[nStepHi] + sub ebp,eax + sbb esi,edx + pop eax ; get and save accumulator + sub esi,eax + shrd ebp,esi,32-ACCURACY + pop esi + mov [esi+ACCUM],ebp + mov [esi+RESERVED],bl + + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + pop ebp + ret + + align 4 +TBL08S dd offset E08S15 + dd offset E08S14 + dd offset E08S13 + dd offset E08S12 + dd offset E08S11 + dd offset E08S10 + dd offset E08S9 + dd offset E08S8 + dd offset E08S7 + dd offset E08S6 + dd offset E08S5 + dd offset E08S4 + dd offset E08S3 + dd offset E08S2 + dd offset E08S1 + dd offset E08S0 +MixAudioPan08S endp + +; +; 8-bit full right stereo mixing routine +; + align 4 +MixAudioRight08S proc + add edi,4 +MixAudioRight08S endp + +; +; 8-bit full left stereo mixing routine +; + align 4 +MixAudioLeft08S proc + mov [nCount],ecx ; save counter + push esi + mov ecx,[esi+ACCUM] ; get voice parameters + mov ebp,[esi+PITCH] + movzx ebx,[esi+VOLUME] + mov esi,[esi+LPDATA] + shl ebx,10 ; get volume table address + push esi + mov eax,ecx + add ebx,[_lpVolumeTable] ; convert accumulator and pitch + sar eax,ACCURACY ; to 32.32 fixed point + shr ebx,2 + shl ecx,32-ACCURACY + mov edx,ebp + add esi,eax + sar edx,ACCURACY + shl ebp,32-ACCURACY + mov [nStepHi],edx + + mov bl,[esi] ; get first sample and advance + add ecx,ebp + adc esi,edx + + mov eax,[nCount] ; jump inside of the unrolled loop + mov edx,eax + and eax,0fh + shr edx,4 + lea edi,[edi+eax*8+(-80h)] + mov [nCount],edx + jmp dword ptr [TBL08L+eax*4] + +RESAMPLE08L macro disp + mov edx,[edi+8*disp] ; 4 cycles/sample + mov eax,[ebx*4] + add eax,edx + add ecx,ebp + mov bl,[esi] + mov edx,[nStepHi] + adc esi,edx + mov [edi+8*disp],eax +E08L&disp: + endm + + align 4 +L08L: RESAMPLE08L 0 + RESAMPLE08L 1 + RESAMPLE08L 2 + RESAMPLE08L 3 + RESAMPLE08L 4 + RESAMPLE08L 5 + RESAMPLE08L 6 + RESAMPLE08L 7 + RESAMPLE08L 8 + RESAMPLE08L 9 + RESAMPLE08L 10 + RESAMPLE08L 11 + RESAMPLE08L 12 + RESAMPLE08L 13 + RESAMPLE08L 14 + RESAMPLE08L 15 + add edi,80h + dec [nCount] + jge L08L + + mov eax,[nStepHi] ; go back one step + sub ecx,ebp + sbb esi,eax + pop eax + sub esi,eax ; get and save accumulator + shrd ecx,esi,32-ACCURACY + pop esi + mov [esi+ACCUM],ecx + mov [esi+RESERVED],bl + + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + pop ebp + ret + + align 4 +TBL08L dd offset E08L15 + dd offset E08L14 + dd offset E08L13 + dd offset E08L12 + dd offset E08L11 + dd offset E08L10 + dd offset E08L9 + dd offset E08L8 + dd offset E08L7 + dd offset E08L6 + dd offset E08L5 + dd offset E08L4 + dd offset E08L3 + dd offset E08L2 + dd offset E08L1 + dd offset E08L0 +MixAudioLeft08S endp + +; +; 8-bit middle stereo mixing routine +; + align 4 +MixAudioMiddle08S proc + mov [nCount],ecx ; save counter + push esi + mov ecx,[esi+ACCUM] ; get voice parameters + mov ebp,[esi+PITCH] + movzx ebx,[esi+VOLUME] + mov esi,[esi+LPDATA] + shr ebx,1 + shl ebx,10 ; get volume table address + push esi + mov eax,ecx + add ebx,[_lpVolumeTable] ; convert accumulator and pitch + sar eax,ACCURACY ; to 32.32 fixed point + shr ebx,2 + shl ecx,32-ACCURACY + mov edx,ebp + add esi,eax + sar edx,ACCURACY + shl ebp,32-ACCURACY + mov [nStepHi],edx + + mov bl,[esi] ; get first sample and advance + add ecx,ebp + adc esi,edx + + mov eax,[nCount] ; jump inside of the unrolled loop + mov edx,eax + and eax,0fh + shr edx,4 + lea edi,[edi+eax*8+(-80h)] + mov [nCount],edx + jmp dword ptr [TBL08C+eax*4] + +RESAMPLE08C macro disp + mov edx,[edi+8*disp+0] ; 4 cycles/sample + mov eax,[ebx*4] + add edx,eax + mov bl,[esi] + mov [edi+8*disp+0],edx + mov edx,[edi+8*disp+4] + add edx,eax + mov eax,[nStepHi] + mov [edi+8*disp+4],edx + add ecx,ebp + adc esi,eax +E08C&disp: + endm + + align 4 +L08C: RESAMPLE08C 0 + RESAMPLE08C 1 + RESAMPLE08C 2 + RESAMPLE08C 3 + RESAMPLE08C 4 + RESAMPLE08C 5 + RESAMPLE08C 6 + RESAMPLE08C 7 + RESAMPLE08C 8 + RESAMPLE08C 9 + RESAMPLE08C 10 + RESAMPLE08C 11 + RESAMPLE08C 12 + RESAMPLE08C 13 + RESAMPLE08C 14 + RESAMPLE08C 15 + add edi,80h + dec [nCount] + jge L08C + + mov eax,[nStepHi] ; go back one step + sub ecx,ebp + sbb esi,eax + pop eax + sub esi,eax ; get and save accumulator + shrd ecx,esi,32-ACCURACY + pop esi + mov [esi+ACCUM],ecx + mov [esi+RESERVED],bl + + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + pop ebp + ret + + align 4 +TBL08C dd offset E08C15 + dd offset E08C14 + dd offset E08C13 + dd offset E08C12 + dd offset E08C11 + dd offset E08C10 + dd offset E08C9 + dd offset E08C8 + dd offset E08C7 + dd offset E08C6 + dd offset E08C5 + dd offset E08C4 + dd offset E08C3 + dd offset E08C2 + dd offset E08C1 + dd offset E08C0 +MixAudioMiddle08S endp + + + +; +; VOID cdecl MixAudioData08MI(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) +; + align 4 +MixAudioData08MI proc +_MixAudioData08MI: +_MixAudioData08MI@12: + push ebp + mov ebp,esp + push eax + push ebx + push ecx + push edx + push esi + push edi + + mov edi,[ebp+08h] ; get parameters + mov ecx,[ebp+0ch] + mov esi,[ebp+10h] + + mov eax,[esi+PITCH] ; select mixing routine + cmp eax,+(1 SHL ACCURACY) + jge __MixAudioData08M + cmp eax,-(1 SHL ACCURACY) + jle __MixAudioData08M + + mov [nCount],ecx ; save counter + push esi + mov ebp,[esi+ACCUM] ; get accumulator + mov ecx,[esi+PITCH] ; get pitch + movzx ebx,[esi+VOLUME] ; get volume + mov dl,[esi+RESERVED] ; get last sample + mov esi,[esi+LPDATA] ; get data address + push esi + + shl ebx,10 ; get volume table address + add ebx,[_lpVolumeTable] + shr ebx,2 + mov bl,dl ; save sample for filtering + + mov eax,ebp ; convert accumulator + sar eax,ACCURACY + shl ebp,32-ACCURACY + add esi,eax + + mov edx,ecx ; get filter table address + mov eax,ecx + shl ecx,32-ACCURACY + sar eax,ACCURACY ; convert pitch + mov [nStepHi],eax + test edx,edx + jge L10 + neg edx +L10: shr edx,ACCURACY-5 + shl edx,8 + add edx,[_lpFilterTable] + + mov eax,[nCount] ; jump inside of the loop + and eax,0fh + lea edi,[edi+eax*4+(-40h)] + shr [nCount],4 + jmp dword ptr [TBL08MI+eax*4] + +RESAMPLE08MI macro disp + mov dl,bl + sub bl,[edx] + mov dl,[esi] + mov dl,[edx] + mov eax,[nStepHi] + add bl,dl + add ebp,ecx + adc esi,eax + mov eax,[ebx*4] + add [edi+4*disp],eax +E08MI&disp: + endm + +L08MI: RESAMPLE08MI 0 ; 11 cycles/sample + RESAMPLE08MI 1 + RESAMPLE08MI 2 + RESAMPLE08MI 3 + RESAMPLE08MI 4 + RESAMPLE08MI 5 + RESAMPLE08MI 6 + RESAMPLE08MI 7 + RESAMPLE08MI 8 + RESAMPLE08MI 9 + RESAMPLE08MI 10 + RESAMPLE08MI 11 + RESAMPLE08MI 12 + RESAMPLE08MI 13 + RESAMPLE08MI 14 + RESAMPLE08MI 15 + add edi,40h + dec [nCount] + jge L08MI + + pop eax + sub esi,eax ; get and save accumulator + shrd ebp,esi,32-ACCURACY + pop esi + mov [esi+ACCUM],ebp + mov [esi+RESERVED],bl + + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + pop ebp + ret + + align 4 +TBL08MI dd offset E08MI15 + dd offset E08MI14 + dd offset E08MI13 + dd offset E08MI12 + dd offset E08MI11 + dd offset E08MI10 + dd offset E08MI9 + dd offset E08MI8 + dd offset E08MI7 + dd offset E08MI6 + dd offset E08MI5 + dd offset E08MI4 + dd offset E08MI3 + dd offset E08MI2 + dd offset E08MI1 + dd offset E08MI0 +MixAudioData08MI endp + +; +; VOID cdecl MixAudioData08SI(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) +; + align 4 +MixAudioData08SI proc +_MixAudioData08SI: +_MixAudioData08SI@12: + push ebp + mov ebp,esp + push eax + push ebx + push ecx + push edx + push esi + push edi + + mov edi,[ebp+08h] ; get parameters + mov ecx,[ebp+0ch] + mov esi,[ebp+10h] + + mov eax,[esi+PITCH] ; select mixing routine + cmp eax,+(1 SHL ACCURACY) + jge __MixAudioData08S + cmp eax,-(1 SHL ACCURACY) + jle __MixAudioData08S + + mov al,[esi+PANNING] ; select panning routine + cmp al,10h + jb MixAudioLeft08SI + cmp al,78h + jb MixAudioPan08SI + cmp al,88h + jb MixAudioMiddle08SI + cmp al,0f0h + jae MixAudioRight08SI +MixAudioData08SI endp + + +; +; 8-bit general stereo mixing routine +; + align 4 +MixAudioPan08SI proc + mov [nCount],ecx ; save counter + push esi + mov ebp,[esi+ACCUM] ; get voice parameters + mov edx,[esi+PITCH] + movzx ebx,[esi+VOLUME] + movzx ecx,[esi+PANNING] + mov al,[esi+RESERVED] + mov esi,[esi+LPDATA] + + push esi ; get volume table addresses + imul ecx,ebx + shr ecx,8 + sub ebx,ecx + shl ebx,10 + shl ecx,10 + add ebx,[_lpVolumeTable] + add ecx,[_lpVolumeTable] + shr ebx,2 + shr ecx,2 + mov bl,al ; save sample for filtering + + mov eax,ebp ; convert accumulator + sar eax,ACCURACY + shl ebp,32-ACCURACY + add esi,eax + + mov eax,edx ; convert pitch + test edx,edx + jge L11 + neg edx +L11: shr edx,ACCURACY-5 + shl edx,8 + add edx,[_lpFilterTable] + push eax + shl eax,32-ACCURACY + mov [nStepLo],eax + pop eax + sar eax,ACCURACY + mov [nStepHi],eax + + mov eax,[nCount] ; jump inside of the loop + and eax,0fh + lea edi,[edi+eax*8+(-80h)] + shr [nCount],4 + jmp dword ptr [TBL08PI+eax*4] + +RESAMPLE08PI macro disp + mov dl,bl + sub bl,[edx] + mov dl,[esi] + mov dl,[edx] + mov eax,[nStepLo] + add bl,dl + add ebp,eax + mov cl,bl + mov eax,[nStepHi] + adc esi,eax + mov eax,[ebx*4] + add [edi+8*disp],eax + mov eax,[ecx*4] + add [edi+8*disp+4],eax +E08PI&disp: + endm + + align 4 +L08PI: RESAMPLE08PI 0 ; 15 cycles/sample + RESAMPLE08PI 1 + RESAMPLE08PI 2 + RESAMPLE08PI 3 + RESAMPLE08PI 4 + RESAMPLE08PI 5 + RESAMPLE08PI 6 + RESAMPLE08PI 7 + RESAMPLE08PI 8 + RESAMPLE08PI 9 + RESAMPLE08PI 10 + RESAMPLE08PI 11 + RESAMPLE08PI 12 + RESAMPLE08PI 13 + RESAMPLE08PI 14 + RESAMPLE08PI 15 + add edi,80h + dec [nCount] + jge L08PI + + pop eax ; get and save accumulator + sub esi,eax + shrd ebp,esi,32-ACCURACY + pop esi + mov [esi+ACCUM],ebp + mov [esi+RESERVED],bl + + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + pop ebp + ret + + align 4 +TBL08PI dd offset E08PI15 + dd offset E08PI14 + dd offset E08PI13 + dd offset E08PI12 + dd offset E08PI11 + dd offset E08PI10 + dd offset E08PI9 + dd offset E08PI8 + dd offset E08PI7 + dd offset E08PI6 + dd offset E08PI5 + dd offset E08PI4 + dd offset E08PI3 + dd offset E08PI2 + dd offset E08PI1 + dd offset E08PI0 +MixAudioPan08SI endp + +; +; 8-bit full right stereo mixing routine +; + align 4 +MixAudioRight08SI proc + add edi,4 +MixAudioRight08SI endp + +; +; 8-bit full left stereo mixing routine +; + align 4 +MixAudioLeft08SI proc + mov [nCount],ecx ; save counter + push esi + mov ebp,[esi+ACCUM] ; get accumulator + mov ecx,[esi+PITCH] ; get pitch + movzx ebx,[esi+VOLUME] ; get volume + mov dl,[esi+RESERVED] ; get last sample + mov esi,[esi+LPDATA] ; get data address + push esi + + shl ebx,10 ; get volume table address + add ebx,[_lpVolumeTable] + shr ebx,2 + mov bl,dl ; save sample for filtering + + mov eax,ebp ; convert accumulator + sar eax,ACCURACY + shl ebp,32-ACCURACY + add esi,eax + + mov edx,ecx ; get filter table address + mov eax,ecx + shl ecx,32-ACCURACY + sar eax,ACCURACY ; convert pitch + mov [nStepHi],eax + test edx,edx + jge L12 + neg edx +L12: shr edx,ACCURACY-5 + shl edx,8 + add edx,[_lpFilterTable] + + mov eax,[nCount] ; jump inside of the loop + and eax,0fh + lea edi,[edi+eax*8+(-80h)] + shr [nCount],4 + jmp dword ptr [TBL08LI+eax*4] + +RESAMPLE08LI macro disp + mov dl,bl + sub bl,[edx] + mov dl,[esi] + mov dl,[edx] + mov eax,[nStepHi] + add bl,dl + add ebp,ecx + adc esi,eax + mov eax,[ebx*4] + add [edi+8*disp],eax +E08LI&disp: + endm + +L08LI: RESAMPLE08LI 0 ; 11 cycles/sample + RESAMPLE08LI 1 + RESAMPLE08LI 2 + RESAMPLE08LI 3 + RESAMPLE08LI 4 + RESAMPLE08LI 5 + RESAMPLE08LI 6 + RESAMPLE08LI 7 + RESAMPLE08LI 8 + RESAMPLE08LI 9 + RESAMPLE08LI 10 + RESAMPLE08LI 11 + RESAMPLE08LI 12 + RESAMPLE08LI 13 + RESAMPLE08LI 14 + RESAMPLE08LI 15 + add edi,80h + dec [nCount] + jge L08LI + + pop eax + sub esi,eax ; get and save accumulator + shrd ebp,esi,32-ACCURACY + pop esi + mov [esi+ACCUM],ebp + mov [esi+RESERVED],bl + + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + pop ebp + ret + + align 4 +TBL08LI dd offset E08LI15 + dd offset E08LI14 + dd offset E08LI13 + dd offset E08LI12 + dd offset E08LI11 + dd offset E08LI10 + dd offset E08LI9 + dd offset E08LI8 + dd offset E08LI7 + dd offset E08LI6 + dd offset E08LI5 + dd offset E08LI4 + dd offset E08LI3 + dd offset E08LI2 + dd offset E08LI1 + dd offset E08LI0 +MixAudioLeft08SI endp + + +; +; 8-bit middle stereo mixing routine +; + align 4 +MixAudioMiddle08SI proc + mov [nCount],ecx ; save counter + push esi + mov ebp,[esi+ACCUM] ; get accumulator + mov ecx,[esi+PITCH] ; get pitch + movzx ebx,[esi+VOLUME] ; get volume + mov dl,[esi+RESERVED] ; get last sample + mov esi,[esi+LPDATA] ; get data address + push esi + + shr ebx,1 ; get volume table address + shl ebx,10 + add ebx,[_lpVolumeTable] + shr ebx,2 + mov bl,dl ; save sample for filtering + + mov eax,ebp ; convert accumulator + sar eax,ACCURACY + shl ebp,32-ACCURACY + add esi,eax + + mov edx,ecx ; get filter table address + mov eax,ecx + shl ecx,32-ACCURACY + sar eax,ACCURACY ; convert pitch + mov [nStepHi],eax + test edx,edx + jge L13 + neg edx +L13: shr edx,ACCURACY-5 + shl edx,8 + add edx,[_lpFilterTable] + + mov eax,[nCount] ; jump inside of the loop + and eax,0fh + lea edi,[edi+eax*8+(-80h)] + shr [nCount],4 + jmp dword ptr [TBL08CI+eax*4] + +RESAMPLE08CI macro disp + mov dl,bl + sub bl,[edx] + mov dl,[esi] + mov dl,[edx] + mov eax,[nStepHi] + add bl,dl + add ebp,ecx + adc esi,eax + mov eax,[ebx*4] + add [edi+8*disp],eax + add [edi+8*disp+4],eax +E08CI&disp: + endm + +L08CI: RESAMPLE08CI 0 ; 14 cycles/sample + RESAMPLE08CI 1 + RESAMPLE08CI 2 + RESAMPLE08CI 3 + RESAMPLE08CI 4 + RESAMPLE08CI 5 + RESAMPLE08CI 6 + RESAMPLE08CI 7 + RESAMPLE08CI 8 + RESAMPLE08CI 9 + RESAMPLE08CI 10 + RESAMPLE08CI 11 + RESAMPLE08CI 12 + RESAMPLE08CI 13 + RESAMPLE08CI 14 + RESAMPLE08CI 15 + add edi,80h + dec [nCount] + jge L08CI + + pop eax + sub esi,eax ; get and save accumulator + shrd ebp,esi,32-ACCURACY + pop esi + mov [esi+ACCUM],ebp + mov [esi+RESERVED],bl + + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + pop ebp + ret + + align 4 +TBL08CI dd offset E08CI15 + dd offset E08CI14 + dd offset E08CI13 + dd offset E08CI12 + dd offset E08CI11 + dd offset E08CI10 + dd offset E08CI9 + dd offset E08CI8 + dd offset E08CI7 + dd offset E08CI6 + dd offset E08CI5 + dd offset E08CI4 + dd offset E08CI3 + dd offset E08CI2 + dd offset E08CI1 + dd offset E08CI0 +MixAudioMiddle08SI endp + +;========================= fake 16 bit mixing routines ========================; + +; +; VOID cdecl MixAudioData16M(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) +; + align 4 +MixAudioData16M proc +_MixAudioData16M: +_MixAudioData16M@12: + push ebp + mov ebp,esp + push eax + push ebx + push ecx + push edx + push esi + push edi + + mov edi,[ebp+08h] ; get parameters + mov ecx,[ebp+0ch] + mov esi,[ebp+10h] + +__MixAudioData16M: + mov [nCount],ecx ; save counter + push esi + mov ecx,[esi+ACCUM] ; get voice parameters + mov ebp,[esi+PITCH] + movzx ebx,[esi+VOLUME] + mov esi,[esi+LPDATA] + shr esi,1 + shl ebx,10 ; get volume table address + push esi + mov eax,ecx + add ebx,[_lpVolumeTable] ; convert accumulator and pitch + sar eax,ACCURACY ; to 32.32 fixed point + shr ebx,2 + shl ecx,32-ACCURACY + mov edx,ebp + add esi,eax + sar edx,ACCURACY + shl ebp,32-ACCURACY + mov [nStepHi],edx + + mov bl,[2*esi+1] ; get first sample and advance + add ecx,ebp + adc esi,edx + + mov eax,[nCount] ; jump inside of the unrolled loop + mov edx,eax + and eax,0fh + shr edx,4 + lea edi,[edi+eax*4+(-40h)] + mov [nCount],edx + jmp dword ptr [TBL16M+eax*4] + +RESAMPLE16M macro disp + mov edx,[edi+4*disp] ; 4 cycles/sample + mov eax,[ebx*4] + add eax,edx + add ecx,ebp + mov bl,[2*esi+1] + mov edx,[nStepHi] + adc esi,edx + mov [edi+4*disp],eax +E16M&disp: + endm + + align 4 +L16M: RESAMPLE16M 0 + RESAMPLE16M 1 + RESAMPLE16M 2 + RESAMPLE16M 3 + RESAMPLE16M 4 + RESAMPLE16M 5 + RESAMPLE16M 6 + RESAMPLE16M 7 + RESAMPLE16M 8 + RESAMPLE16M 9 + RESAMPLE16M 10 + RESAMPLE16M 11 + RESAMPLE16M 12 + RESAMPLE16M 13 + RESAMPLE16M 14 + RESAMPLE16M 15 + add edi,40h + dec [nCount] + jge L16M + + mov eax,[nStepHi] ; go back one step + sub ecx,ebp + sbb esi,eax + pop eax + sub esi,eax ; get and save accumulator + shrd ecx,esi,32-ACCURACY + pop esi + mov [esi+ACCUM],ecx + mov [esi+RESERVED],bl + + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + pop ebp + ret + + align 4 +TBL16M dd offset E16M15 + dd offset E16M14 + dd offset E16M13 + dd offset E16M12 + dd offset E16M11 + dd offset E16M10 + dd offset E16M9 + dd offset E16M8 + dd offset E16M7 + dd offset E16M6 + dd offset E16M5 + dd offset E16M4 + dd offset E16M3 + dd offset E16M2 + dd offset E16M1 + dd offset E16M0 +MixAudioData16M endp + + +; +; VOID cdecl MixAudioData16S(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) +; + align 4 +MixAudioData16S proc +_MixAudioData16S: +_MixAudioData16S@12: + push ebp + mov ebp,esp + push eax + push ebx + push ecx + push edx + push esi + push edi + + mov edi,[ebp+08h] ; get parameters + mov ecx,[ebp+0ch] + mov esi,[ebp+10h] + +__MixAudioData16S: + mov al,[esi+PANNING] ; get panning + cmp al,10h + jb MixAudioLeft16S ; full left? + cmp al,78h + jb MixAudioPan16S ; left? + cmp al,88h + jb MixAudioMiddle16S ; center? + cmp al,0f0h + jae MixAudioRight16S ; full right? +MixAudioData16S endp + +; +; 16-bit general stereo mixing routine +; + align 4 +MixAudioPan16S proc + mov [nCount],ecx ; save counter + push esi + mov ebp,[esi+ACCUM] ; get voice parameters + mov edx,[esi+PITCH] + movzx ebx,[esi+VOLUME] + movzx ecx,[esi+PANNING] + mov esi,[esi+LPDATA] + shr esi,1 + + push esi ; get volume table addresses + imul ecx,ebx + shr ecx,8 + sub ebx,ecx + shl ebx,10 + shl ecx,10 + add ebx,[_lpVolumeTable] + add ecx,[_lpVolumeTable] + shr ebx,2 + shr ecx,2 + + mov eax,ebp ; convert accumulator and pitch + sar eax,ACCURACY ; to 32.32 fixed point + shl ebp,32-ACCURACY + add esi,eax + mov eax,edx + sar edx,ACCURACY + shl eax,32-ACCURACY + mov [nStepLo],eax + mov [nStepHi],edx + + mov bl,[2*esi+1] ; get first sample and advance + add ebp,eax + adc esi,edx + mov cl,bl + + mov eax,[nCount] ; jump inside of the unrolled loop + mov edx,eax + and eax,0fh + shr edx,4 + lea edi,[edi+eax*8+(-80h)] + mov [nCount],edx + jmp dword ptr [TBL16S+eax*4] + +RESAMPLE16S macro disp + mov eax,[ebx*4] ; 7 cycles/sample + mov edx,[edi+8*disp] + add eax,edx + mov edx,[edi+8*disp+4] + mov [edi+8*disp],eax + mov eax,[ecx*4] + add eax,edx + mov bl,[2*esi+1] + mov [edi+8*disp+4],eax + mov eax,[nStepLo] + add ebp,eax + mov edx,[nStepHi] + adc esi,edx + mov cl,bl +E16S&disp: + endm + + align 4 +L16S: RESAMPLE16S 0 + RESAMPLE16S 1 + RESAMPLE16S 2 + RESAMPLE16S 3 + RESAMPLE16S 4 + RESAMPLE16S 5 + RESAMPLE16S 6 + RESAMPLE16S 7 + RESAMPLE16S 8 + RESAMPLE16S 9 + RESAMPLE16S 10 + RESAMPLE16S 11 + RESAMPLE16S 12 + RESAMPLE16S 13 + RESAMPLE16S 14 + RESAMPLE16S 15 + add edi,80h + dec [nCount] + jge L16S + + mov eax,[nStepLo] ; go back one step + mov edx,[nStepHi] + sub ebp,eax + sbb esi,edx + pop eax ; get and save accumulator + sub esi,eax + shrd ebp,esi,32-ACCURACY + pop esi + mov [esi+ACCUM],ebp + mov [esi+RESERVED],bl + + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + pop ebp + ret + + align 4 +TBL16S dd offset E16S15 + dd offset E16S14 + dd offset E16S13 + dd offset E16S12 + dd offset E16S11 + dd offset E16S10 + dd offset E16S9 + dd offset E16S8 + dd offset E16S7 + dd offset E16S6 + dd offset E16S5 + dd offset E16S4 + dd offset E16S3 + dd offset E16S2 + dd offset E16S1 + dd offset E16S0 +MixAudioPan16S endp + +; +; 16-bit full right stereo mixing routine +; + align 4 +MixAudioRight16S proc + add edi,4 +MixAudioRight16S endp + +; +; 16-bit full left stereo mixing routine +; + align 4 +MixAudioLeft16S proc + mov [nCount],ecx ; save counter + push esi + mov ecx,[esi+ACCUM] ; get voice parameters + mov ebp,[esi+PITCH] + movzx ebx,[esi+VOLUME] + mov esi,[esi+LPDATA] + shr esi,1 + shl ebx,10 ; get volume table address + push esi + mov eax,ecx + add ebx,[_lpVolumeTable] ; convert accumulator and pitch + sar eax,ACCURACY ; to 32.32 fixed point + shr ebx,2 + shl ecx,32-ACCURACY + mov edx,ebp + add esi,eax + sar edx,ACCURACY + shl ebp,32-ACCURACY + mov [nStepHi],edx + + mov bl,[2*esi+1] ; get first sample and advance + add ecx,ebp + adc esi,edx + + mov eax,[nCount] ; jump inside of the unrolled loop + mov edx,eax + and eax,0fh + shr edx,4 + lea edi,[edi+eax*8+(-80h)] + mov [nCount],edx + jmp dword ptr [TBL16L+eax*4] + +RESAMPLE16L macro disp + mov edx,[edi+8*disp] ; 4 cycles/sample + mov eax,[ebx*4] + add eax,edx + add ecx,ebp + mov bl,[2*esi+1] + mov edx,[nStepHi] + adc esi,edx + mov [edi+8*disp],eax +E16L&disp: + endm + + align 4 +L16L: RESAMPLE16L 0 + RESAMPLE16L 1 + RESAMPLE16L 2 + RESAMPLE16L 3 + RESAMPLE16L 4 + RESAMPLE16L 5 + RESAMPLE16L 6 + RESAMPLE16L 7 + RESAMPLE16L 8 + RESAMPLE16L 9 + RESAMPLE16L 10 + RESAMPLE16L 11 + RESAMPLE16L 12 + RESAMPLE16L 13 + RESAMPLE16L 14 + RESAMPLE16L 15 + add edi,80h + dec [nCount] + jge L16L + + mov eax,[nStepHi] ; go back one step + sub ecx,ebp + sbb esi,eax + pop eax + sub esi,eax ; get and save accumulator + shrd ecx,esi,32-ACCURACY + pop esi + mov [esi+ACCUM],ecx + mov [esi+RESERVED],bl + + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + pop ebp + ret + + align 4 +TBL16L dd offset E16L15 + dd offset E16L14 + dd offset E16L13 + dd offset E16L12 + dd offset E16L11 + dd offset E16L10 + dd offset E16L9 + dd offset E16L8 + dd offset E16L7 + dd offset E16L6 + dd offset E16L5 + dd offset E16L4 + dd offset E16L3 + dd offset E16L2 + dd offset E16L1 + dd offset E16L0 +MixAudioLeft16S endp + +; +; 16-bit middle stereo mixing routine +; + align 4 +MixAudioMiddle16S proc + mov [nCount],ecx ; save counter + push esi + mov ecx,[esi+ACCUM] ; get voice parameters + mov ebp,[esi+PITCH] + movzx ebx,[esi+VOLUME] + mov esi,[esi+LPDATA] + shr esi,1 + shr ebx,1 + shl ebx,10 ; get volume table address + push esi + mov eax,ecx + add ebx,[_lpVolumeTable] ; convert accumulator and pitch + sar eax,ACCURACY ; to 32.32 fixed point + shr ebx,2 + shl ecx,32-ACCURACY + mov edx,ebp + add esi,eax + sar edx,ACCURACY + shl ebp,32-ACCURACY + mov [nStepHi],edx + + mov bl,[2*esi+1] ; get first sample and advance + add ecx,ebp + adc esi,edx + + mov eax,[nCount] ; jump inside of the unrolled loop + mov edx,eax + and eax,0fh + shr edx,4 + lea edi,[edi+eax*8+(-80h)] + mov [nCount],edx + jmp dword ptr [TBL16C+eax*4] + +RESAMPLE16C macro disp + mov edx,[edi+8*disp+0] ; 4 cycles/sample + mov eax,[ebx*4] + add edx,eax + mov bl,[2*esi+1] + mov [edi+8*disp+0],edx + mov edx,[edi+8*disp+4] + add edx,eax + mov eax,[nStepHi] + mov [edi+8*disp+4],edx + add ecx,ebp + adc esi,eax +E16C&disp: + endm + + align 4 +L16C: RESAMPLE16C 0 + RESAMPLE16C 1 + RESAMPLE16C 2 + RESAMPLE16C 3 + RESAMPLE16C 4 + RESAMPLE16C 5 + RESAMPLE16C 6 + RESAMPLE16C 7 + RESAMPLE16C 8 + RESAMPLE16C 9 + RESAMPLE16C 10 + RESAMPLE16C 11 + RESAMPLE16C 12 + RESAMPLE16C 13 + RESAMPLE16C 14 + RESAMPLE16C 15 + add edi,80h + dec [nCount] + jge L16C + + mov eax,[nStepHi] ; go back one step + sub ecx,ebp + sbb esi,eax + pop eax + sub esi,eax ; get and save accumulator + shrd ecx,esi,32-ACCURACY + pop esi + mov [esi+ACCUM],ecx + mov [esi+RESERVED],bl + + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + pop ebp + ret + + align 4 +TBL16C dd offset E16C15 + dd offset E16C14 + dd offset E16C13 + dd offset E16C12 + dd offset E16C11 + dd offset E16C10 + dd offset E16C9 + dd offset E16C8 + dd offset E16C7 + dd offset E16C6 + dd offset E16C5 + dd offset E16C4 + dd offset E16C3 + dd offset E16C2 + dd offset E16C1 + dd offset E16C0 +MixAudioMiddle16S endp + + + +; +; VOID cdecl MixAudioData16MI(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) +; + align 4 +MixAudioData16MI proc +_MixAudioData16MI: +_MixAudioData16MI@12: + push ebp + mov ebp,esp + push eax + push ebx + push ecx + push edx + push esi + push edi + + mov edi,[ebp+08h] ; get parameters + mov ecx,[ebp+0ch] + mov esi,[ebp+10h] + + mov eax,[esi+PITCH] ; select mixing routine + cmp eax,+(1 SHL ACCURACY) + jge __MixAudioData16M + cmp eax,-(1 SHL ACCURACY) + jle __MixAudioData16M + + mov [nCount],ecx ; save counter + push esi + mov ebp,[esi+ACCUM] ; get accumulator + mov ecx,[esi+PITCH] ; get pitch + movzx ebx,[esi+VOLUME] ; get volume + mov dl,[esi+RESERVED] ; get last sample + mov esi,[esi+LPDATA] ; get data address + shr esi,1 + push esi + + shl ebx,10 ; get volume table address + add ebx,[_lpVolumeTable] + shr ebx,2 + mov bl,dl ; save sample for filtering + + mov eax,ebp ; convert accumulator + sar eax,ACCURACY + shl ebp,32-ACCURACY + add esi,eax + + mov edx,ecx ; get filter table address + mov eax,ecx + shl ecx,32-ACCURACY + sar eax,ACCURACY ; convert pitch + mov [nStepHi],eax + test edx,edx + jge L20 + neg edx +L20: shr edx,ACCURACY-5 + shl edx,8 + add edx,[_lpFilterTable] + + mov eax,[nCount] ; jump inside of the loop + and eax,0fh + lea edi,[edi+eax*4+(-40h)] + shr [nCount],4 + jmp dword ptr [TBL16MI+eax*4] + +RESAMPLE16MI macro disp + mov dl,bl + sub bl,[edx] + mov dl,[2*esi+1] + mov dl,[edx] + mov eax,[nStepHi] + add bl,dl + add ebp,ecx + adc esi,eax + mov eax,[ebx*4] + add [edi+4*disp],eax +E16MI&disp: + endm + +L16MI: RESAMPLE16MI 0 ; 11 cycles/sample + RESAMPLE16MI 1 + RESAMPLE16MI 2 + RESAMPLE16MI 3 + RESAMPLE16MI 4 + RESAMPLE16MI 5 + RESAMPLE16MI 6 + RESAMPLE16MI 7 + RESAMPLE16MI 8 + RESAMPLE16MI 9 + RESAMPLE16MI 10 + RESAMPLE16MI 11 + RESAMPLE16MI 12 + RESAMPLE16MI 13 + RESAMPLE16MI 14 + RESAMPLE16MI 15 + add edi,40h + dec [nCount] + jge L16MI + + pop eax + sub esi,eax ; get and save accumulator + shrd ebp,esi,32-ACCURACY + pop esi + mov [esi+ACCUM],ebp + mov [esi+RESERVED],bl + + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + pop ebp + ret + + align 4 +TBL16MI dd offset E16MI15 + dd offset E16MI14 + dd offset E16MI13 + dd offset E16MI12 + dd offset E16MI11 + dd offset E16MI10 + dd offset E16MI9 + dd offset E16MI8 + dd offset E16MI7 + dd offset E16MI6 + dd offset E16MI5 + dd offset E16MI4 + dd offset E16MI3 + dd offset E16MI2 + dd offset E16MI1 + dd offset E16MI0 +MixAudioData16MI endp + +; +; VOID cdecl MixAudioData16SI(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) +; + align 4 +MixAudioData16SI proc +_MixAudioData16SI: +_MixAudioData16SI@12: + push ebp + mov ebp,esp + push eax + push ebx + push ecx + push edx + push esi + push edi + + mov edi,[ebp+08h] ; get parameters + mov ecx,[ebp+0ch] + mov esi,[ebp+10h] + + mov eax,[esi+PITCH] ; select mixing routine + cmp eax,+(1 SHL ACCURACY) + jge __MixAudioData16S + cmp eax,-(1 SHL ACCURACY) + jle __MixAudioData16S + + mov al,[esi+PANNING] ; select panning routine + cmp al,10h + jb MixAudioLeft16SI + cmp al,78h + jb MixAudioPan16SI + cmp al,88h + jb MixAudioMiddle16SI + cmp al,0f0h + jae MixAudioRight16SI +MixAudioData16SI endp + + +; +; 16-bit general stereo mixing routine +; + align 4 +MixAudioPan16SI proc + mov [nCount],ecx ; save counter + push esi + mov ebp,[esi+ACCUM] ; get voice parameters + mov edx,[esi+PITCH] + movzx ebx,[esi+VOLUME] + movzx ecx,[esi+PANNING] + mov al,[esi+RESERVED] + mov esi,[esi+LPDATA] + shr esi,1 + + push esi ; get volume table addresses + imul ecx,ebx + shr ecx,8 + sub ebx,ecx + shl ebx,10 + shl ecx,10 + add ebx,[_lpVolumeTable] + add ecx,[_lpVolumeTable] + shr ebx,2 + shr ecx,2 + mov bl,al ; save sample for filtering + + mov eax,ebp ; convert accumulator + sar eax,ACCURACY + shl ebp,32-ACCURACY + add esi,eax + + mov eax,edx ; convert pitch + test edx,edx + jge L21 + neg edx +L21: shr edx,ACCURACY-5 + shl edx,8 + add edx,[_lpFilterTable] + push eax + shl eax,32-ACCURACY + mov [nStepLo],eax + pop eax + sar eax,ACCURACY + mov [nStepHi],eax + + mov eax,[nCount] ; jump inside of the loop + and eax,0fh + lea edi,[edi+eax*8+(-80h)] + shr [nCount],4 + jmp dword ptr [TBL16PI+eax*4] + +RESAMPLE16PI macro disp + mov dl,bl + sub bl,[edx] + mov dl,[2*esi+1] + mov dl,[edx] + mov eax,[nStepLo] + add bl,dl + add ebp,eax + mov cl,bl + mov eax,[nStepHi] + adc esi,eax + mov eax,[ebx*4] + add [edi+8*disp],eax + mov eax,[ecx*4] + add [edi+8*disp+4],eax +E16PI&disp: + endm + + align 4 +L16PI: RESAMPLE16PI 0 ; 15 cycles/sample + RESAMPLE16PI 1 + RESAMPLE16PI 2 + RESAMPLE16PI 3 + RESAMPLE16PI 4 + RESAMPLE16PI 5 + RESAMPLE16PI 6 + RESAMPLE16PI 7 + RESAMPLE16PI 8 + RESAMPLE16PI 9 + RESAMPLE16PI 10 + RESAMPLE16PI 11 + RESAMPLE16PI 12 + RESAMPLE16PI 13 + RESAMPLE16PI 14 + RESAMPLE16PI 15 + add edi,80h + dec [nCount] + jge L16PI + + pop eax ; get and save accumulator + sub esi,eax + shrd ebp,esi,32-ACCURACY + pop esi + mov [esi+ACCUM],ebp + mov [esi+RESERVED],bl + + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + pop ebp + ret + + align 4 +TBL16PI dd offset E16PI15 + dd offset E16PI14 + dd offset E16PI13 + dd offset E16PI12 + dd offset E16PI11 + dd offset E16PI10 + dd offset E16PI9 + dd offset E16PI8 + dd offset E16PI7 + dd offset E16PI6 + dd offset E16PI5 + dd offset E16PI4 + dd offset E16PI3 + dd offset E16PI2 + dd offset E16PI1 + dd offset E16PI0 +MixAudioPan16SI endp + +; +; 16-bit full right stereo mixing routine +; + align 4 +MixAudioRight16SI proc + add edi,4 +MixAudioRight16SI endp + +; +; 16-bit full left stereo mixing routine +; + align 4 +MixAudioLeft16SI proc + mov [nCount],ecx ; save counter + push esi + mov ebp,[esi+ACCUM] ; get accumulator + mov ecx,[esi+PITCH] ; get pitch + movzx ebx,[esi+VOLUME] ; get volume + mov dl,[esi+RESERVED] ; get last sample + mov esi,[esi+LPDATA] ; get data address + shr esi,1 + push esi + + shl ebx,10 ; get volume table address + add ebx,[_lpVolumeTable] + shr ebx,2 + mov bl,dl ; save sample for filtering + + mov eax,ebp ; convert accumulator + sar eax,ACCURACY + shl ebp,32-ACCURACY + add esi,eax + + mov edx,ecx ; get filter table address + mov eax,ecx + shl ecx,32-ACCURACY + sar eax,ACCURACY ; convert pitch + mov [nStepHi],eax + test edx,edx + jge L22 + neg edx +L22: shr edx,ACCURACY-5 + shl edx,8 + add edx,[_lpFilterTable] + + mov eax,[nCount] ; jump inside of the loop + and eax,0fh + lea edi,[edi+eax*8+(-80h)] + shr [nCount],4 + jmp dword ptr [TBL16LI+eax*4] + +RESAMPLE16LI macro disp + mov dl,bl + sub bl,[edx] + mov dl,[2*esi+1] + mov dl,[edx] + mov eax,[nStepHi] + add bl,dl + add ebp,ecx + adc esi,eax + mov eax,[ebx*4] + add [edi+8*disp],eax +E16LI&disp: + endm + +L16LI: RESAMPLE16LI 0 ; 11 cycles/sample + RESAMPLE16LI 1 + RESAMPLE16LI 2 + RESAMPLE16LI 3 + RESAMPLE16LI 4 + RESAMPLE16LI 5 + RESAMPLE16LI 6 + RESAMPLE16LI 7 + RESAMPLE16LI 8 + RESAMPLE16LI 9 + RESAMPLE16LI 10 + RESAMPLE16LI 11 + RESAMPLE16LI 12 + RESAMPLE16LI 13 + RESAMPLE16LI 14 + RESAMPLE16LI 15 + add edi,80h + dec [nCount] + jge L16LI + + pop eax + sub esi,eax ; get and save accumulator + shrd ebp,esi,32-ACCURACY + pop esi + mov [esi+ACCUM],ebp + mov [esi+RESERVED],bl + + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + pop ebp + ret + + align 4 +TBL16LI dd offset E16LI15 + dd offset E16LI14 + dd offset E16LI13 + dd offset E16LI12 + dd offset E16LI11 + dd offset E16LI10 + dd offset E16LI9 + dd offset E16LI8 + dd offset E16LI7 + dd offset E16LI6 + dd offset E16LI5 + dd offset E16LI4 + dd offset E16LI3 + dd offset E16LI2 + dd offset E16LI1 + dd offset E16LI0 +MixAudioLeft16SI endp + + +; +; 16-bit middle stereo mixing routine +; + align 4 +MixAudioMiddle16SI proc + mov [nCount],ecx ; save counter + push esi + mov ebp,[esi+ACCUM] ; get accumulator + mov ecx,[esi+PITCH] ; get pitch + movzx ebx,[esi+VOLUME] ; get volume + mov dl,[esi+RESERVED] ; get last sample + mov esi,[esi+LPDATA] ; get data address + shr esi,1 + push esi + + shr ebx,1 ; get volume table address + shl ebx,10 + add ebx,[_lpVolumeTable] + shr ebx,2 + mov bl,dl ; save sample for filtering + + mov eax,ebp ; convert accumulator + sar eax,ACCURACY + shl ebp,32-ACCURACY + add esi,eax + + mov edx,ecx ; get filter table address + mov eax,ecx + shl ecx,32-ACCURACY + sar eax,ACCURACY ; convert pitch + mov [nStepHi],eax + test edx,edx + jge L23 + neg edx +L23: shr edx,ACCURACY-5 + shl edx,8 + add edx,[_lpFilterTable] + + mov eax,[nCount] ; jump inside of the loop + and eax,0fh + lea edi,[edi+eax*8+(-80h)] + shr [nCount],4 + jmp dword ptr [TBL16CI+eax*4] + +RESAMPLE16CI macro disp + mov dl,bl + sub bl,[edx] + mov dl,[2*esi+1] + mov dl,[edx] + mov eax,[nStepHi] + add bl,dl + add ebp,ecx + adc esi,eax + mov eax,[ebx*4] + add [edi+8*disp],eax + add [edi+8*disp+4],eax +E16CI&disp: + endm + +L16CI: RESAMPLE16CI 0 ; 14 cycles/sample + RESAMPLE16CI 1 + RESAMPLE16CI 2 + RESAMPLE16CI 3 + RESAMPLE16CI 4 + RESAMPLE16CI 5 + RESAMPLE16CI 6 + RESAMPLE16CI 7 + RESAMPLE16CI 8 + RESAMPLE16CI 9 + RESAMPLE16CI 10 + RESAMPLE16CI 11 + RESAMPLE16CI 12 + RESAMPLE16CI 13 + RESAMPLE16CI 14 + RESAMPLE16CI 15 + add edi,80h + dec [nCount] + jge L16CI + + pop eax + sub esi,eax ; get and save accumulator + shrd ebp,esi,32-ACCURACY + pop esi + mov [esi+ACCUM],ebp + mov [esi+RESERVED],bl + + pop edi + pop esi + pop edx + pop ecx + pop ebx + pop eax + pop ebp + ret + + align 4 +TBL16CI dd offset E16CI15 + dd offset E16CI14 + dd offset E16CI13 + dd offset E16CI12 + dd offset E16CI11 + dd offset E16CI10 + dd offset E16CI9 + dd offset E16CI8 + dd offset E16CI7 + dd offset E16CI6 + dd offset E16CI5 + dd offset E16CI4 + dd offset E16CI3 + dd offset E16CI2 + dd offset E16CI1 + dd offset E16CI0 +MixAudioMiddle16SI endp + + end diff --git a/seal-hack/src/allegdrv.c b/seal-hack/src/allegdrv.c new file mode 100644 index 0000000..a0be547 --- /dev/null +++ b/seal-hack/src/allegdrv.c @@ -0,0 +1,172 @@ +/* + * $Id: lnxdrv.c 1.5 1996/08/05 18:51:19 chasan released $ + * + * SDL audio driver. Turns SEAL into a mixer on top of SDL. + * + * Copyright 2002 Greg Velichansky (hmaon@bumba.net) + * + * Based in part on the Linux Voxware driver, + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +#ifdef __APPLE__ +#define USE_CONSOLE +#include +#else +#define USE_CONSOLE +#include +#endif + +#include "audio.h" +#include "drivers.h" + + +/* + * fragments defines + */ +#define NUMFRAGS 16 +#define FRAGSIZE 11 +#define BUFFERSIZE (1 << FRAGSIZE) + +/* + * configuration structure + */ +static struct AudioStruct { + AUDIOSTREAM *stream; + BYTE aBuffer[BUFFERSIZE*4]; + LPFNAUDIOWAVE lpfnAudioWave; + WORD wFormat; +} Audio; + + +/* + * Linux driver API interface + */ +static UINT AIAPI GetAudioCaps(LPAUDIOCAPS lpCaps) +{ + static AUDIOCAPS Caps = + { + AUDIO_PRODUCT_LINUX, "Allegro", + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_1M16 | AUDIO_FORMAT_1S16 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_2M16 | AUDIO_FORMAT_2S16 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 | + AUDIO_FORMAT_4M16 | AUDIO_FORMAT_4S16 + }; + + memcpy(lpCaps, &Caps, sizeof(AUDIOCAPS)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI PingAudio(VOID) +{ + return 0; +/* return (SDL_INIT_AUDIO == SDL_WasInit(SDL_INIT_AUDIO)); */ +} + +static UINT AIAPI OpenAudio(LPAUDIOINFO lpInfo) +{ + int nBitsPerSample, nStereoOn, nSampleRate, nFrags; + + memset(&Audio, 0, sizeof(Audio)); + + allegro_init(); + + if (install_sound(DIGI_AUTODETECT, MIDI_NONE, "") != 0) + return AUDIO_ERROR_NODEVICE; + + //nBitsPerSample = lpInfo->wFormat & AUDIO_FORMAT_16BITS ? 16 : 8; + //nStereoOn = lpInfo->wFormat & AUDIO_FORMAT_STEREO ? 1 : 0; + /*nSampleRate = lpInfo->nSampleRate;*/ + +/* Audio.desired.freq = lpInfo->nSampleRate; + Audio.desired.samples = 512; + Audio.desired.channels = nStereoOn ? 2 : 1; + + Audio.desired.format = (lpInfo->wFormat & AUDIO_FORMAT_16BITS) ? AUDIO_U16SYS : AUDIO_U8; + + Audio.desired.userdata = (void*)&Audio; + + Audio.desired.callback = updatecallback;*/ + + //SDL_OpenAudio(&(Audio.desired), &(Audio.spec)); + Audio.stream = play_audio_stream(BUFFERSIZE, 16, TRUE, lpInfo->nSampleRate, 255, 128); + voice_start(Audio.stream->voice); + + /* we should probably do something here... blah... whatever :/ */ + + /* setup number and size of buffer fragments */ + /*nFrags = (NUMFRAGS << 16) + (FRAGSIZE); + ioctl(Audio.nHandle, SNDCTL_DSP_SETFRAGMENT, &nFrags);*/ + + /* setup audio playback encoding format and sampling frequency */ + /*if (ioctl(Audio.nHandle, SNDCTL_DSP_SAMPLESIZE, &nBitsPerSample) < 0 || + ioctl(Audio.nHandle, SNDCTL_DSP_STEREO, &nStereoOn) < 0 || + ioctl(Audio.nHandle, SNDCTL_DSP_SPEED, &nSampleRate) < 0) { + close(Audio.nHandle); + return AUDIO_ERROR_BADFORMAT; + }*/ + + /*Audio.wFormat = lpInfo->wFormat;*/ + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI CloseAudio(VOID) +{ + //SDL_CloseAudio(); + voice_stop(Audio.stream); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudio(UINT nFrames) +{ + unsigned char *Buf; + Buf = get_audio_stream_buffer(Audio.stream); + /* compute frame size */ + if (Audio.wFormat & AUDIO_FORMAT_16BITS) nFrames <<= 1; + if (Audio.wFormat & AUDIO_FORMAT_STEREO) nFrames <<= 1; + if (nFrames <= 0 || nFrames > sizeof(Audio.aBuffer)) + nFrames = sizeof(Audio.aBuffer); + + /* send PCM samples to the DSP audio device */ + if (Audio.lpfnAudioWave != NULL) { + Audio.lpfnAudioWave(Buf, nFrames); + } + + + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + /* set up DSP audio device user's callback function */ + Audio.lpfnAudioWave = lpfnAudioWave; + return AUDIO_ERROR_NONE; +} + + +/* + * Linux driver public interface + */ +AUDIOWAVEDRIVER AllegWaveDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudio, SetAudioCallback +}; + +AUDIODRIVER AllegDriver = +{ + &AllegWaveDriver, NULL +}; diff --git a/seal-hack/src/ariadrv.c b/seal-hack/src/ariadrv.c new file mode 100644 index 0000000..69c2611 --- /dev/null +++ b/seal-hack/src/ariadrv.c @@ -0,0 +1,370 @@ +/* + * $Id: ariadrv.c 1.6 1996/08/05 18:51:19 chasan released $ + * + * Sierra Semiconductors' Aria soundcard audio driver. + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include "audio.h" +#include "drivers.h" +#include "msdos.h" + +/* + * Aria DSP chip register offsets + */ +#define ARIA_CMD 0x000 /* Aria DSP command port */ +#define ARIA_STAT 0x002 /* Aria DSP write status */ +#define ARIA_ADDR 0x004 /* Aria DSP memory address */ +#define ARIA_DATA 0x006 /* Aria DSP indexed memory data */ + +/* + * Aria DSP playback mode defines + */ +#define ARIA_MODE_0 0x0000 /* 4 mono or 2 stereo PCM channels */ +#define ARIA_MODE_1 0x0001 /* 2 mono or 1 stereo PCM channels */ +#define ARIA_MODE_2 0x0002 /* 2 mono or 1 stereo PCM channels */ + +/* + * Aria DSP playback format defines + */ +#define ARIA_FMT_11025 0x0000 /* select 11025 Hz sampling rate */ +#define ARIA_FMT_22050 0x0010 /* select 22050 Hz sampling rate */ +#define ARIA_FMT_44100 0x0020 /* select 44100 Hz sampling rate */ +#define ARIA_FMT_MONO 0x0000 /* select mono output */ +#define ARIA_FMT_STEREO 0x0001 /* select stereo output */ +#define ARIA_FMT_8BIT 0x0000 /* select 8-bit PCM encoding */ +#define ARIA_FMT_16BIT 0x0002 /* select 16-bit PCM encoding */ +#define ARIA_FMT_ADPCM 0x0004 /* select ADPCM encoding */ + +#define BUFFERSIZE 50 /* buffer length in milliseconds */ +#define PACKETSIZE 1024 /* packet size in bytes */ +#define TIMEOUT 60000 /* timeout counter for DSP writes */ + + +/* + * Aria DSP configuration structure + */ +static struct { + WORD wFormat; /* playback encoding format */ + WORD nSampleRate; /* sampling frequency */ + WORD wFmt; /* Aria DSP format command */ + WORD wPort; /* base I/O port address */ + BYTE nIrqLine; /* interrupt request line */ + BYTE nDmaChannel; /* direct memory access channel */ + LPBYTE lpBuffer; /* DMA buffer address */ + UINT nBufferSize; /* DMA buffer length in bytes */ + UINT nPosition; /* DMA buffer playing position */ + UINT nWritePosition; /* DMA buffer DSP write position */ + LPFNAUDIOWAVE lpfnAudioWave; /* user wave callback function */ +} Aria; + + +/* + * Aria DSP low level programming routines + */ +static VOID ARPortW(WORD wCmd) +{ + UINT n; + + /* wait until the Aria DSP is ready to receive a command */ + for (n = 0; n < TIMEOUT; n++) { + if (!(INW(Aria.wPort + ARIA_STAT) & 0x8000)) + break; + } + /* send the command to the Aria DSP chip */ + OUTW(Aria.wPort + ARIA_CMD, wCmd); +} + +static VOID ARPokeW(WORD nIndex, WORD wData) +{ + OUTB(Aria.wPort + ARIA_ADDR, nIndex); + OUTB(Aria.wPort + ARIA_DATA, wData); +} + +static WORD ARPeekW(WORD nIndex) +{ + OUTW(Aria.wPort + ARIA_ADDR, nIndex); + return INW(Aria.wPort + ARIA_DATA); +} + +static VOID ARSetPlaybackMode(WORD nMode) +{ + /* + * Setup Aria's playback mode to one of the following: + * + * ARIA_MODE_0 4 mono or 2 stereo PCM channels, no synth operators + * ARIA_MODE_1 2 mono or 1 stereo PCM channels, 20 synth operators + * ARIA_MODE_2 2 mono or 1 stereo PCM channels, 32 synth operators + * + */ + ARPortW(0x0006); + ARPortW(nMode); + ARPortW(0xFFFF); +} + +static VOID ARStartPlayback(VOID) +{ + ARPortW(0x0011); + ARPortW(0x0000); + ARPortW(0xFFFF); +} + +static VOID ARStopPlayback(VOID) +{ + ARPortW(0x0012); + ARPortW(0x0000); + ARPortW(0xFFFF); +} + +static VOID ARSetFormat(WORD wFmt) +{ + /* we have to set some parameters to play at 44100 Hz */ + if (wFmt & ARIA_FMT_44100) { + ARSetPlaybackMode(ARIA_MODE_0); + OUTW(Aria.wPort + ARIA_STAT, 0x008A); + } + ARPortW(0x0003); + ARPortW(wFmt); + ARPortW(0xFFFF); +} + +static VOID ARInit(VOID) +{ + UINT n; + + /* + * Set up Aria in native mode (disable SB emulation mode), + * first initialize the chip and then clear the init flag. + */ + OUTW(Aria.wPort + ARIA_STAT, 0x00C8); + ARPokeW(0x6102, 0x0000); + + /* Aria DSP initialization */ + ARPortW(0x0000); + ARPortW(0x0000); + ARPortW(0x0000); + ARPortW(0x0000); + ARPortW(0xFFFF); + + /* wait until Aria DSP initialization finishes */ + for (n = 0; n < TIMEOUT; n++) { + if (ARPeekW(0x6102) == 1) + break; + } + + /* complete Aria initialization */ + OUTW(Aria.wPort + ARIA_CMD, 0x00CA); +} + +static VOID ARReset(WORD wFmt) +{ + /* + * We need to reset the Aria chip back to 22050 Hz + * when it was programmed to play at 44100 Hz. + */ + if (wFmt & ARIA_FMT_44100) { + ARSetPlaybackMode(ARIA_MODE_2); + OUTW(Aria.wPort + ARIA_STAT, 0x00CA); + } + + /* switch back to SB emulation mode */ + OUTW(Aria.wPort + ARIA_STAT, 0x0040); +} + +static VOID AIAPI ARInterruptHandler(VOID) +{ + LPWORD lpPacket; + WORD wAddress; + UINT n; + + /* check interrupt type and exit if not generated by Aria */ + if (INW(Aria.wPort + ARIA_CMD) == 1) { + /* play a packet of samples from our buffer */ + wAddress = 0x8000 - PACKETSIZE + ARPeekW(0x6100); + OUTW(Aria.wPort + ARIA_ADDR, wAddress); + lpPacket = (LPWORD) (Aria.lpBuffer + Aria.nWritePosition); + for (n = 0; n < PACKETSIZE/2; n++) { + OUTW(Aria.wPort + ARIA_DATA, *lpPacket++); + } + if ((Aria.nWritePosition += PACKETSIZE) >= Aria.nBufferSize) + Aria.nWritePosition -= Aria.nBufferSize; + ARPortW(0x0010); + ARPortW(0xFFFF); + } +} + + +/* + * Aria audio driver API interface + */ +static UINT AIAPI PingAudio(VOID) +{ + LPSTR lpszAria; + UINT nChar; + + if ((lpszAria = DosGetEnvironment("ARIA")) != NULL) { + Aria.wPort = 0x290; + Aria.nIrqLine = 10; + Aria.nDmaChannel = 5; + nChar = DosParseString(lpszAria, TOKEN_CHAR); + while (nChar != 0) { + switch (nChar) { + case 'A': + case 'a': + Aria.wPort = DosParseString(NULL, TOKEN_HEX); + break; + case 'I': + case 'i': + Aria.nIrqLine = DosParseString(NULL, TOKEN_DEC); + break; + case 'D': + case 'd': + Aria.nDmaChannel = DosParseString(NULL, TOKEN_DEC); + break; + } + nChar = DosParseString(NULL, TOKEN_CHAR); + } + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_NODEVICE; +} + +static UINT AIAPI GetAudioCaps(LPAUDIOCAPS lpCaps) +{ + static AUDIOCAPS Caps = + { + AUDIO_PRODUCT_ARIA, "Aria sound card", + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_1M16 | AUDIO_FORMAT_1S16 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_2M16 | AUDIO_FORMAT_2S16 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 | + AUDIO_FORMAT_4M16 | AUDIO_FORMAT_4S16 + }; + + memcpy(lpCaps, &Caps, sizeof(AUDIOCAPS)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI OpenAudio(LPAUDIOINFO lpInfo) +{ + DWORD dwBytesPerSecond; + + memset(&Aria, 0, sizeof(Aria)); + + /* + * Initialize the Aria DSP configuration parameters + */ + Aria.wFormat = lpInfo->wFormat; + Aria.nSampleRate = lpInfo->nSampleRate < 16357 ? 11025 : + (lpInfo->nSampleRate < 33075 ? 22050 : 44100); + if (PingAudio()) + return AUDIO_ERROR_NODEVICE; + + /* + * Allocate and clean DMA buffer used for playback + */ + dwBytesPerSecond = Aria.nSampleRate; + if (Aria.wFormat & AUDIO_FORMAT_16BITS) + dwBytesPerSecond <<= 1; + if (Aria.wFormat & AUDIO_FORMAT_STEREO) + dwBytesPerSecond <<= 1; + Aria.nBufferSize = dwBytesPerSecond / (1000 / (BUFFERSIZE >> 1)); + Aria.nBufferSize = (Aria.nBufferSize + PACKETSIZE) & -PACKETSIZE; + Aria.nBufferSize <<= 1; + if ((Aria.lpBuffer = malloc(Aria.nBufferSize)) == NULL) + return AUDIO_ERROR_NOMEMORY; + memset(Aria.lpBuffer, Aria.wFormat & AUDIO_FORMAT_16BITS ? + 0x00 : 0x80, Aria.nBufferSize); + + /* + * Initialize the Aria DSP chip, set playback format, + * sampling frequency and start the DAC transfer. + */ + ARInit(); + DosSetVectorHandler(Aria.nIrqLine, ARInterruptHandler); + Aria.wFmt = Aria.wFormat & AUDIO_FORMAT_16BITS ? + ARIA_FMT_16BIT : ARIA_FMT_8BIT; + Aria.wFmt |= Aria.wFormat & AUDIO_FORMAT_STEREO ? + ARIA_FMT_STEREO : ARIA_FMT_MONO; + Aria.wFmt |= (Aria.nSampleRate <= 11025 ? ARIA_FMT_11025 : + (Aria.nSampleRate <= 22050 ? ARIA_FMT_22050 : ARIA_FMT_44100)); + ARSetFormat(Aria.wFmt); + ARStartPlayback(); + + /* refresh caller's format and sampling frequency */ + lpInfo->wFormat = Aria.wFormat; + lpInfo->nSampleRate = Aria.nSampleRate; + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI CloseAudio(VOID) +{ + ARStopPlayback(); + ARReset(Aria.wFmt); + DosSetVectorHandler(Aria.nIrqLine, NULL); + if (Aria.lpBuffer != NULL) + free(Aria.lpBuffer); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudio(UINT nFrames) +{ + int nBlockSize, nSize; + + if (Aria.wFormat & AUDIO_FORMAT_16BITS) nFrames <<= 1; + if (Aria.wFormat & AUDIO_FORMAT_STEREO) nFrames <<= 1; + if (nFrames <= 0 || nFrames > Aria.nBufferSize) + nFrames = Aria.nBufferSize; + + if ((nBlockSize = Aria.nWritePosition - Aria.nPosition) < 0) + nBlockSize += Aria.nBufferSize; + + if (nBlockSize > nFrames) + nBlockSize = nFrames; + + while (nBlockSize != 0) { + if ((nSize = Aria.nBufferSize - Aria.nPosition) > nBlockSize) + nSize = nBlockSize; + if (Aria.lpfnAudioWave != NULL) { + Aria.lpfnAudioWave(&Aria.lpBuffer[Aria.nPosition], nSize); + } + else { + memset(&Aria.lpBuffer[Aria.nPosition], + Aria.wFormat & AUDIO_FORMAT_16BITS ? 0x00 : 0x80, nSize); + } + if ((Aria.nPosition += nSize) >= Aria.nBufferSize) + Aria.nPosition -= Aria.nBufferSize; + nBlockSize -= nSize; + } + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + Aria.lpfnAudioWave = lpfnAudioWave; + return AUDIO_ERROR_NONE; +} + + +/* + * Aria DSP audio driver public interface + */ +AUDIOWAVEDRIVER AriaWaveDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudio, SetAudioCallback +}; + +AUDIODRIVER AriaDriver = +{ + &AriaWaveDriver, NULL +}; diff --git a/seal-hack/src/audio.c b/seal-hack/src/audio.c new file mode 100644 index 0000000..b3ecfeb --- /dev/null +++ b/seal-hack/src/audio.c @@ -0,0 +1,559 @@ +/* + * $Id: audio.c 1.13 1996/12/12 16:32:06 chasan Exp $ + * 1.14 1998/10/18 14:59:21 chasan (BeOS and OS/2 driver) + * 1.15 1998/11/30 18:20:26 chasan (Mixer and UpdateAudioEx API) + * + * Audio device drivers API interface + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifdef __GNUC__ +#include +#endif +#include +#include +#include "audio.h" +#include "drivers.h" + + +/* + * Copyright information hard-coded into the library + */ +CHAR szAudioCopyright[] = +"SEAL Synthetic Audio Library 1.07 (Build " __DATE__ ")\n" +"Copyright (C) 1995, 1996, 1997, 1998, 1999 Carlos Hasan\n"; +#ifdef __OS2__ +CHAR szMartyCopyright[] = +"OS/2 Audio Driver Copyright (C) 1998 by Martin Amodeo"; +#endif + + +/* + * Audio device drivers resource limits + */ +#define MAXDRIVERS 8 +#define MAXVOICES 32 + +/* + * Macros to work with audio channels handles + */ +#define VOICENUM(handle) ((UINT)handle-1) + +/* + * Table of registered audio device drivers and channels. + */ +static LPAUDIODRIVER aDriverTable[MAXDRIVERS]; +static HAC aVoiceTable[MAXVOICES]; +static UINT nNumVoices; + +/* + * Currently active audio device driver virtual method tables + */ +static UINT nDriverId = AUDIO_DEVICE_MAPPER; +static AUDIOWAVEDRIVER WaveDriver; +static AUDIOSYNTHDRIVER SynthDriver; + + +/* + * Audio device drivers API interface + */ +UINT AIAPI AAudioFatalError(UINT nErrorCode) +{ + nNumVoices = 0; + nDriverId = AUDIO_DEVICE_MAPPER; + memset(aVoiceTable, 0, sizeof(aVoiceTable)); + memcpy(&WaveDriver, &NoneWaveDriver, sizeof(AUDIOWAVEDRIVER)); + memcpy(&SynthDriver, &NoneSynthDriver, sizeof(AUDIOSYNTHDRIVER)); + return nErrorCode; +} + +UINT AIAPI AGetErrorText(UINT nErrorCode, LPSTR lpText, UINT nSize) +{ + static LPSTR aErrorTable[] = + { + "Unknown audio system error", + "Bad channel or sample handle", + "Invalid parameter passed", + "Invalid audio system call", + "Bad audio device identifier", + "No audio device found", + "Audio device is busy", + "Bad audio data format", + "Not enough memory", + "Not enough device memory", + "File not found", + "Bad file format" + }; + + if (lpText != NULL) { + if (nErrorCode <= AUDIO_LAST_ERROR) { + strncpy(lpText, aErrorTable[nErrorCode], nSize); + return AUDIO_ERROR_NONE; + } + strncpy(lpText, aErrorTable[AUDIO_ERROR_NONE], nSize); + } + return AUDIO_ERROR_INVALPARAM; +} + +UINT AIAPI ARegisterAudioDriver(LPAUDIODRIVER lpDriver) +{ + UINT nDeviceId; + + for (nDeviceId = 0; nDeviceId < MAXDRIVERS; nDeviceId++) { + if (aDriverTable[nDeviceId] == NULL || + aDriverTable[nDeviceId] == lpDriver) { + aDriverTable[nDeviceId] = lpDriver; + return AUDIO_ERROR_NONE; + } + } + return AUDIO_ERROR_NOMEMORY; +} + +UINT AIAPI AGetAudioNumDevs(VOID) +{ + UINT nDeviceId, nNumDevs; + + nNumDevs = 0; + for (nDeviceId = 0; nDeviceId < MAXDRIVERS; nDeviceId++) { + if (aDriverTable[nDeviceId] != NULL) + nNumDevs++; + } + return nNumDevs; +} + +UINT AIAPI AGetAudioDevCaps(UINT nDeviceId, LPAUDIOCAPS lpCaps) +{ + LPAUDIODRIVER lpDriver; + + if (lpCaps != NULL) { + memset(lpCaps, 0, sizeof(AUDIOCAPS)); + if (nDeviceId < MAXDRIVERS) { + if ((lpDriver = aDriverTable[nDeviceId]) != NULL) { + if (lpDriver->lpWaveDriver != NULL) { + return lpDriver->lpWaveDriver->GetAudioCaps(lpCaps); + } + else if (lpDriver->lpSynthDriver != NULL) { + return lpDriver->lpSynthDriver->GetAudioCaps(lpCaps); + } + } + } + return AUDIO_ERROR_BADDEVICEID; + } + return AUDIO_ERROR_INVALPARAM; +} + +UINT AIAPI APingAudio(LPUINT lpnDeviceId) +{ + LPAUDIODRIVER lpDriver; + UINT nDeviceId; + + if (lpnDeviceId != NULL) { + *lpnDeviceId = AUDIO_DEVICE_NONE; + if (nDriverId == AUDIO_DEVICE_MAPPER) { + for (nDeviceId = MAXDRIVERS - 1; nDeviceId != 0; nDeviceId--) { + if ((lpDriver = aDriverTable[nDeviceId]) != NULL) { + if (lpDriver->lpWaveDriver != NULL && + !lpDriver->lpWaveDriver->PingAudio()) { + *lpnDeviceId = nDeviceId; + return AUDIO_ERROR_NONE; + } + else if (lpDriver->lpSynthDriver != NULL && + !lpDriver->lpSynthDriver->PingAudio()) { + *lpnDeviceId = nDeviceId; + return AUDIO_ERROR_NONE; + } + } + } + return AUDIO_ERROR_NODEVICE; + } + return AUDIO_ERROR_NOTSUPPORTED; + } + return AUDIO_ERROR_INVALPARAM; +} + +UINT AIAPI AOpenAudio(LPAUDIOINFO lpInfo) +{ + LPAUDIODRIVER lpDriver; + LPAUDIOWAVEDRIVER lpWaveDriver; + LPAUDIOSYNTHDRIVER lpSynthDriver; + UINT nErrorCode; + + if (nDriverId == AUDIO_DEVICE_MAPPER) { + if (lpInfo != NULL && lpInfo->nDeviceId == AUDIO_DEVICE_MAPPER) { + nErrorCode = APingAudio(&lpInfo->nDeviceId); + if (nErrorCode != AUDIO_ERROR_NONE) + return AAudioFatalError(nErrorCode); + } + if (lpInfo != NULL && lpInfo->nDeviceId < MAXDRIVERS) { + if ((lpDriver = aDriverTable[lpInfo->nDeviceId]) != NULL) { + if ((lpWaveDriver = lpDriver->lpWaveDriver) == NULL) + lpWaveDriver = &NoneWaveDriver; + if ((lpSynthDriver = lpDriver->lpSynthDriver) == NULL) + lpSynthDriver = &EmuSynthDriver; + memcpy(&WaveDriver, lpWaveDriver, sizeof(AUDIOWAVEDRIVER)); + memcpy(&SynthDriver, lpSynthDriver, sizeof(AUDIOSYNTHDRIVER)); + nErrorCode = WaveDriver.OpenAudio(lpInfo); + if (nErrorCode != AUDIO_ERROR_NONE) + return AAudioFatalError(nErrorCode); + nErrorCode = SynthDriver.OpenAudio(lpInfo); + if (nErrorCode != AUDIO_ERROR_NONE) { + WaveDriver.CloseAudio(); + return AAudioFatalError(nErrorCode); + } + memset(aVoiceTable, 0, sizeof(aVoiceTable)); + nNumVoices = 0; + nDriverId = lpInfo->nDeviceId; + return AUDIO_ERROR_NONE; + } + } + return AAudioFatalError(lpInfo != NULL ? AUDIO_ERROR_BADDEVICEID : + AUDIO_ERROR_INVALPARAM); + } + return AUDIO_ERROR_NOTSUPPORTED; +} + +UINT AIAPI ACloseAudio(VOID) +{ + UINT nErrorCode; + + nDriverId = AUDIO_DEVICE_MAPPER; + if ((nErrorCode = SynthDriver.CloseAudio()) != AUDIO_ERROR_NONE) + return AAudioFatalError(nErrorCode); + if ((nErrorCode = WaveDriver.CloseAudio()) != AUDIO_ERROR_NONE) + return AAudioFatalError(nErrorCode); + return AAudioFatalError(AUDIO_ERROR_NONE); +} + +UINT AIAPI AUpdateAudio(VOID) +{ + return AUpdateAudioEx(0); +} + +UINT AIAPI AUpdateAudioEx(UINT nFrames) +{ + static UINT nSemalphore = 0; + UINT nErrorCode = AUDIO_ERROR_NONE; + + /* TODO: This is not a real semalphore, may fail sometimes. */ + if (nDriverId != AUDIO_DEVICE_MAPPER) { + if (!nSemalphore++) nErrorCode = WaveDriver.UpdateAudio(nFrames); + nSemalphore--; + } + return nErrorCode; +} + +UINT AIAPI AOpenVoices(UINT nVoices) +{ + UINT nErrorCode; + + memset(aVoiceTable, 0, sizeof(aVoiceTable)); + if ((nErrorCode = SynthDriver.OpenVoices(nVoices)) == AUDIO_ERROR_NONE) + nNumVoices = nVoices; + return nErrorCode; +} + +UINT AIAPI ACloseVoices(VOID) +{ + UINT nVoice; + + for (nVoice = 0; nVoice < nNumVoices; nVoice++) { + if (aVoiceTable[nVoice] != (HAC) NULL) + return AUDIO_ERROR_NOTSUPPORTED; + } + nNumVoices = 0; + memset(aVoiceTable, 0, sizeof(aVoiceTable)); + return SynthDriver.CloseVoices(); +} + +UINT AIAPI ASetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + return WaveDriver.SetAudioCallback(lpfnAudioWave); +} + +UINT AIAPI ASetAudioTimerProc(LPFNAUDIOTIMER lpfnAudioTimer) +{ + return SynthDriver.SetAudioTimerProc(lpfnAudioTimer); +} + +UINT AIAPI ASetAudioTimerRate(UINT nTimerRate) +{ + return SynthDriver.SetAudioTimerRate(nTimerRate); +} + +UINT AIAPI ASetAudioMixerValue(UINT nChannel, UINT nValue) +{ + return SynthDriver.SetAudioMixerValue(nChannel, nValue); +} + +LONG AIAPI AGetAudioDataAvail(VOID) +{ + return SynthDriver.GetAudioDataAvail(); +} + +UINT AIAPI ACreateAudioData(LPAUDIOWAVE lpWave) +{ + UINT nErrorCode; + + if (lpWave != NULL) { + if ((lpWave->lpData = malloc(lpWave->dwLength + 4)) != NULL) { + nErrorCode = SynthDriver.CreateAudioData(lpWave); + if (nErrorCode != AUDIO_ERROR_NONE) { + free(lpWave->lpData); + lpWave->lpData = NULL; + } + return nErrorCode; + } + return AUDIO_ERROR_NOMEMORY; + } + return AUDIO_ERROR_INVALPARAM; +} + +UINT AIAPI ADestroyAudioData(LPAUDIOWAVE lpWave) +{ + UINT nErrorCode; + + if (lpWave != NULL) { + nErrorCode = SynthDriver.DestroyAudioData(lpWave); + if (lpWave->lpData != NULL) + free(lpWave->lpData); + return nErrorCode; + } + return AUDIO_ERROR_INVALHANDLE; +} + +UINT AIAPI AWriteAudioData(LPAUDIOWAVE lpWave, DWORD dwOffset, UINT nCount) +{ + if (lpWave != NULL && lpWave->lpData != NULL) { + if (nCount != 0) { + return SynthDriver.WriteAudioData(lpWave, dwOffset, nCount); + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +UINT AIAPI ACreateAudioVoice(LPHAC lphVoice) +{ + UINT nVoice; + + if (lphVoice != NULL) { + for (nVoice = 0; nVoice < nNumVoices; nVoice++) { + if (!aVoiceTable[nVoice]) { + *lphVoice = aVoiceTable[nVoice] = (HAC) (nVoice + 1); + return AUDIO_ERROR_NONE; + } + } + return AUDIO_ERROR_NOMEMORY; + } + return AUDIO_ERROR_INVALPARAM; +} + +UINT AIAPI ADestroyAudioVoice(HAC hVoice) +{ + UINT nVoice; + + if ((nVoice = VOICENUM(hVoice)) < nNumVoices) { + aVoiceTable[nVoice] = (HAC) NULL; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; +} + +UINT AIAPI APlayVoice(HAC hVoice, LPAUDIOWAVE lpWave) +{ + UINT nErrorCode; + + if (lpWave != NULL) { + if (!(nErrorCode = APrimeVoice(hVoice, lpWave)) && + !(nErrorCode = ASetVoiceFrequency(hVoice, lpWave->nSampleRate))) + return AStartVoice(hVoice); + return nErrorCode; + } + return AUDIO_ERROR_INVALHANDLE; +} + +UINT AIAPI APrimeVoice(HAC hVoice, LPAUDIOWAVE lpWave) +{ + return SynthDriver.PrimeVoice(VOICENUM(hVoice), lpWave); +} + +UINT AIAPI AStartVoice(HAC hVoice) +{ + return SynthDriver.StartVoice(VOICENUM(hVoice)); +} + +UINT AIAPI AStopVoice(HAC hVoice) +{ + return SynthDriver.StopVoice(VOICENUM(hVoice)); +} + +UINT AIAPI ASetVoicePosition(HAC hVoice, LONG dwPosition) +{ + return SynthDriver.SetVoicePosition(VOICENUM(hVoice), dwPosition); +} + +UINT AIAPI ASetVoiceFrequency(HAC hVoice, LONG dwFrequency) +{ + return SynthDriver.SetVoiceFrequency(VOICENUM(hVoice), dwFrequency); +} + +UINT AIAPI ASetVoiceVolume(HAC hVoice, UINT nVolume) +{ + return SynthDriver.SetVoiceVolume(VOICENUM(hVoice), nVolume); +} + +UINT AIAPI ASetVoicePanning(HAC hVoice, UINT nPanning) +{ + return SynthDriver.SetVoicePanning(VOICENUM(hVoice), nPanning); +} + +UINT AIAPI AGetVoicePosition(HAC hVoice, LPLONG lpdwPosition) +{ + return SynthDriver.GetVoicePosition(VOICENUM(hVoice), lpdwPosition); +} + +UINT AIAPI AGetVoiceFrequency(HAC hVoice, LPLONG lpdwFrequency) +{ + return SynthDriver.GetVoiceFrequency(VOICENUM(hVoice), lpdwFrequency); +} + +UINT AIAPI AGetVoiceVolume(HAC hVoice, LPUINT lpnVolume) +{ + return SynthDriver.GetVoiceVolume(VOICENUM(hVoice), lpnVolume); +} + +UINT AIAPI AGetVoicePanning(HAC hVoice, LPUINT lpnPanning) +{ + return SynthDriver.GetVoicePanning(VOICENUM(hVoice), lpnPanning); +} + +UINT AIAPI AGetVoiceStatus(HAC hVoice, LPBOOL lpnStatus) +{ + return SynthDriver.GetVoiceStatus(VOICENUM(hVoice), lpnStatus); +} + + + +/* + * External system-dependant audio device drivers + */ +#ifdef __BEOS__ +extern AUDIODRIVER BeOSR3Driver; +extern AUDIODRIVER BeOSDriver; +#endif +#ifdef __OS2__ +extern AUDIODRIVER OS2MMPMDriver; +#endif +#ifdef __LINUX__ +extern AUDIODRIVER LinuxDriver; +#endif +#ifdef __OSX__ +//extern AUDIODRIVER MacOSXDriver; +extern AUDIODRIVER AllegDriver; +#endif +#ifdef __FREEBSD__ +extern AUDIODRIVER LinuxDriver; +#endif +#ifdef __SPARC__ +extern AUDIODRIVER SparcDriver; +#endif +#ifdef __SOLARIS__ +extern AUDIODRIVER SparcDriver; +#endif +#ifdef __SILICON__ +extern AUDIODRIVER SiliconDriver; +#endif +#ifdef __WINDOWS__ +extern AUDIODRIVER WindowsDriver; +extern AUDIODRIVER DirectSoundDriver; +extern AUDIODRIVER DirectSoundAccelDriver; +#endif +#if defined(__DOS16__) || defined(__DPMI__) +extern AUDIODRIVER SoundBlasterDriver; +extern AUDIODRIVER SoundBlaster32Driver; +extern AUDIODRIVER ProAudioSpectrumDriver; +extern AUDIODRIVER UltraSoundDriver; +extern AUDIODRIVER UltraSoundMaxDriver; +extern AUDIODRIVER WinSndSystemDriver; +extern AUDIODRIVER SoundscapeDriver; +extern AUDIODRIVER AriaDriver; +#endif +#ifdef __SDL__ +extern AUDIODRIVER SDLDriver; +#endif + + +UINT AIAPI AGetVersion(VOID) +{ + /* return the current hard-coded audio system version */ + return AUDIO_SYSTEM_VERSION; +} + +UINT AIAPI AInitialize(VOID) +{ +#ifdef __DJGPP__ + /* 1998/12/20 lock code and data memory */ + SEAL_LOCK_MEMORY(); +#endif + + /* + * Initialize all the audio system state variables, + * and registers all the built-in audio drivers. + */ + if (nDriverId != AUDIO_DEVICE_MAPPER) + return AUDIO_ERROR_NOTSUPPORTED; + + ARegisterAudioDriver(&NoneDriver); +#ifdef __BEOS__ + ARegisterAudioDriver(&BeOSR3Driver); + ARegisterAudioDriver(&BeOSDriver); +#endif +#ifdef __OS2__ + ARegisterAudioDriver(&OS2MMPMDriver); +#endif +#ifdef __LINUX__ + ARegisterAudioDriver(&LinuxDriver); +#endif +#ifdef __OSX__ +// ARegisterAudioDriver(&MacOSXDriver); + ARegisterAudioDriver(&AllegDriver); +#endif +#ifdef __FREEBSD__ + ARegisterAudioDriver(&LinuxDriver); +#endif +#ifdef __SPARC__ + ARegisterAudioDriver(&SparcDriver); +#endif +#ifdef __SOLARIS__ + ARegisterAudioDriver(&SparcDriver); +#endif +#ifdef __SILICON__ + ARegisterAudioDriver(&SiliconDriver); +#endif +#ifdef __WINDOWS__ + ARegisterAudioDriver(&WindowsDriver); + ARegisterAudioDriver(&DirectSoundAccelDriver); + ARegisterAudioDriver(&DirectSoundDriver); +#endif +#if defined(__DOS16__) || defined(__DPMI__) + ARegisterAudioDriver(&SoundBlasterDriver); + ARegisterAudioDriver(&SoundBlaster32Driver); + ARegisterAudioDriver(&ProAudioSpectrumDriver); + ARegisterAudioDriver(&UltraSoundMaxDriver); + ARegisterAudioDriver(&UltraSoundDriver); + ARegisterAudioDriver(&WinSndSystemDriver); + ARegisterAudioDriver(&SoundscapeDriver); + ARegisterAudioDriver(&AriaDriver); +#endif +#ifdef __SDL__ + ARegisterAudioDriver(&SDLDriver); +#endif + + return AAudioFatalError(AUDIO_ERROR_NONE); +} diff --git a/seal-hack/src/audio.h b/seal-hack/src/audio.h new file mode 100644 index 0000000..d9031d8 --- /dev/null +++ b/seal-hack/src/audio.h @@ -0,0 +1,391 @@ +/* + * $Id: audio.h 1.17 1996/09/25 17:13:02 chasan released $ + * 1.18 1998/10/12 23:54:08 chasan released + * 1.19 1998/10/24 18:20:52 chasan released + * 1.20 1999/06/27 17:49:49 chasan released + * + * SEAL Synthetic Audio Library API Interface + * + * Copyright (C) 1995, 1996, 1997, 1998, 1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __AUDIO_H +#define __AUDIO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef WIN32 +#define AIAPI +#else +#define AIAPI __stdcall +#endif + +#ifndef WINAPI + +/* atomic data types definitions */ +#if 0 + typedef void VOID; + typedef char CHAR; + typedef int INT; + typedef long LONG; + typedef int BOOL; + + typedef unsigned char BYTE; + typedef unsigned short WORD; + typedef unsigned int UINT; + typedef unsigned long DWORD; +#else + typedef void VOID; + typedef int8_t CHAR; + typedef int32_t INT; + typedef int32_t LONG; + typedef int8_t BOOL; + + typedef uint8_t BYTE; + typedef uint16_t WORD; + typedef uint32_t UINT; + typedef uint32_t DWORD; +#endif + typedef VOID* LPVOID; + typedef CHAR* LPCHAR; + typedef INT* LPINT; + typedef LONG* LPLONG; + typedef BOOL* LPBOOL; + typedef BYTE* LPBYTE; + typedef WORD* LPWORD; + typedef UINT* LPUINT; + typedef DWORD* LPDWORD; + typedef CHAR* LPSTR; + typedef DWORD HANDLE; + +/* helper macros */ +#define LOBYTE(s) ((BYTE)(s)) +#define HIBYTE(s) ((BYTE)((WORD)(s)>>8)) +#define LOWORD(l) ((WORD)(l)) +#define HIWORD(l) ((WORD)((DWORD)(l)>>16)) +#define MAKEWORD(l,h) ((WORD)(((BYTE)(l))|(((WORD)((BYTE)(h)))<<8))) +#define MAKELONG(l,h) ((DWORD)(((WORD)(l))|(((DWORD)((WORD)(h)))<<16))) + +#endif + + +/* audio system version number */ +#define AUDIO_SYSTEM_VERSION 0x0106 + +/* audio capabilities bit fields definitions */ +#define AUDIO_FORMAT_1M08 0x00000001 +#define AUDIO_FORMAT_1S08 0x00000002 +#define AUDIO_FORMAT_1M16 0x00000004 +#define AUDIO_FORMAT_1S16 0x00000008 +#define AUDIO_FORMAT_2M08 0x00000010 +#define AUDIO_FORMAT_2S08 0x00000020 +#define AUDIO_FORMAT_2M16 0x00000040 +#define AUDIO_FORMAT_2S16 0x00000080 +#define AUDIO_FORMAT_4M08 0x00000100 +#define AUDIO_FORMAT_4S08 0x00000200 +#define AUDIO_FORMAT_4M16 0x00000400 +#define AUDIO_FORMAT_4S16 0x00000800 + +/* audio format bit fields defines for devices and waveforms */ +#define AUDIO_FORMAT_8BITS 0x0000 +#define AUDIO_FORMAT_16BITS 0x0001 +#define AUDIO_FORMAT_LOOP 0x0010 +#define AUDIO_FORMAT_BIDILOOP 0x0020 +#define AUDIO_FORMAT_REVERSE 0x0080 +#define AUDIO_FORMAT_MONO 0x0000 +#define AUDIO_FORMAT_STEREO 0x0100 +#define AUDIO_FORMAT_FILTER 0x8000 + +/* audio resource limits defines */ +#define AUDIO_MAX_VOICES 32 +#define AUDIO_MAX_SAMPLES 16 +#define AUDIO_MAX_PATCHES 128 +#define AUDIO_MAX_PATTERNS 256 +#define AUDIO_MAX_ORDERS 256 +#define AUDIO_MAX_NOTES 96 +#define AUDIO_MAX_POINTS 12 +#define AUDIO_MIN_PERIOD 1 +#define AUDIO_MAX_PERIOD 31999 +#define AUDIO_MIN_VOLUME 0x00 +#define AUDIO_MAX_VOLUME 0x40 +#define AUDIO_MIN_PANNING 0x00 +#define AUDIO_MAX_PANNING 0xFF +#define AUDIO_MIN_POSITION 0x00000000L +#define AUDIO_MAX_POSITION 0x00100000L +#define AUDIO_MIN_FREQUENCY 0x00000200L +#define AUDIO_MAX_FREQUENCY 0x00080000L + +/* audio error code defines */ +#define AUDIO_ERROR_NONE 0x0000 +#define AUDIO_ERROR_INVALHANDLE 0x0001 +#define AUDIO_ERROR_INVALPARAM 0x0002 +#define AUDIO_ERROR_NOTSUPPORTED 0x0003 +#define AUDIO_ERROR_BADDEVICEID 0x0004 +#define AUDIO_ERROR_NODEVICE 0x0005 +#define AUDIO_ERROR_DEVICEBUSY 0x0006 +#define AUDIO_ERROR_BADFORMAT 0x0007 +#define AUDIO_ERROR_NOMEMORY 0x0008 +#define AUDIO_ERROR_NODRAMMEMORY 0x0009 +#define AUDIO_ERROR_FILENOTFOUND 0x000A +#define AUDIO_ERROR_BADFILEFORMAT 0x000B +#define AUDIO_LAST_ERROR 0x000B + +/* audio device identifiers */ +#define AUDIO_DEVICE_NONE 0x0000 +#define AUDIO_DEVICE_MAPPER 0xFFFF + +/* audio product identifiers */ +#define AUDIO_PRODUCT_NONE 0x0000 +#define AUDIO_PRODUCT_SB 0x0001 +#define AUDIO_PRODUCT_SB15 0x0002 +#define AUDIO_PRODUCT_SB20 0x0003 +#define AUDIO_PRODUCT_SBPRO 0x0004 +#define AUDIO_PRODUCT_SB16 0x0005 +#define AUDIO_PRODUCT_AWE32 0x0006 +#define AUDIO_PRODUCT_WSS 0x0007 +#define AUDIO_PRODUCT_ESS 0x0008 +#define AUDIO_PRODUCT_GUS 0x0009 +#define AUDIO_PRODUCT_GUSDB 0x000A +#define AUDIO_PRODUCT_GUSMAX 0x000B +#define AUDIO_PRODUCT_IWAVE 0x000C +#define AUDIO_PRODUCT_PAS 0x000D +#define AUDIO_PRODUCT_PAS16 0x000E +#define AUDIO_PRODUCT_ARIA 0x000F +#define AUDIO_PRODUCT_WINDOWS 0x0100 +#define AUDIO_PRODUCT_LINUX 0x0101 +#define AUDIO_PRODUCT_SPARC 0x0102 +#define AUDIO_PRODUCT_SGI 0x0103 +#define AUDIO_PRODUCT_DSOUND 0x0104 +#define AUDIO_PRODUCT_OS2MMPM 0x0105 +#define AUDIO_PRODUCT_OS2DART 0x0106 +#define AUDIO_PRODUCT_BEOSR3 0x0107 +#define AUDIO_PRODUCT_BEOS 0x0108 +#define AUDIO_PRODUCT_QNX 0x0109 + +/* audio mixer channels */ +#define AUDIO_MIXER_MASTER_VOLUME 0x0001 +#define AUDIO_MIXER_TREBLE 0x0002 +#define AUDIO_MIXER_BASS 0x0003 +#define AUDIO_MIXER_CHORUS 0x0004 +#define AUDIO_MIXER_REVERB 0x0005 + +/* audio envelope bit fields */ +#define AUDIO_ENVELOPE_ON 0x0001 +#define AUDIO_ENVELOPE_SUSTAIN 0x0002 +#define AUDIO_ENVELOPE_LOOP 0x0004 + +/* audio pattern bit fields */ +#define AUDIO_PATTERN_PACKED 0x0080 +#define AUDIO_PATTERN_NOTE 0x0001 +#define AUDIO_PATTERN_SAMPLE 0x0002 +#define AUDIO_PATTERN_VOLUME 0x0004 +#define AUDIO_PATTERN_COMMAND 0x0008 +#define AUDIO_PATTERN_PARAMS 0x0010 + +/* audio module bit fields */ +#define AUDIO_MODULE_AMIGA 0x0000 +#define AUDIO_MODULE_LINEAR 0x0001 +#define AUDIO_MODULE_PANNING 0x8000 + +#pragma pack(1) + +/* audio capabilities structure */ + typedef struct { + WORD wProductId; /* product identifier */ + CHAR szProductName[30]; /* product name */ + DWORD dwFormats; /* formats supported */ + } AUDIOCAPS, *LPAUDIOCAPS; + +/* audio format structure */ + typedef struct { + UINT nDeviceId; /* device identifier */ + WORD wFormat; /* playback format */ + WORD nSampleRate; /* sampling frequency */ + } AUDIOINFO, *LPAUDIOINFO; + +/* audio waveform structure */ + typedef struct { + LPBYTE lpData; /* data pointer */ + DWORD dwHandle; /* waveform handle */ + DWORD dwLength; /* waveform length */ + DWORD dwLoopStart; /* loop start point */ + DWORD dwLoopEnd; /* loop end point */ + WORD nSampleRate; /* sampling rate */ + WORD wFormat; /* format bits */ + } AUDIOWAVE, *LPAUDIOWAVE; + + +/* audio envelope point structure */ + typedef struct { + WORD nFrame; /* envelope frame */ + WORD nValue; /* envelope value */ + } AUDIOPOINT, *LPAUDIOPOINT; + +/* audio envelope structure */ + typedef struct { + AUDIOPOINT aEnvelope[AUDIO_MAX_POINTS]; /* envelope points */ + BYTE nPoints; /* number of points */ + BYTE nSustain; /* sustain point */ + BYTE nLoopStart; /* loop start point */ + BYTE nLoopEnd; /* loop end point */ + WORD wFlags; /* envelope flags */ + WORD nSpeed; /* envelope speed */ + } AUDIOENVELOPE, *LPAUDIOENVELOPE; + +/* audio sample structure */ + typedef struct { + CHAR szSampleName[32]; /* sample name */ + BYTE nVolume; /* default volume */ + BYTE nPanning; /* default panning */ + BYTE nRelativeNote; /* relative note */ + BYTE nFinetune; /* finetune */ + AUDIOWAVE Wave; /* waveform handle */ + } AUDIOSAMPLE, *LPAUDIOSAMPLE; + +/* audio patch structure */ + typedef struct { + CHAR szPatchName[32]; /* patch name */ + BYTE aSampleNumber[AUDIO_MAX_NOTES]; /* multi-sample table */ + WORD nSamples; /* number of samples */ + BYTE nVibratoType; /* vibrato type */ + BYTE nVibratoSweep; /* vibrato sweep */ + BYTE nVibratoDepth; /* vibrato depth */ + BYTE nVibratoRate; /* vibrato rate */ + WORD nVolumeFadeout; /* volume fadeout */ + AUDIOENVELOPE Volume; /* volume envelope */ + AUDIOENVELOPE Panning; /* panning envelope */ + LPAUDIOSAMPLE aSampleTable; /* sample table */ + } AUDIOPATCH, *LPAUDIOPATCH; + +/* audio pattern structure */ + typedef struct { + WORD nPacking; /* packing type */ + WORD nTracks; /* number of tracks */ + WORD nRows; /* number of rows */ + WORD nSize; /* data size */ + LPBYTE lpData; /* data pointer */ + } AUDIOPATTERN, *LPAUDIOPATTERN; + +/* audio module structure */ + typedef struct { + CHAR szModuleName[32]; /* module name */ + WORD wFlags; /* module flags */ + WORD nOrders; /* number of orders */ + WORD nRestart; /* restart position */ + WORD nTracks; /* number of tracks */ + WORD nPatterns; /* number of patterns */ + WORD nPatches; /* number of patches */ + WORD nTempo; /* initial tempo */ + WORD nBPM; /* initial BPM */ + BYTE aOrderTable[AUDIO_MAX_ORDERS]; /* order table */ + BYTE aPanningTable[AUDIO_MAX_VOICES]; /* panning table */ + LPAUDIOPATTERN aPatternTable; /* pattern table */ + LPAUDIOPATCH aPatchTable; /* patch table */ + } AUDIOMODULE, *LPAUDIOMODULE; + +/* audio music track structure */ + typedef struct { + BYTE nNote; /* note index */ + BYTE nPatch; /* patch number */ + BYTE nSample; /* sample number */ + BYTE nCommand; /* effect command */ + BYTE bParams; /* effect params */ + BYTE nVolumeCmd; /* volume command */ + BYTE nVolume; /* volume level */ + BYTE nPanning; /* stereo panning */ + LONG dwFrequency; /* note frequency */ + WORD wPeriod; /* note period */ + } AUDIOTRACK, *LPAUDIOTRACK; + +/* audio callback function defines */ + typedef VOID (AIAPI* LPFNAUDIOWAVE)(LPBYTE, UINT); + typedef VOID (AIAPI* LPFNAUDIOTIMER)(VOID); + typedef VOID (AIAPI* LPFNAUDIOCALLBACK)(BYTE, UINT, UINT); + +/* audio handle defines */ + typedef HANDLE HAC; + typedef HAC* LPHAC; + +#pragma pack() + +/* audio interface API prototypes */ + UINT AIAPI AInitialize(VOID); + UINT AIAPI AGetVersion(VOID); + UINT AIAPI AGetAudioNumDevs(VOID); + UINT AIAPI AGetAudioDevCaps(UINT nDeviceId, LPAUDIOCAPS lpCaps); + UINT AIAPI AGetErrorText(UINT nErrorCode, LPSTR lpText, UINT nSize); + + UINT AIAPI APingAudio(LPUINT lpnDeviceId); + UINT AIAPI AOpenAudio(LPAUDIOINFO lpInfo); + UINT AIAPI ACloseAudio(VOID); + UINT AIAPI AUpdateAudio(VOID); + UINT AIAPI AUpdateAudioEx(UINT nFrames); + + UINT AIAPI ASetAudioMixerValue(UINT nChannel, UINT nValue); + + UINT AIAPI AOpenVoices(UINT nVoices); + UINT AIAPI ACloseVoices(VOID); + + UINT AIAPI ASetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave); + UINT AIAPI ASetAudioTimerProc(LPFNAUDIOTIMER lpfnAudioTimer); + UINT AIAPI ASetAudioTimerRate(UINT nTimerRate); + + LONG AIAPI AGetAudioDataAvail(VOID); + UINT AIAPI ACreateAudioData(LPAUDIOWAVE lpWave); + UINT AIAPI ADestroyAudioData(LPAUDIOWAVE lpWave); + UINT AIAPI AWriteAudioData(LPAUDIOWAVE lpWave, DWORD dwOffset, UINT nCount); + + UINT AIAPI ACreateAudioVoice(LPHAC lphVoice); + UINT AIAPI ADestroyAudioVoice(HAC hVoice); + + UINT AIAPI APlayVoice(HAC hVoice, LPAUDIOWAVE lpWave); + UINT AIAPI APrimeVoice(HAC hVoice, LPAUDIOWAVE lpWave); + UINT AIAPI AStartVoice(HAC hVoice); + UINT AIAPI AStopVoice(HAC hVoice); + + UINT AIAPI ASetVoicePosition(HAC hVoice, LONG dwPosition); + UINT AIAPI ASetVoiceFrequency(HAC hVoice, LONG dwFrequency); + UINT AIAPI ASetVoiceVolume(HAC hVoice, UINT nVolume); + UINT AIAPI ASetVoicePanning(HAC hVoice, UINT nPanning); + + UINT AIAPI AGetVoicePosition(HAC hVoice, LPLONG lpdwPosition); + UINT AIAPI AGetVoiceFrequency(HAC hVoice, LPLONG lpdwFrequency); + UINT AIAPI AGetVoiceVolume(HAC hVoice, LPUINT lpnVolume); + UINT AIAPI AGetVoicePanning(HAC hVoice, LPUINT lpnPanning); + UINT AIAPI AGetVoiceStatus(HAC hVoice, LPBOOL lpnStatus); + + UINT AIAPI APlayModule(LPAUDIOMODULE lpModule); + UINT AIAPI AStopModule(VOID); + UINT AIAPI APauseModule(VOID); + UINT AIAPI AResumeModule(VOID); + UINT AIAPI ASetModuleVolume(UINT nVolume); + UINT AIAPI ASetModulePosition(UINT nOrder, UINT nRow); + UINT AIAPI AGetModuleVolume(LPUINT lpnVolume); + UINT AIAPI AGetModulePosition(LPUINT pnOrder, LPUINT lpnRow); + UINT AIAPI AGetModuleStatus(LPBOOL lpnStatus); + UINT AIAPI ASetModuleCallback(LPFNAUDIOCALLBACK lpfnAudioCallback); + + UINT AIAPI ALoadModuleFile(LPSTR lpszFileName, + LPAUDIOMODULE* lplpModule, DWORD dwFileOffset); + UINT AIAPI AFreeModuleFile(LPAUDIOMODULE lpModule); + + UINT AIAPI ALoadWaveFile(LPSTR lpszFileName, + LPAUDIOWAVE* lplpWave, DWORD dwFileOffset); + UINT AIAPI AFreeWaveFile(LPAUDIOWAVE lpWave); + + UINT AIAPI AGetModuleTrack(UINT nTrack, LPAUDIOTRACK lpTrack); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/seal-hack/src/audiodj.c b/seal-hack/src/audiodj.c new file mode 100644 index 0000000..1b4f43e --- /dev/null +++ b/seal-hack/src/audiodj.c @@ -0,0 +1,383 @@ +/* + * @(#)audiodj.c 0.2 1998/12/20 Carlos Hasan (chasan@dcc.uchile.cl) + * + * Hack for DJGPP 2.01 to lock code and data into a contiguous memory region. + * + * Copyright (C) 1998-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include + +static int __SEAL_BSS_BEGIN; +static int __SEAL_DATA_BEGIN = 0xCafe; +static int __SEAL_TEXT_BEGIN(void) { return 0; } + +static void SEAL_LOCK_MEMORY(void); + +#include "audio.c" +#include "wavfile.c" +#include "xmfile.c" +#include "s3mfile.c" +#include "modfile.c" +#include "mtmfile.c" +#include "iofile.c" +#include "modeng.c" + +#undef BUFFERSIZE +#undef CLIP +#undef TIMEOUT +#undef DEBUG + +#undef GetAudioCaps +#undef PingAudio +#undef OpenAudio +#undef CloseAudio +#undef UpdateAudio +#undef SetAudioCallback + +#define GetAudioCaps noneGetAudioCaps +#define PingAudio nonePingAudio +#define OpenAudio noneOpenAudio +#define CloseAudio noneCloseAudio +#define UpdateAudio noneUpdateAudio +#define SetAudioCallback noneSetAudioCallback + +#include "nondrv.c" + +#undef BUFFERSIZE +#undef CLIP +#undef TIMEOUT +#undef DEBUG + +#undef GetAudioCaps +#undef PingAudio +#undef OpenAudio +#undef CloseAudio +#undef UpdateAudio +#undef SetAudioCallback + +#define GetAudioCaps sbGetAudioCaps +#define PingAudio sbPingAudio +#define OpenAudio sbOpenAudio +#define CloseAudio sbCloseAudio +#define UpdateAudio sbUpdateAudio +#define SetAudioCallback sbSetAudioCallback + +#include "sbdrv.c" + +#undef BUFFERSIZE +#undef CLIP +#undef TIMEOUT +#undef DEBUG + +#undef GetAudioCaps +#undef PingAudio +#undef OpenAudio +#undef CloseAudio +#undef UpdateAudio +#undef SetAudioCallback + +#define GetAudioCaps pasGetAudioCaps +#define PingAudio pasPingAudio +#define OpenAudio pasOpenAudio +#define CloseAudio pasCloseAudio +#define UpdateAudio pasUpdateAudio +#define SetAudioCallback pasSetAudioCallback + +#include "pasdrv.c" + +#undef BUFFERSIZE +#undef CLIP +#undef TIMEOUT +#undef DEBUG + +#undef GetAudioCaps +#undef PingAudio +#undef OpenAudio +#undef CloseAudio +#undef UpdateAudio +#undef SetAudioCallback + +#define GetAudioCaps wssGetAudioCaps +#define PingAudio wssPingAudio +#define OpenAudio wssOpenAudio +#define CloseAudio wssCloseAudio +#define UpdateAudio wssUpdateAudio +#define SetAudioCallback wssSetAudioCallback + +#include "wssdrv.c" + +#undef BUFFERSIZE +#undef CLIP +#undef TIMEOUT +#undef DEBUG + +#undef GetAudioCaps +#undef PingAudio +#undef OpenAudio +#undef CloseAudio +#undef UpdateAudio +#undef SetAudioCallback + +#define GetAudioCaps ariaGetAudioCaps +#define PingAudio ariaPingAudio +#define OpenAudio ariaOpenAudio +#define CloseAudio ariaCloseAudio +#define UpdateAudio ariaUpdateAudio +#define SetAudioCallback ariaSetAudioCallback + +#include "ariadrv.c" + + +#undef BUFFERSIZE +#undef CLIP +#undef TIMEOUT +#undef DEBUG + +#undef VOICE_START +#undef VOICE_STOP +#undef VOICE_LOOP +#undef VOICE_BIDILOOP + +#undef aVolumeTable +#undef aFrequencyTable + +#define aVolumeTable mixVolumeTable +#define aFrequencyTable mixFrequencyTable + +#undef GetAudioCaps +#undef PingAudio +#undef OpenAudio +#undef CloseAudio +#undef UpdateAudio +#undef SetAudioCallback +#undef SetAudioMixerValue +#undef OpenVoices +#undef CloseVoices +#undef GetAudioDataAvail +#undef CreateAudioData +#undef DestroyAudioData +#undef WriteAudioData +#undef PrimeVoice +#undef StartVoice +#undef StopVoice +#undef SetVoicePosition +#undef SetVoiceFrequency +#undef SetVoiceVolume +#undef SetVoicePanning +#undef GetVoicePosition +#undef GetVoiceFrequency +#undef GetVoiceVolume +#undef GetVoicePanning +#undef GetVoiceStatus +#undef SetAudioTimerProc +#undef SetAudioTimerRate + +#define GetAudioCaps mixGetAudioCaps +#define PingAudio mixPingAudio +#define OpenAudio mixOpenAudio +#define CloseAudio mixCloseAudio +#define UpdateAudio mixUpdateAudio +#define SetAudioCallback mixSetAudioCallback +#define SetAudioMixerValue mixSetAudioMixerValue +#define OpenVoices mixOpenVoices +#define CloseVoices mixCloseVoices +#define GetAudioDataAvail mixGetAudioDataAvail +#define CreateAudioData mixCreateAudioData +#define DestroyAudioData mixDestroyAudioData +#define WriteAudioData mixWriteAudioData +#define PrimeVoice mixPrimeVoice +#define StartVoice mixStartVoice +#define StopVoice mixStopVoice +#define SetVoicePosition mixSetVoicePosition +#define SetVoiceFrequency mixSetVoiceFrequency +#define SetVoiceVolume mixSetVoiceVolume +#define SetVoicePanning mixSetVoicePanning +#define GetVoicePosition mixGetVoicePosition +#define GetVoiceFrequency mixGetVoiceFrequency +#define GetVoiceVolume mixGetVoiceVolume +#define GetVoicePanning mixGetVoicePanning +#define GetVoiceStatus mixGetVoiceStatus +#define SetAudioTimerProc mixSetAudioTimerProc +#define SetAudioTimerRate mixSetAudioTimerRate + +#include "mixdrv.c" + +#undef BUFFERSIZE +#undef CLIP +#undef TIMEOUT +#undef DEBUG + +#undef VOICE_START +#undef VOICE_STOP +#undef VOICE_LOOP +#undef VOICE_BIDILOOP + +#undef aVolumeTable +#undef aFrequencyTable + +#define aVolumeTable aweVolumeTable +#define aFrequencyTable aweFrequencyTable + +#undef GetAudioCaps +#undef PingAudio +#undef OpenAudio +#undef CloseAudio +#undef UpdateAudio +#undef SetAudioCallback +#undef SetAudioMixerValue +#undef OpenVoices +#undef CloseVoices +#undef GetAudioDataAvail +#undef CreateAudioData +#undef DestroyAudioData +#undef WriteAudioData +#undef PrimeVoice +#undef StartVoice +#undef StopVoice +#undef SetVoicePosition +#undef SetVoiceFrequency +#undef SetVoiceVolume +#undef SetVoicePanning +#undef GetVoicePosition +#undef GetVoiceFrequency +#undef GetVoiceVolume +#undef GetVoicePanning +#undef GetVoiceStatus +#undef SetAudioTimerProc +#undef SetAudioTimerRate + +#define GetAudioCaps aweGetAudioCaps +#define PingAudio awePingAudio +#define OpenAudio aweOpenAudio +#define CloseAudio aweCloseAudio +#define UpdateAudio aweUpdateAudio +#define SetAudioCallback aweSetAudioCallback +#define SetAudioMixerValue aweSetAudioMixerValue +#define OpenVoices aweOpenVoices +#define CloseVoices aweCloseVoices +#define GetAudioDataAvail aweGetAudioDataAvail +#define CreateAudioData aweCreateAudioData +#define DestroyAudioData aweDestroyAudioData +#define WriteAudioData aweWriteAudioData +#define PrimeVoice awePrimeVoice +#define StartVoice aweStartVoice +#define StopVoice aweStopVoice +#define SetVoicePosition aweSetVoicePosition +#define SetVoiceFrequency aweSetVoiceFrequency +#define SetVoiceVolume aweSetVoiceVolume +#define SetVoicePanning aweSetVoicePanning +#define GetVoicePosition aweGetVoicePosition +#define GetVoiceFrequency aweGetVoiceFrequency +#define GetVoiceVolume aweGetVoiceVolume +#define GetVoicePanning aweGetVoicePanning +#define GetVoiceStatus aweGetVoiceStatus +#define SetAudioTimerProc aweSetAudioTimerProc +#define SetAudioTimerRate aweSetAudioTimerRate + +#include "awedrv.c" + +#undef BUFFERSIZE +#undef CLIP +#undef TIMEOUT +#undef DEBUG + +#undef VOICE_START +#undef VOICE_STOP +#undef VOICE_LOOP +#undef VOICE_BIDILOOP + +#undef aVolumeTable +#undef aFrequencyTable + +#define aVolumeTable gusVolumeTable +#define aFrequencyTable gusFrequencyTable + +#undef GetAudioCaps +#undef PingAudio +#undef OpenAudio +#undef CloseAudio +#undef UpdateAudio +#undef SetAudioCallback +#undef SetAudioMixerValue +#undef OpenVoices +#undef CloseVoices +#undef GetAudioDataAvail +#undef CreateAudioData +#undef DestroyAudioData +#undef WriteAudioData +#undef PrimeVoice +#undef StartVoice +#undef StopVoice +#undef SetVoicePosition +#undef SetVoiceFrequency +#undef SetVoiceVolume +#undef SetVoicePanning +#undef GetVoicePosition +#undef GetVoiceFrequency +#undef GetVoiceVolume +#undef GetVoicePanning +#undef GetVoiceStatus +#undef SetAudioTimerProc +#undef SetAudioTimerRate + +#define GetAudioCaps gusGetAudioCaps +#define PingAudio gusPingAudio +#define OpenAudio gusOpenAudio +#define CloseAudio gusCloseAudio +#define UpdateAudio gusUpdateAudio +#define SetAudioCallback gusSetAudioCallback +#define SetAudioMixerValue gusSetAudioMixerValue +#define OpenVoices gusOpenVoices +#define CloseVoices gusCloseVoices +#define GetAudioDataAvail gusGetAudioDataAvail +#define CreateAudioData gusCreateAudioData +#define DestroyAudioData gusDestroyAudioData +#define WriteAudioData gusWriteAudioData +#define PrimeVoice gusPrimeVoice +#define StartVoice gusStartVoice +#define StopVoice gusStopVoice +#define SetVoicePosition gusSetVoicePosition +#define SetVoiceFrequency gusSetVoiceFrequency +#define SetVoiceVolume gusSetVoiceVolume +#define SetVoicePanning gusSetVoicePanning +#define GetVoicePosition gusGetVoicePosition +#define GetVoiceFrequency gusGetVoiceFrequency +#define GetVoiceVolume gusGetVoiceVolume +#define GetVoicePanning gusGetVoicePanning +#define GetVoiceStatus gusGetVoiceStatus +#define SetAudioTimerProc gusSetAudioTimerProc +#define SetAudioTimerRate gusSetAudioTimerRate + +#include "gusdrv.c" + + +#include "msdos.c" + +static int __SEAL_BSS_END; +static int __SEAL_DATA_END = 0xCafe; +static int __SEAL_TEXT_END(void) { return 0; } + +static void SEAL_LOCK_MEMORY(void) +{ + /* lock in host memory the text, data and bss segments */ + _go32_dpmi_lock_code(__SEAL_TEXT_BEGIN, + (long) __SEAL_TEXT_END - (long) __SEAL_TEXT_BEGIN); + + _go32_dpmi_lock_data(&__SEAL_DATA_BEGIN, + (long) &__SEAL_DATA_END - (long) &__SEAL_DATA_BEGIN); + + _go32_dpmi_lock_data(&__SEAL_BSS_BEGIN, + (long) &__SEAL_BSS_END - (long) &__SEAL_BSS_BEGIN); + + /* lock conventional memory used for DMA buffers and IRQ callbacks */ + _crt0_startup_flags |= _CRT0_FLAG_NEARPTR; + __djgpp_nearptr_enable(); + _go32_dpmi_lock_data((void *) __djgpp_conventional_base, 640 << 10); +} diff --git a/seal-hack/src/audiow32.c b/seal-hack/src/audiow32.c new file mode 100644 index 0000000..a6cecaf --- /dev/null +++ b/seal-hack/src/audiow32.c @@ -0,0 +1,68 @@ +/* + * $Id: audiow32.c 1.7 1996/09/20 23:55:38 chasan released $ + * 1.8 1998/12/24 15:07:30 chasan released (NT fix) + * + * Win32 dynamic-link library entry point routine + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include "audio.h" + +#ifdef WIN32 + +#define AUDIO_UPDATE_LATENCY 10 /* audio latency in milliseconds */ + +static HANDLE hThread; +static DWORD nThreadId; +static BOOL bTerminate; + +DWORD WINAPI UpdateAudioThread(LPVOID lpThreadParameter) +{ + LONG dwAudioTime, dwSleepTime; + + dwAudioTime = GetTickCount(); + while (!bTerminate) { + AUpdateAudio(); + dwAudioTime += AUDIO_UPDATE_LATENCY; + if ((dwSleepTime = dwAudioTime - GetTickCount()) > 0) + Sleep(dwSleepTime); + } + return (lpThreadParameter != NULL); +} + +#endif + +#ifdef __MSC__ +BOOL WINAPI DllMain(HINSTANCE hinstDLL, + DWORD fdwReason, LPVOID lpvReserved) +#else + BOOL WINAPI DllEntryPoint(HINSTANCE hinstDLL, + DWORD fdwReason, LPVOID lpvReserved) +#endif +{ + if (fdwReason == DLL_PROCESS_ATTACH) { + AInitialize(); +#ifdef WIN32 + bTerminate = FALSE; + hThread = CreateThread(NULL, 0, UpdateAudioThread, NULL, 0, &nThreadId); + SetPriorityClass(hThread, HIGH_PRIORITY_CLASS); + SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL); + } + if (fdwReason == DLL_PROCESS_DETACH) { + bTerminate = TRUE; + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); +#endif + } + if (hinstDLL != (HINSTANCE)0 && lpvReserved != (LPVOID)0) { + /* avoid compiler warnings */ + } + return TRUE; +} diff --git a/seal-hack/src/awedrv.c b/seal-hack/src/awedrv.c new file mode 100644 index 0000000..0e8da44 --- /dev/null +++ b/seal-hack/src/awedrv.c @@ -0,0 +1,1384 @@ +/* + * $Id: awedrv.c 1.10 1996/09/13 17:00:08 chasan released $ + * 1.11 1998/10/24 18:20:53 chasan released (Mixer API) + * + * Sound Blaster AWE32 audio driver. + * + * Copyright (C) 1996-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include "audio.h" +#include "drivers.h" +#include "msdos.h" + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + + +/* + * Macros to build a oscillator/register/port packed register + */ +#define AWEREG(nReg, nCnl, nPort) ((nCnl)|((nReg)<<5)|((nPort)<<8)) +#define ALL 0 + +/* + * Sound Blaster AWE32 I/O ports offsets + */ +#define AWE32_DATA0 0x400 /* read and write of dword data */ +#define AWE32_DATA1 0x800 /* read and write of word and dword */ +#define AWE32_DATA2 0x802 /* read and write of word data */ +#define AWE32_DATA3 0xC00 /* read and write of word data */ +#define AWE32_POINTER 0xC02 /* read and write of register pointer */ + +/* + * Sound Blaster AWE32 voice indirect registers + */ +#define CPF AWEREG(0, ALL, 0) /* current pitch and fractional address */ +#define PTRX AWEREG(1, ALL, 0) /* pitch target, reverb send, aux byte */ +#define CVCF AWEREG(2, ALL, 0) /* current volume and filter cutoff */ +#define VTFT AWEREG(3, ALL, 0) /* volume and filter cutoff targets */ +#define PSST AWEREG(6, ALL, 0) /* pan send and loop start address */ +#define CSL AWEREG(7, ALL, 0) /* chorus send and loop end address */ +#define CCCA AWEREG(0, ALL, 1) /* Q, control bits, current address */ +#define ENVVOL AWEREG(4, ALL, 1) /* volume envelope delay */ +#define DCYSUSV AWEREG(5, ALL, 1) /* volume envelope sustain and decay */ +#define ENVVAL AWEREG(6, ALL, 1) /* modulation envelope delay */ +#define DCYSUS AWEREG(7, ALL, 1) /* modulation envelope sustain and decay */ +#define ATKHLDV AWEREG(4, ALL, 2) /* volume envelope hold and attack */ +#define LFO1VAL AWEREG(5, ALL, 2) /* LFO#1 delay */ +#define ATKHLD AWEREG(6, ALL, 2) /* modulation envelope hold and attack */ +#define LFO2VAL AWEREG(7, ALL, 2) /* LFO#2 delay */ +#define IP AWEREG(0, ALL, 3) /* initial pitch */ +#define IFATN AWEREG(1, ALL, 3) /* initial filter cutoff and attenuation */ +#define PEFE AWEREG(2, ALL, 3) /* pitch and filter envelope heights */ +#define FMMOD AWEREG(3, ALL, 3) /* vibrato and filter modulation from LFO#1 */ +#define TREMFRQ AWEREG(4, ALL, 3) /* LFO#1 tremolo amount and frequency */ +#define FM2FRQ2 AWEREG(5, ALL, 3) /* LFO#2 vibrato amount and frequency */ +#define PROBE AWEREG(7, ALL, 3) /* dunno... not documented! */ + +/* + * Sound Blaster AWE32 global indirect registers + */ +#define HWCF4 AWEREG(1, 9, 1) /* configuration doubleword 4 */ +#define HWCF5 AWEREG(1, 10, 1) /* configuration doubleword 5 */ +#define HWCF6 AWEREG(1, 13, 1) /* configuration doubleword 6 */ +#define SMALR AWEREG(1, 20, 1) /* SM address for left SM reads */ +#define SMARR AWEREG(1, 21, 1) /* SM address for right SM reads */ +#define SMALW AWEREG(1, 22, 1) /* SM address for left SM writes */ +#define SMARW AWEREG(1, 23, 1) /* SM address for right SM writes */ +#define SMLD AWEREG(1, 26, 1) /* sound memory left data */ +#define SMRD AWEREG(1, 26, 2) /* sound memory right data */ +#define WC AWEREG(1, 27, 2) /* sample counter */ +#define HWCF1 AWEREG(1, 29, 1) /* configuration word 1 */ +#define HWCF2 AWEREG(1, 30, 1) /* configuration word 2 */ +#define HWCF3 AWEREG(1, 31, 1) /* configuration word 3 */ +#define INIT1 AWEREG(2, ALL, 1) /* initialization array 1 */ +#define INIT2 AWEREG(2, ALL, 2) /* initialization array 2 */ +#define INIT3 AWEREG(3, ALL, 1) /* initialization array 3 */ +#define INIT4 AWEREG(3, ALL, 2) /* initialization array 4 */ + + +/* + * Sound Blaster AWE32 Sound Memory Manager Defines + */ +#define NODE_HEADER_SIZE 4 +#define CLICKBUFSIZE 8 + +/* + * Sound Blaster AWE32 Chorus/Reverb/FilterQ default settings + */ +#define CHORUS 0 /*21*/ +#define REVERB 0 /*58*/ +#define FILTERQ 0 + + +/* + * Sound Blaster AWE32 Initialization Arrays + */ +static WORD aInitTableA[4*32] = { + 0x03FF, 0x0030, 0x07FF, 0x0130, 0x0BFF, 0x0230, 0x0FFF, 0x0330, + 0x13FF, 0x0430, 0x17FF, 0x0530, 0x1BFF, 0x0630, 0x1FFF, 0x0730, + 0x23FF, 0x0830, 0x27FF, 0x0930, 0x2BFF, 0x0A30, 0x2FFF, 0x0B30, + 0x33FF, 0x0C30, 0x37FF, 0x0D30, 0x3BFF, 0x0E30, 0x3FFF, 0x0F30, + + 0x43FF, 0x0030, 0x47FF, 0x0130, 0x4BFF, 0x0230, 0x4FFF, 0x0330, + 0x53FF, 0x0430, 0x57FF, 0x0530, 0x5BFF, 0x0630, 0x5FFF, 0x0730, + 0x63FF, 0x0830, 0x67FF, 0x0930, 0x6BFF, 0x0A30, 0x6FFF, 0x0B30, + 0x73FF, 0x0C30, 0x77FF, 0x0D30, 0x7BFF, 0x0E30, 0x7FFF, 0x0F30, + + 0x83FF, 0x0030, 0x87FF, 0x0130, 0x8BFF, 0x0230, 0x8FFF, 0x0330, + 0x93FF, 0x0430, 0x97FF, 0x0530, 0x9BFF, 0x0630, 0x9FFF, 0x0730, + 0xA3FF, 0x0830, 0xA7FF, 0x0930, 0xABFF, 0x0A30, 0xAFFF, 0x0B30, + 0xB3FF, 0x0C30, 0xB7FF, 0x0D30, 0xBBFF, 0x0E30, 0xBFFF, 0x0F30, + + 0xC3FF, 0x0030, 0xC7FF, 0x0130, 0xCBFF, 0x0230, 0xCFFF, 0x0330, + 0xD3FF, 0x0430, 0xD7FF, 0x0530, 0xDBFF, 0x0630, 0xDFFF, 0x0730, + 0xE3FF, 0x0830, 0xE7FF, 0x0930, 0xEBFF, 0x0A30, 0xEFFF, 0x0B30, + 0xF3FF, 0x0C30, 0xF7FF, 0x0D30, 0xFBFF, 0x0E30, 0xFFFF, 0x0F30 +}; + +static WORD aInitTableB[4*32] = { + 0x03FF, 0x8030, 0x07FF, 0x8130, 0x0BFF, 0x8230, 0x0FFF, 0x8330, + 0x13FF, 0x8430, 0x17FF, 0x8530, 0x1BFF, 0x8630, 0x1FFF, 0x8730, + 0x23FF, 0x8830, 0x27FF, 0x8930, 0x2BFF, 0x8A30, 0x2FFF, 0x8B30, + 0x33FF, 0x8C30, 0x37FF, 0x8D30, 0x3BFF, 0x8E30, 0x3FFF, 0x8F30, + + 0x43FF, 0x8030, 0x47FF, 0x8130, 0x4BFF, 0x8230, 0x4FFF, 0x8330, + 0x53FF, 0x8430, 0x57FF, 0x8530, 0x5BFF, 0x8630, 0x5FFF, 0x8730, + 0x63FF, 0x8830, 0x67FF, 0x8930, 0x6BFF, 0x8A30, 0x6FFF, 0x8B30, + 0x73FF, 0x8C30, 0x77FF, 0x8D30, 0x7BFF, 0x8E30, 0x7FFF, 0x8F30, + + 0x83FF, 0x8030, 0x87FF, 0x8130, 0x8BFF, 0x8230, 0x8FFF, 0x8330, + 0x93FF, 0x8430, 0x97FF, 0x8530, 0x9BFF, 0x8630, 0x9FFF, 0x8730, + 0xA3FF, 0x8830, 0xA7FF, 0x8930, 0xABFF, 0x8A30, 0xAFFF, 0x8B30, + 0xB3FF, 0x8C30, 0xB7FF, 0x8D30, 0xBBFF, 0x8E30, 0xBFFF, 0x8F30, + + 0xC3FF, 0x8030, 0xC7FF, 0x8130, 0xCBFF, 0x8230, 0xCFFF, 0x8330, + 0xD3FF, 0x8430, 0xD7FF, 0x8530, 0xDBFF, 0x8630, 0xDFFF, 0x8730, + 0xE3FF, 0x8830, 0xE7FF, 0x8930, 0xEBFF, 0x8A30, 0xEFFF, 0x8B30, + 0xF3FF, 0x8C30, 0xF7FF, 0x8D30, 0xFBFF, 0x8E30, 0xFFFF, 0x8F30 +}; + +static WORD aInitTableC[4*32] = { + 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5, + 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x8F7C, 0x167E, 0xF254, + 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x8BAA, 0x1B6D, 0xF234, + 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x86E7, 0x229E, 0xF224, + + 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x87F6, 0x2C28, 0xF254, + 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x8F02, 0x1341, 0xF264, + 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x8FA9, 0x3EB5, 0xF294, + 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0xC4C3, 0x3EBB, 0xC5C3, + + 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x8671, 0x14FD, 0x8287, + 0x3EBC, 0xE610, 0x3EC8, 0x8C7B, 0x031A, 0x87E6, 0x3EC8, 0x86F7, + 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x821F, 0x3ECA, 0x8386, + 0x3EC1, 0x8C03, 0x3EC9, 0x831E, 0x3ECA, 0x8C4C, 0x3EBF, 0x8C55, + + 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x8EAD, 0x3EC8, 0xD308, + 0x3EC2, 0x8F7E, 0x3ECB, 0x8219, 0x3ECB, 0xD26E, 0x3EC5, 0x831F, + 0x3EC6, 0xC308, 0x3EC3, 0xB2FF, 0x3EC9, 0x8265, 0x3EC9, 0x8319, + 0x1342, 0xD36E, 0x3EC7, 0xB3FF, 0x0000, 0x8365, 0x1420, 0x9570 +}; + +static WORD aInitTableD[4*32] = { + 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5, + 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254, + 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234, + 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x06E7, 0x229E, 0x7224, + + 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x07F6, 0x2C28, 0x7254, + 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x0F02, 0x1341, 0x7264, + 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x0FA9, 0x3EB5, 0x7294, + 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0x44C3, 0x3EBB, 0x45C3, + + 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x0671, 0x14FD, 0x0287, + 0x3EBC, 0xE610, 0x3EC8, 0x0C7B, 0x031A, 0x07E6, 0x3EC8, 0x86F7, + 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x021F, 0x3ECA, 0x0386, + 0x3EC1, 0x0C03, 0x3EC9, 0x031E, 0x3ECA, 0x8C4C, 0x3EBF, 0x0C55, + + 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x0EAD, 0x3EC8, 0xD308, + 0x3EC2, 0x8F7E, 0x3ECB, 0x0219, 0x3ECB, 0xD26E, 0x3EC5, 0x031F, + 0x3EC6, 0xC308, 0x3EC3, 0x32FF, 0x3EC9, 0x0265, 0x3EC9, 0x8319, + 0x1342, 0xD36E, 0x3EC7, 0x33FF, 0x0000, 0x8365, 0x1420, 0x9570 +}; + +/* + * Sound Blaster AWE32 Linear Volume Table + */ +static BYTE aVolumeTable[65] = { + 0xFF, + 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, + 0x36, 0x35, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, + 0x2F, 0x2E, 0x2D, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, + 0x29, 0x28, 0x27, 0x26, 0x26, 0x25, 0x24, 0x23, + 0x23, 0x22, 0x21, 0x21, 0x20, 0x1F, 0x1F, 0x1E, + 0x1D, 0x1D, 0x1C, 0x1B, 0x1B, 0x1A, 0x19, 0x19, + 0x18, 0x18, 0x17, 0x16, 0x16, 0x15, 0x15, 0x14, + 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x10, 0x10 +}; + + +/* + * Sound Blaster AWE32 configuration state + */ +static struct { + WORD wPort; + BYTE nIrqLine; + BYTE nDmaChannel; + WORD wBasePort; + WORD wPointerPort; + WORD wDataPort[4]; + DWORD dwTopOfMemory; + UINT nVoices; + DWORD aCurrentAddress[32]; + DWORD aStartAddress[32]; + DWORD aLoopStart[32]; + DWORD aLoopEnd[32]; + DWORD aFrequencyTable[32]; + BYTE aVolumeTable[32]; + BYTE aPanningTable[32]; + LPFNAUDIOTIMER lpfnAudioTimer; +} AWE32; + +static volatile BYTE nEmuIndex; + + +/* + * Low-level Sound Blaster AWE32 programming routines + */ +static VOID AWEPortW(WORD wIndex, WORD wData) +{ + nEmuIndex = LOBYTE(wIndex); + /* get oscillator number (0-31) and register number (0-7) */ + OUTW(AWE32.wPointerPort, LOBYTE(wIndex)); + /* write the word data into the specified I/O data port (0-3) */ + OUTW(AWE32.wDataPort[HIBYTE(wIndex)], wData); +} + +static WORD AWEPortRW(WORD wIndex) +{ + nEmuIndex = LOBYTE(wIndex); + OUTW(AWE32.wPointerPort, LOBYTE(wIndex)); + return INW(AWE32.wDataPort[HIBYTE(wIndex)]); +} + +static VOID AWEPortDW(WORD wIndex, DWORD dwData) +{ + nEmuIndex = LOBYTE(wIndex); + /* get oscillator number (0-31) and register number (0-7) */ + OUTW(AWE32.wPointerPort, LOBYTE(wIndex)); + /* write the doubleword data into the specified I/O port (0-1) */ + OUTW(AWE32.wDataPort[HIBYTE(wIndex)], LOWORD(dwData)); + OUTW(AWE32.wDataPort[HIBYTE(wIndex)] + 2, HIWORD(dwData)); +} + +static DWORD AWEPortRDW(WORD wIndex) +{ + DWORD dwData; + nEmuIndex = LOBYTE(wIndex); + OUTW(AWE32.wPointerPort, LOBYTE(wIndex)); + dwData = (DWORD) INW(AWE32.wDataPort[HIBYTE(wIndex)]); + dwData |= ((DWORD) INW(AWE32.wDataPort[HIBYTE(wIndex)] + 2)) << 16; + return dwData; +} + +static VOID AWEWait(UINT nTicks) +{ + UINT nTarget, nTimeOut; + nTarget = (WORD) (AWEPortRW(WC) + nTicks); + for (nTimeOut = 0; nTimeOut < 0xC000; nTimeOut++) + if (AWEPortRW(WC) == nTarget) break; +} + +static BOOL AWEProbe(WORD wBasePort) +{ + /* set up AWE32 base I/O port addresses */ + if (wBasePort > 0x300) wBasePort -= AWE32_DATA0; + AWE32.wDataPort[0] = wBasePort + AWE32_DATA0; + AWE32.wDataPort[1] = wBasePort + AWE32_DATA1; + AWE32.wDataPort[2] = wBasePort + AWE32_DATA2; + AWE32.wDataPort[3] = wBasePort + AWE32_DATA3; + AWE32.wPointerPort = wBasePort + AWE32_POINTER; + + /* probe if a EMU8000 chip is there */ + AWEPortRW(PROBE); + return ((AWEPortRW(PROBE) & 0x000f) == 0x000c && + (AWEPortRW(HWCF1) & 0x007e) == 0x0058 && + (AWEPortRW(HWCF2) & 0x0003) == 0x0003); +} + +static BOOL AWEInitialize(VOID) +{ + UINT n; + + /* check if we have an EMU8000 chip */ + if (!AWEProbe(AWE32.wBasePort)) + return TRUE; + + /* reset the hardware configuration */ + AWEPortW(HWCF1, 0x0059); + AWEPortW(HWCF2, 0x0020); + + /* initialize all the channels */ + for (n = 0; n < 32; n++) { + /* turn off envelope engine */ + AWEPortW(DCYSUSV + n, 0x0080); + } + for (n = 0; n < 32; n++) { + /* initialize all envelope and sound engine registers */ + AWEPortW(ENVVOL + n, 0x0000); + AWEPortW(ENVVAL + n, 0x0000); + AWEPortW(DCYSUS + n, 0x0000); + AWEPortW(ATKHLDV + n, 0x0000); + AWEPortW(LFO1VAL + n, 0x0000); + AWEPortW(ATKHLD + n, 0x0000); + AWEPortW(LFO2VAL + n, 0x0000); + AWEPortW(IP + n, 0x0000); + AWEPortW(IFATN + n, 0x0000); + AWEPortW(PEFE + n, 0x0000); + AWEPortW(FMMOD + n, 0x0000); + AWEPortW(TREMFRQ + n, 0x0000); + AWEPortW(FM2FRQ2 + n, 0x0000); + AWEPortDW(PTRX + n, 0x00000000L); + AWEPortDW(VTFT + n, 0x00000000L); + AWEPortDW(PSST + n, 0x00000000L); + AWEPortDW(CSL + n, 0x00000000L); + AWEPortDW(CCCA + n, 0x00000000L); + } + for (n = 0; n < 32; n++) { + /* now initialize the "current" registers */ + AWEPortDW(CPF + n, 0x00000000L); + AWEPortDW(CVCF + n, 0x00000000L); + } + + /* initialize the sound memory DMA registers */ + AWEPortW(SMALR, 0x0000); + AWEPortW(SMARR, 0x0000); + AWEPortW(SMALW, 0x0000); + AWEPortW(SMARW, 0x0000); + + /* set up the initialization arrays */ + + /* 1. copy the first set of initialization arrays */ + for (n = 0; n < 32; n++) + AWEPortW(INIT1 + n, aInitTableA[0x00 + n]); + for (n = 0; n < 32; n++) + AWEPortW(INIT2 + n, aInitTableA[0x20 + n]); + for (n = 0; n < 32; n++) + AWEPortW(INIT3 + n, aInitTableA[0x40 + n]); + for (n = 0; n < 32; n++) + AWEPortW(INIT4 + n, aInitTableA[0x60 + n]); + + /* 2. wait 1024 sample periods (24 msec) */ + AWEWait(1024); + + /* 3. copy second set of initialization arrays */ + for (n = 0; n < 32; n++) + AWEPortW(INIT1 + n, aInitTableB[0x00 + n]); + for (n = 0; n < 32; n++) + AWEPortW(INIT2 + n, aInitTableB[0x20 + n]); + for (n = 0; n < 32; n++) + AWEPortW(INIT3 + n, aInitTableB[0x40 + n]); + for (n = 0; n < 32; n++) + AWEPortW(INIT4 + n, aInitTableB[0x60 + n]); + + /* 4. copy third set of initialization arrays */ + for (n = 0; n < 32; n++) + AWEPortW(INIT1 + n, aInitTableC[0x00 + n]); + for (n = 0; n < 32; n++) + AWEPortW(INIT2 + n, aInitTableC[0x20 + n]); + for (n = 0; n < 32; n++) + AWEPortW(INIT3 + n, aInitTableC[0x40 + n]); + for (n = 0; n < 32; n++) + AWEPortW(INIT4 + n, aInitTableC[0x60 + n]); + + /* 5. set the harware configuration registers */ + AWEPortDW(HWCF4, 0x00000000L); + AWEPortDW(HWCF5, 0x00000083L); + AWEPortDW(HWCF6, 0x00008000L); + + /* 6. copy fourth set of initialization arrays */ + for (n = 0; n < 32; n++) + AWEPortW(INIT1 + n, aInitTableD[0x00 + n]); + for (n = 0; n < 32; n++) + AWEPortW(INIT2 + n, aInitTableD[0x20 + n]); + for (n = 0; n < 32; n++) + AWEPortW(INIT3 + n, aInitTableD[0x40 + n]); + for (n = 0; n < 32; n++) + AWEPortW(INIT4 + n, aInitTableD[0x60 + n]); + + /* enable audio output */ + AWEPortW(HWCF3, 0x0004); + + return FALSE; +} + +static DWORD AWEDetectMemory(VOID) +{ + DWORD dwAddr; + UINT nChannel, nTimeOut; + + /* allocate 15/15 channels in left read/write DMA mode */ + for (nChannel = 0; nChannel < 30; nChannel++) { + AWEPortW(DCYSUSV + nChannel, 0x0080); + AWEPortDW(VTFT + nChannel, 0x00000000L); + AWEPortDW(CVCF + nChannel, 0x00000000L); + AWEPortDW(PTRX + nChannel, 0x40000000L); + AWEPortDW(CPF + nChannel, 0x40000000L); + AWEPortDW(PSST + nChannel, 0x00000000L); + AWEPortDW(CSL + nChannel, 0x00000000L); + /* select left read/write and enter in DMA mode */ + AWEPortDW(CCCA + nChannel, nChannel & 1 ? 0x06000000L : 0x04000000L); + } + + /* wait until the empty and full bits of the DMA streams are clear */ + for (nTimeOut = 0; nTimeOut < 0x8000; nTimeOut++) + if (!(AWEPortRDW(SMALR) & 0x80000000L) && + !(AWEPortRDW(SMALW) & 0x80000000L)) break; + + /* write pattern at start of sound memory address space */ + AWEPortDW(SMALW, 0x00200000L); + AWEPortW(SMLD, 0xAAAA); + AWEPortW(SMLD, 0x5555); + + /* read it back to check if we have sound memory */ + AWEPortDW(SMALR, 0x00200000L); + AWEPortRW(SMLD); + if (AWEPortRW(SMLD) == 0xAAAA && + AWEPortRW(SMLD) == 0x5555) { + + /* check how much sound memory we have (up to 28MB) */ + for (dwAddr = 0x00220000L; dwAddr < 0xFE0000L; dwAddr += 0x10000L) { + + /* write pattern at sound memory step location */ + AWEPortDW(SMALW, dwAddr); + AWEPortW(SMLD, 0x1234); + AWEPortW(SMLD, 0x5678); + + /* check first sound memory location for mirrorring */ + AWEPortDW(SMALR, 0x00200000L); + AWEPortRW(SMLD); + if (AWEPortRW(SMLD) != 0xAAAA) break; + + /* now, check if the pattern was actually written */ + AWEPortDW(SMALR, dwAddr); + AWEPortDW(SMALR, dwAddr); + AWEPortRW(SMLD); + if (AWEPortRW(SMLD) != 0x1234 || + AWEPortRW(SMLD) != 0x5678) break; + } + dwAddr -= 0x00200000L; + } + else { + /* we do not have sound memory */ + dwAddr = 0L; + } + + /* wait until the empty and full bits of the DMA streams are clear */ + for (nTimeOut = 0; nTimeOut < 0x8000; nTimeOut++) + if (!(AWEPortRDW(SMALR) & 0x80000000L) && + !(AWEPortRDW(SMALW) & 0x80000000L)) break; + + /* deallocate 30 channels */ + for (nChannel = 0; nChannel < 30; nChannel++) { + AWEPortDW(CCCA + nChannel, 0x00000000L); + AWEPortW(DCYSUSV + nChannel, 0x807F); + } + + return dwAddr; +} + +static VOID AWEUploadData(BYTE nFirstChannel, DWORD dwAddress, + LPWORD lpData, UINT nCount) +{ + UINT nTimeOut, nChannel; + + /* allocate channels in left write DMA mode */ + for (nChannel = nFirstChannel; nChannel < 32; nChannel++) { + AWEPortW(DCYSUSV + nChannel, 0x0080); + AWEPortDW(VTFT + nChannel, 0x00000000L); + AWEPortDW(CVCF + nChannel, 0x00000000L); + AWEPortDW(PTRX + nChannel, 0x40000000L); + AWEPortDW(CPF + nChannel, 0x40000000L); + AWEPortDW(PSST + nChannel, 0x00000000L); + AWEPortDW(CSL + nChannel, 0x00000000L); + AWEPortDW(CCCA + nChannel, 0x06000000L); + } + + /* wait until the full bit of the DMA stream is clear */ + for (nTimeOut = 0; nTimeOut < 0x8000; nTimeOut++) + if (!(AWEPortRDW(SMALW) & 0x80000000L)) break; + + /* set start address for writting data */ + AWEPortDW(SMALW, dwAddress); + + /* upload 16-bit signed words to sound memory */ + while (nCount--) { + AWEPortW(SMLD, *lpData++); + } + + /* wait until the full bit of the DMA stream is clear */ + for (nTimeOut = 0; nTimeOut < 0x8000; nTimeOut++) + if (!(AWEPortRDW(SMALW) & 0x80000000L)) break; + + /* deallocate channels */ + for (nChannel = nFirstChannel; nChannel < 32; nChannel++) { + AWEPortDW(CCCA + nChannel, 0x00000000L); + AWEPortW(DCYSUSV + nChannel, 0x807F); + AWEPortW(DCYSUSV + nChannel, 0x0080); + AWEPortDW(VTFT + nChannel, 0x00000000L); + AWEPortDW(CVCF + nChannel, 0x00000000L); + AWEPortDW(PTRX + nChannel, 0x00000000L); + AWEPortDW(CPF + nChannel, 0x00000000L); + } +} + +static VOID AWEUploadData8(BYTE nFirstChannel, DWORD dwAddress, + LPBYTE lpData, UINT nCount) +{ + UINT nTimeOut, nChannel; + + /* allocate channels in left write DMA mode */ + for (nChannel = nFirstChannel; nChannel < 32; nChannel++) { + AWEPortW(DCYSUSV + nChannel, 0x0080); + AWEPortDW(VTFT + nChannel, 0x00000000L); + AWEPortDW(CVCF + nChannel, 0x00000000L); + AWEPortDW(PTRX + nChannel, 0x40000000L); + AWEPortDW(CPF + nChannel, 0x40000000L); + AWEPortDW(PSST + nChannel, 0x00000000L); + AWEPortDW(CSL + nChannel, 0x00000000L); + AWEPortDW(CCCA + nChannel, 0x06000000L); + } + + /* wait until the full bit of the DMA stream is clear */ + for (nTimeOut = 0; nTimeOut < 0x8000; nTimeOut++) + if (!(AWEPortRDW(SMALW) & 0x80000000L)) break; + + /* set start address for writting data */ + AWEPortDW(SMALW, dwAddress); + + /* upload 8-bit signed bytes to sound memory */ + while (nCount--) { + AWEPortW(SMLD, *lpData++ << 8); + } + + /* wait until the full bit of the DMA stream is clear */ + for (nTimeOut = 0; nTimeOut < 0x8000; nTimeOut++) + if (!(AWEPortRDW(SMALW) & 0x80000000L)) break; + + /* deallocate channel */ + for (nChannel = nFirstChannel; nChannel < 32; nChannel++) { + AWEPortDW(CCCA + nChannel, 0x00000000L); + AWEPortW(DCYSUSV + nChannel, 0x807F); + AWEPortW(DCYSUSV + nChannel, 0x0080); + AWEPortDW(VTFT + nChannel, 0x00000000L); + AWEPortDW(CVCF + nChannel, 0x00000000L); + AWEPortDW(PTRX + nChannel, 0x00000000L); + AWEPortDW(CPF + nChannel, 0x00000000L); + } +} + +static VOID AWEDownloadData(BYTE nFirstChannel, DWORD dwAddress, + LPWORD lpData, UINT nCount) +{ + UINT nTimeOut, nChannel; + + /* allocate channels in left read DMA mode */ + for (nChannel = nFirstChannel; nChannel < 32; nChannel++) { + AWEPortW(DCYSUSV + nChannel, 0x0080); + AWEPortDW(VTFT + nChannel, 0x00000000L); + AWEPortDW(CVCF + nChannel, 0x00000000L); + AWEPortDW(PTRX + nChannel, 0x40000000L); + AWEPortDW(CPF + nChannel, 0x40000000L); + AWEPortDW(PSST + nChannel, 0x00000000L); + AWEPortDW(CSL + nChannel, 0x00000000L); + AWEPortDW(CCCA + nChannel, 0x04000000L); + } + + /* wait until the empty bit of the DMA stream is clear */ + for (nTimeOut = 0; nTimeOut < 0x8000; nTimeOut++) + if (!(AWEPortRDW(SMALR) & 0x80000000L)) break; + + /* set start address for reading data */ + AWEPortDW(SMALR, dwAddress); + AWEPortRW(SMLD); + + /* download 16-bit signed words from sound memory */ + while (nCount--) { + *lpData++ = AWEPortRW(SMLD); + } + + /* wait until the empty bit of the DMA stream is clear */ + for (nTimeOut = 0; nTimeOut < 0x8000; nTimeOut++) + if (!(AWEPortRDW(SMALR) & 0x80000000L)) break; + + /* deallocate channel */ + for (nChannel = nFirstChannel; nChannel < 32; nChannel++) { + AWEPortDW(CCCA + nChannel, 0x00000000L); + AWEPortW(DCYSUSV + nChannel, 0x807F); + AWEPortW(DCYSUSV + nChannel, 0x0080); + AWEPortDW(VTFT + nChannel, 0x00000000L); + AWEPortDW(CVCF + nChannel, 0x00000000L); + AWEPortDW(PTRX + nChannel, 0x00000000L); + AWEPortDW(CPF + nChannel, 0x00000000L); + } +} + +static VOID AWEPrimeNote(BYTE nChannel, WORD wPitch, + BYTE nVolume, BYTE nPanning, BYTE nChorusSend, BYTE nFilterQ, + DWORD dwStartAddress, DWORD dwLoopStart, DWORD dwLoopEnd) +{ + /* first the channel must be silent and idle */ + AWEPortW(DCYSUSV + nChannel, 0x0080); + AWEPortDW(VTFT + nChannel, 0x00000000L); + AWEPortDW(CVCF + nChannel, 0x00000000L); + AWEPortDW(PTRX + nChannel, 0x00000000L); + AWEPortDW(CPF + nChannel, 0x00000000L); + + /* now set the envelope engine parameters */ + AWEPortW(ENVVOL + nChannel, 0x8000); + AWEPortW(ENVVAL + nChannel, 0x8000); + AWEPortW(DCYSUS + nChannel, 0x7F7F); + AWEPortW(ATKHLDV + nChannel, 0x7F7F); + AWEPortW(LFO1VAL + nChannel, 0x8000); + AWEPortW(ATKHLD + nChannel, 0x7F7F); + AWEPortW(LFO2VAL + nChannel, 0x8000); + AWEPortW(IP + nChannel, wPitch); + AWEPortW(IFATN + nChannel, 0xFF00 | nVolume); + AWEPortW(PEFE + nChannel, 0x0000); + AWEPortW(FMMOD + nChannel, 0x0000); + AWEPortW(TREMFRQ + nChannel, 0x0010); + AWEPortW(FM2FRQ2 + nChannel, 0x0010); + + /* decrease memory addresses (due to interpolator offset) */ + dwStartAddress--; + dwLoopStart--; + dwLoopEnd--; + + /* set the loop start and loop end addresses */ + AWEPortDW(PSST + nChannel, ((DWORD) nPanning << 24) | dwLoopStart); + AWEPortDW(CSL + nChannel, ((DWORD) nChorusSend << 24) | dwLoopEnd); + + /* set filter Q of channel and audio start address */ + AWEPortDW(CCCA + nChannel, ((DWORD) nFilterQ << 28) | dwStartAddress); +} + +static VOID AWEStartNote(BYTE nChannel) +{ + /* start the note (do it all as close to simultaneously as possible) */ + AWEPortDW(VTFT + nChannel, 0x0000FFFFL); + AWEPortDW(CVCF + nChannel, 0x0000FFFFL); + AWEPortW(DCYSUSV + nChannel, 0x7F7F); + AWEPortDW(PTRX + nChannel, 0x40000000L | (REVERB << 8)); + AWEPortDW(CPF + nChannel, 0x40000000L); +} + +static VOID AWEStopNote(BYTE nChannel) +{ + /* turn off the envolope engine and take the volume to zero */ + AWEPortW(DCYSUSV + nChannel, 0x0080); + AWEPortDW(VTFT + nChannel, 0x0000FFFFL); + AWEPortDW(CVCF + nChannel, 0x0000FFFFL); +} + +static VOID AWEReleaseNote(BYTE nChannel, BYTE nReleaseRate) +{ + /* enter the envelope in release mode */ + AWEPortW(DCYSUSV + nChannel, 0x8000 | nReleaseRate); +} + +static VOID AWESetNoteOffset(BYTE nChannel, DWORD dwStartAddress, BYTE nFilterQ) +{ + /* set filter Q of channel and audio start address */ + AWEPortDW(CCCA + nChannel, ((DWORD) nFilterQ << 28) | dwStartAddress); +} + +static DWORD AWEGetNoteOffset(BYTE nChannel) +{ + DWORD dwCCCA; + dwCCCA = AWEPortRDW(CCCA + nChannel); + return (dwCCCA & 0x00FFFFFFL); +} + +static VOID AWESetNotePitch(BYTE nChannel, WORD wPitch) +{ + /* change the initial pitch register on the fly */ + AWEPortW(IP + nChannel, wPitch); +} + +static VOID AWESetNoteVolume(BYTE nChannel, BYTE nVolume) +{ + /* change the volume bit field of IFATN and set filter cutoff to 8 kHz */ + AWEPortW(IFATN + nChannel, 0xFF00 | nVolume); +} + +static VOID AWESetNotePanning(BYTE nChannel, BYTE nPanning, DWORD dwLoopStart) +{ + /* change the voice panning position and loop start address */ + AWEPortDW(PSST + nChannel, ((DWORD) nPanning << 24) | dwLoopStart); +} + +static WORD AWEGetPitchShift(DWORD dwFrequency) +{ + UINT n, nPitch; + + /* convert frequency to logarithmic pitch shift */ + + if (dwFrequency <= (44100 >> 14)) + return 0x0000; + if (dwFrequency >= (44100 << 2)) + return 0xFFFF; + + dwFrequency <<= 14; + dwFrequency /= 44100; + + nPitch = 0x0000; + for (n = 16; n--; ) { + if (dwFrequency >= (1 << n)) { + nPitch = n << 12; + dwFrequency <<= 14; + dwFrequency >>= n; + break; + } + } + for (n = 12; n--; ) { + dwFrequency = (dwFrequency * dwFrequency) >> 14; + if (dwFrequency >= (2 << 14)) { + nPitch += 1 << n; + dwFrequency >>= 1; + } + } + return (WORD) nPitch; +} + + +/* + * Sound Blaster AWE32 Sound Memory Manager + */ +static VOID AWEPokeDW(DWORD dwAddress, DWORD dwValue) +{ + AWEUploadData(AWE32.nVoices, dwAddress, (LPWORD) &dwValue, 2); +} + +static DWORD AWEPeekDW(DWORD dwAddress) +{ + DWORD dwValue; + AWEDownloadData(AWE32.nVoices, dwAddress, (LPWORD) &dwValue, 2); + return dwValue; +} + +static BOOL AWEInitMemory(VOID) +{ + DWORD dwMemorySize; + + /* get amount of AWE32 memory size (16-bit words) */ + if ((dwMemorySize = AWEDetectMemory()) <= 2*NODE_HEADER_SIZE) + return TRUE; + + /* set up heap memory blocks */ + AWE32.dwTopOfMemory = 0x200000L + dwMemorySize; + AWEPokeDW(0x200000L + 0, 0x200000L + NODE_HEADER_SIZE); + AWEPokeDW(0x200000L + 2, NODE_HEADER_SIZE); + AWEPokeDW(0x200000L + NODE_HEADER_SIZE + 0, 0x000000L); + AWEPokeDW(0x200000L + NODE_HEADER_SIZE + 2, dwMemorySize - NODE_HEADER_SIZE); + + return FALSE; +} + +static DWORD AWEMemAvail(VOID) +{ + DWORD dwNode, dwPrevNode, dwSize; + + dwSize = 0; + dwPrevNode = 0x200000L; + while ((dwNode = AWEPeekDW(dwPrevNode + 0)) != 0x000000L) { + dwSize += AWEPeekDW(dwNode + 2); + dwPrevNode = dwNode; + } + + /* return number of 8-bit bytes availables */ + return dwSize << 1; +} + +static DWORD AWEMemAlloc(DWORD dwSize) +{ + DWORD dwNode, dwPrevNode, dwNodeSize; + + if ((dwSize += NODE_HEADER_SIZE) != 0L) { + dwSize = (dwSize + NODE_HEADER_SIZE - 1) & -NODE_HEADER_SIZE; + dwPrevNode = 0x200000L; + while ((dwNode = AWEPeekDW(dwPrevNode + 0)) != 0L) { + if ((dwNodeSize = AWEPeekDW(dwNode + 2)) >= dwSize) { + if (dwNodeSize == dwSize) { + AWEPokeDW(dwPrevNode + 0, AWEPeekDW(dwNode + 0)); + } + else { + dwNodeSize -= dwSize; + AWEPokeDW(dwNode + 2, dwNodeSize); + dwNode += dwNodeSize; + AWEPokeDW(dwNode + 2, dwSize); + } + AWEPokeDW(dwNode + 0, ~dwSize); + return (dwNode + NODE_HEADER_SIZE); + } + dwPrevNode = dwNode; + } + } + return 0L; +} + +static VOID AWEMemFree(DWORD dwAddr) +{ + DWORD dwNode, dwNextNode, dwNodeSize; + + if ((dwAddr -= NODE_HEADER_SIZE) < AWE32.dwTopOfMemory && + AWEPeekDW(dwAddr + 0) == ~AWEPeekDW(dwAddr + 2)) { + dwNode = 0x200000L; + while (dwNode != AWE32.dwTopOfMemory) { + if ((dwNextNode = AWEPeekDW(dwNode + 0)) == 0x000000L) + dwNextNode = AWE32.dwTopOfMemory; + if (dwAddr > dwNode && dwAddr < dwNextNode) + break; + dwNode = dwNextNode; + } + if (dwNode != AWE32.dwTopOfMemory) { + if (dwNextNode == AWE32.dwTopOfMemory) + dwNextNode = 0x00000L; + dwNodeSize = AWEPeekDW(dwAddr + 2); + if (dwAddr + dwNodeSize == dwNextNode) { + AWEPokeDW(dwAddr + 2, dwNodeSize + AWEPeekDW(dwNextNode + 2)); + AWEPokeDW(dwAddr + 0, AWEPeekDW(dwNextNode + 0)); + } + else { + AWEPokeDW(dwAddr + 0, dwNextNode); + } + dwNodeSize = AWEPeekDW(dwNode + 2); + if (dwNode + dwNodeSize == dwAddr) { + AWEPokeDW(dwNode + 2, dwNodeSize + AWEPeekDW(dwAddr + 2)); + AWEPokeDW(dwNode + 0, AWEPeekDW(dwAddr + 0)); + } + else { + AWEPokeDW(dwNode + 0, dwAddr); + } + } + } +} + + +/* + * Sound Blaster AWE32 DSP-based timer routines + */ +static VOID SB16PortB(BYTE bData) +{ + UINT nTimeOut; + + for (nTimeOut = 0; nTimeOut < 0x8000; nTimeOut++) + if (!(INB(AWE32.wPort + 0x0C) & 0x80)) + break; + OUTB(AWE32.wPort + 0x0C, bData); +} + +static UINT SB16Reset(VOID) +{ + UINT n, nTimeOut; + + for (n = 0; n < 8; n++) { + /* first reset the DSP processor */ + OUTB(AWE32.wPort + 0x06, 0x01); + for (nTimeOut = 0; nTimeOut < 8; nTimeOut++) + INB(AWE32.wPort + 0x06); + OUTB(AWE32.wPort + 0x06, 0x00); + + /* now wait to get back the DSP acknowledge */ + for (nTimeOut = 0; nTimeOut < 0x8000; nTimeOut++) + if (INB(AWE32.wPort + 0x0E) & 0x80) + break; + if (INB(AWE32.wPort + 0x0A) == 0xAA) + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_NODEVICE; +} + +static VOID AWEInterruptHandler(VOID) +{ + BYTE nSaveIndex; + + if (AWE32.lpfnAudioTimer != NULL) { + nSaveIndex = nEmuIndex; + AWE32.lpfnAudioTimer(); + nEmuIndex = nSaveIndex; + OUTW(AWE32.wPointerPort, nEmuIndex); + } + INB(AWE32.wPort + 0x0E); +} + +static UINT AWEInitTimer(VOID) +{ + LPBYTE lpBuffer; + + /* reset the DSP processor */ + if (SB16Reset()) + return AUDIO_ERROR_NODEVICE; + + /* turn off the DSP speaker */ + SB16PortB(0xD3); + + /* set output sample rate to 44100 Hz */ + SB16PortB(0x41); + SB16PortB(HIBYTE(44100)); + SB16PortB(LOBYTE(44100)); + + /* allocate and clear small DMA buffer */ + if (DosAllocChannel(AWE32.nDmaChannel, 4)) + return AUDIO_ERROR_NOMEMORY; + + if ((lpBuffer = DosLockChannel(AWE32.nDmaChannel)) != NULL) { + memset(lpBuffer, 0x80, 4); + DosUnlockChannel(AWE32.nDmaChannel); + } + + /* setup the DMA channel parameters */ + DosSetupChannel(AWE32.nDmaChannel, DMA_WRITE | DMA_AUTOINIT, 0); + + /* setup our IRQ interrupt handler */ + DosSetVectorHandler(AWE32.nIrqLine, AWEInterruptHandler); + + return AUDIO_ERROR_NONE; +} + +static VOID AWEDoneTimer(VOID) +{ + /* reset the DSP processor */ + SB16Reset(); + + /* turn off DSP speaker */ + SB16PortB(0xD3); + + /* restore the interrupt handler */ + DosSetVectorHandler(AWE32.nIrqLine, NULL); + + /* reset and release DMA buffer */ + DosDisableChannel(AWE32.nDmaChannel); + DosFreeChannel(AWE32.nDmaChannel); +} + +static VOID AWESetTimerRate(UINT nTicks) +{ + /* start 8-bit mono high-speed autoinit DMA transfer */ + SB16PortB(0xC6); + SB16PortB(0x00); + nTicks--; + SB16PortB(LOBYTE(nTicks)); + SB16PortB(HIBYTE(nTicks)); +} + + +/* + * Sound Blaster AWE32 driver API interface + */ +static UINT AIAPI GetAudioCaps(LPAUDIOCAPS lpCaps) +{ + static AUDIOCAPS Caps = { + AUDIO_PRODUCT_AWE32, "Sound Blaster AWE32", + AUDIO_FORMAT_4S16, + }; + memcpy(lpCaps, &Caps, sizeof(AUDIOCAPS)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI PingAudio(VOID) +{ + LPSTR lpszBlaster; + UINT n; + + if ((lpszBlaster = DosGetEnvironment("BLASTER")) != NULL) { + AWE32.wPort = 0x220; + AWE32.nIrqLine = 5; + AWE32.nDmaChannel = 1; + AWE32.wBasePort = 0x620; + n = DosParseString(lpszBlaster, TOKEN_CHAR); + while (n != 0) { + switch (n) { + case 'A': + case 'a': + AWE32.wPort = DosParseString(NULL, TOKEN_HEX); + break; + case 'I': + case 'i': + AWE32.nIrqLine = DosParseString(NULL, TOKEN_DEC); + break; + case 'D': + case 'd': + AWE32.nDmaChannel = DosParseString(NULL, TOKEN_DEC); + break; + case 'E': + case 'e': + AWE32.wBasePort = DosParseString(NULL, TOKEN_HEX); + break; + } + n = DosParseString(NULL, TOKEN_CHAR); + } + if (AWEProbe(AWE32.wBasePort) && AWEDetectMemory()) + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_NODEVICE; +} + +static UINT AIAPI OpenAudio(LPAUDIOINFO lpInfo) +{ + /* initialize the AWE32 driver for playback */ + memset(&AWE32, 0, sizeof(AWE32)); + if (PingAudio()) + return AUDIO_ERROR_NODEVICE; + if (AWEInitialize()) + return AUDIO_ERROR_NODEVICE; + if (AWEInitMemory()) + return AUDIO_ERROR_NODRAMMEMORY; + if (AWEInitTimer()) + return AUDIO_ERROR_NODEVICE; + + /* set caller playback format fields */ + lpInfo->wFormat = AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO; + lpInfo->nSampleRate = 44100; + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI CloseAudio(VOID) +{ + UINT nVoice; + + /* reset and release AWE32 timer resources */ + AWEDoneTimer(); + + /* reset EMU8000 synthesizer and exit */ + for (nVoice = 0; nVoice < 31; nVoice++) + AWEStopNote(nVoice); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudio(VOID) +{ + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioMixerValue(UINT nChannel, UINT nValue) +{ + if (nChannel != AUDIO_MIXER_MASTER_VOLUME && + nChannel != AUDIO_MIXER_TREBLE && + nChannel != AUDIO_MIXER_BASS && + nChannel != AUDIO_MIXER_CHORUS && + nChannel != AUDIO_MIXER_REVERB) + return AUDIO_ERROR_NOTSUPPORTED; + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI OpenVoices(UINT nVoices) +{ + if (nVoices < AUDIO_MAX_VOICES && nVoices < 31) { + AWE32.nVoices = nVoices; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; +} + +static UINT AIAPI CloseVoices(VOID) +{ + UINT nVoice; + for (AWE32.nVoices = nVoice = 0; nVoice < 31; nVoice++) + AWEStopNote(nVoice); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioTimerProc(LPFNAUDIOTIMER lpfnAudioTimer) +{ + AWE32.lpfnAudioTimer = lpfnAudioTimer; + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioTimerRate(UINT nBPM) +{ + UINT nTicks; + + if (nBPM >= 0x20 && nBPM <= 0xFF) { + nTicks = (44100 * 5) / (2 * nBPM); + AWESetTimerRate(nTicks); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; +} + +static LONG AIAPI GetAudioDataAvail(VOID) +{ + return AWEMemAvail(); +} + +static UINT AIAPI CreateAudioData(LPAUDIOWAVE lpWave) +{ + if (lpWave != NULL) { + if (lpWave->wFormat & AUDIO_FORMAT_16BITS) + lpWave->dwHandle = AWEMemAlloc((lpWave->dwLength >> 1) + CLICKBUFSIZE); + else + lpWave->dwHandle = AWEMemAlloc(lpWave->dwLength + CLICKBUFSIZE); + return lpWave->dwHandle ? AUDIO_ERROR_NONE : AUDIO_ERROR_NODRAMMEMORY; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI DestroyAudioData(LPAUDIOWAVE lpWave) +{ + if (lpWave != NULL && lpWave->dwHandle != 0) { + AWEMemFree(lpWave->dwHandle); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI WriteAudioData(LPAUDIOWAVE lpWave, + DWORD dwOffset, UINT nCount) +{ + static WORD aClickBuffer[CLICKBUFSIZE]; + + if (lpWave != NULL && lpWave->dwHandle != 0) { + if (dwOffset + nCount <= lpWave->dwLength) { + if (lpWave->wFormat & AUDIO_FORMAT_16BITS) { + AWEUploadData(AWE32.nVoices, lpWave->dwHandle + (dwOffset >> 1), + (LPWORD) (lpWave->lpData + dwOffset), nCount >> 1); + } + else { + AWEUploadData8(AWE32.nVoices, lpWave->dwHandle + dwOffset, + lpWave->lpData + dwOffset, nCount); + } + + if (lpWave->wFormat & (AUDIO_FORMAT_LOOP | AUDIO_FORMAT_BIDILOOP)) { + if (dwOffset <= lpWave->dwLoopEnd && + dwOffset + nCount >= lpWave->dwLoopEnd) { + if (lpWave->wFormat & AUDIO_FORMAT_16BITS) { + AWEDownloadData(AWE32.nVoices, + lpWave->dwHandle + (lpWave->dwLoopStart >> 1), + aClickBuffer, CLICKBUFSIZE); + AWEUploadData(AWE32.nVoices, + lpWave->dwHandle + (lpWave->dwLoopEnd >> 1), + aClickBuffer, CLICKBUFSIZE); + } + else { + AWEDownloadData(AWE32.nVoices, + lpWave->dwHandle + lpWave->dwLoopStart, + aClickBuffer, CLICKBUFSIZE); + AWEUploadData(AWE32.nVoices, + lpWave->dwHandle + lpWave->dwLoopEnd, + aClickBuffer, CLICKBUFSIZE); + } + } + } + else if (dwOffset + nCount >= lpWave->dwLength) { + memset(aClickBuffer, 0, sizeof(aClickBuffer)); + if (lpWave->wFormat & AUDIO_FORMAT_16BITS) { + AWEUploadData(AWE32.nVoices, + lpWave->dwHandle + (lpWave->dwLength >> 1), + aClickBuffer, CLICKBUFSIZE); + } + else { + AWEUploadData(AWE32.nVoices, + lpWave->dwHandle + lpWave->dwLength, + aClickBuffer, CLICKBUFSIZE); + } + } + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI PrimeVoice(UINT nVoice, LPAUDIOWAVE lpWave) +{ + DWORD dwLength, dwLoopStart, dwLoopEnd; + + if (nVoice < 31 && lpWave != NULL && lpWave->dwHandle != 0) { + AWE32.aStartAddress[nVoice] = + AWE32.aCurrentAddress[nVoice] = lpWave->dwHandle; + dwLength = lpWave->dwLength; + dwLoopStart = lpWave->dwLoopStart; + dwLoopEnd = lpWave->dwLoopEnd; + if (lpWave->wFormat & AUDIO_FORMAT_16BITS) { + dwLength >>= 1; + dwLoopStart >>= 1; + dwLoopEnd >>= 1; + } + if (lpWave->wFormat & (AUDIO_FORMAT_LOOP | AUDIO_FORMAT_BIDILOOP)) { + AWE32.aLoopStart[nVoice] = dwLoopStart; + AWE32.aLoopEnd[nVoice] = dwLoopEnd; + } + else { + AWE32.aLoopStart[nVoice] = dwLength + 2; + AWE32.aLoopEnd[nVoice] = dwLength + CLICKBUFSIZE - 2; + } + + AWEPrimeNote(nVoice, + AWEGetPitchShift(AWE32.aFrequencyTable[nVoice]), + aVolumeTable[AWE32.aVolumeTable[nVoice]], + 0xFF - AWE32.aPanningTable[nVoice], + CHORUS, FILTERQ, + AWE32.aStartAddress[nVoice], + AWE32.aStartAddress[nVoice] + AWE32.aLoopStart[nVoice], + AWE32.aStartAddress[nVoice] + AWE32.aLoopEnd[nVoice]); + + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI StartVoice(UINT nVoice) +{ + if (nVoice < 31) { + if (AWE32.aCurrentAddress[nVoice]) { + AWESetNoteOffset(nVoice, AWE32.aCurrentAddress[nVoice], FILTERQ); + AWEStartNote(nVoice); + AWE32.aCurrentAddress[nVoice] = 0; + } + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI StopVoice(UINT nVoice) +{ + if (nVoice < 31) { + /* release the note at 240 usec/dB (faster rate) */ + if (!AWE32.aCurrentAddress[nVoice]) { + AWE32.aCurrentAddress[nVoice] = AWEGetNoteOffset(nVoice); + AWEReleaseNote(nVoice, 0x7F); + } + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI SetVoicePosition(UINT nVoice, LONG dwPosition) +{ + if (nVoice < 31) { + if (dwPosition >= 0 && dwPosition <= AWE32.aLoopEnd[nVoice]) { + AWESetNoteOffset(nVoice, + AWE32.aStartAddress[nVoice] + dwPosition, 0); + if (AWE32.aCurrentAddress[nVoice]) + AWE32.aCurrentAddress[nVoice] = AWEGetNoteOffset(nVoice); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI SetVoiceFrequency(UINT nVoice, LONG dwFrequency) +{ + if (nVoice < 31) { + if (dwFrequency >= AUDIO_MIN_FREQUENCY && + dwFrequency <= AUDIO_MAX_FREQUENCY) { + AWE32.aFrequencyTable[nVoice] = dwFrequency; + AWESetNotePitch(nVoice, AWEGetPitchShift(dwFrequency)); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI SetVoiceVolume(UINT nVoice, UINT nVolume) +{ + if (nVoice < 31) { + if (nVolume <= AUDIO_MAX_VOLUME) { + AWE32.aVolumeTable[nVoice] = nVolume; + AWESetNoteVolume(nVoice, aVolumeTable[nVolume]); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI SetVoicePanning(UINT nVoice, UINT nPanning) +{ + if (nVoice < 31) { + if (nPanning <= AUDIO_MAX_PANNING) { + AWE32.aPanningTable[nVoice] = nPanning; + AWESetNotePanning(nVoice, 0xFF - nPanning, + AWE32.aStartAddress[nVoice] + AWE32.aLoopStart[nVoice]); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoicePosition(UINT nVoice, LPLONG lpdwPosition) +{ + if (nVoice < 31) { + if (lpdwPosition != NULL) { + *lpdwPosition = AWEGetNoteOffset(nVoice) - + AWE32.aStartAddress[nVoice]; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoiceFrequency(UINT nVoice, LPLONG lpdwFrequency) +{ + if (nVoice < 31) { + if (lpdwFrequency != NULL) { + *lpdwFrequency = AWE32.aFrequencyTable[nVoice]; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoiceVolume(UINT nVoice, LPUINT lpnVolume) +{ + if (nVoice < 31) { + if (lpnVolume != NULL) { + *lpnVolume = AWE32.aVolumeTable[nVoice]; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoicePanning(UINT nVoice, LPUINT lpnPanning) +{ + if (nVoice < 31) { + if (lpnPanning != NULL) { + *lpnPanning = AWE32.aPanningTable[nVoice]; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoiceStatus(UINT nVoice, LPBOOL lpbStatus) +{ + if (nVoice < 31) { + if (lpbStatus != NULL) { + *lpbStatus = (AWE32.aLoopStart[nVoice] + CLICKBUFSIZE - 4 == AWE32.aLoopEnd[nVoice]) && + (AWEGetNoteOffset(nVoice) >= + AWE32.aStartAddress[nVoice] + AWE32.aLoopStart[nVoice]); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + + +/* + * Sound Blaster AWE32 driver public interface + */ +AUDIOSYNTHDRIVER SoundBlaster32SynthDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudio, OpenVoices, CloseVoices, + SetAudioTimerProc, SetAudioTimerRate, SetAudioMixerValue, + GetAudioDataAvail, CreateAudioData, DestroyAudioData, + WriteAudioData, PrimeVoice, StartVoice, StopVoice, + SetVoicePosition, SetVoiceFrequency, SetVoiceVolume, + SetVoicePanning, GetVoicePosition, GetVoiceFrequency, + GetVoiceVolume, GetVoicePanning, GetVoiceStatus +}; + +AUDIODRIVER SoundBlaster32Driver = +{ + NULL, &SoundBlaster32SynthDriver +}; diff --git a/seal-hack/src/be3drv.c b/seal-hack/src/be3drv.c new file mode 100644 index 0000000..c1a12df --- /dev/null +++ b/seal-hack/src/be3drv.c @@ -0,0 +1,185 @@ +/* + * $Id: be3drv.c 1.0 1998/10/12 00:33:08 chasan Exp $ + * + * Intel BeOS Release 3 audio driver. + * + * Copyright (C) 1998-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include "BeOS/old_audio_driver.h" +#include "audio.h" +#include "drivers.h" + +#define BUFFERSIZE (1 << 12) + +/* + * BeOS driver configuration structure + */ +static struct { + int nHandle; + char szDeviceName[MAXNAMLEN]; + BYTE aBuffer[sizeof(audio_buffer_header) + BUFFERSIZE]; + LPFNAUDIOWAVE lpfnAudioWave; +} Audio; + + +/* + * BeOS driver API interface + */ +static UINT AIAPI GetAudioCaps(LPAUDIOCAPS lpCaps) +{ + static AUDIOCAPS Caps = + { + AUDIO_PRODUCT_BEOSR3, "BeOS R3 Sound Driver", + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_1M16 | AUDIO_FORMAT_1S16 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_2M16 | AUDIO_FORMAT_2S16 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 | + AUDIO_FORMAT_4M16 | AUDIO_FORMAT_4S16 + }; + + memcpy(lpCaps, &Caps, sizeof(AUDIOCAPS)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI PingAudio(VOID) +{ + DIR *dir; + struct dirent *entry; + + /* first try the default sound device */ + strcpy(Audio.szDeviceName, "/dev/old/sound"); + if (access(Audio.szDeviceName, W_OK) == 0) + return AUDIO_ERROR_NONE; + + /* search an old audio device */ + if ((dir = opendir("/dev/old")) != 0) { + while ((entry = readdir(dir)) != 0) { + if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) { + strcat(strcpy(Audio.szDeviceName, "/dev/old/"), entry->d_name); + if (access(Audio.szDeviceName, W_OK) == 0) { + closedir(dir); + return AUDIO_ERROR_NONE; + } + } + } + closedir(dir); + } + return AUDIO_ERROR_NODEVICE; +} + +static UINT AIAPI OpenAudio(LPAUDIOINFO lpInfo) +{ + static int sample_rates[] = { + 5510, B_AUDIO_SAMPLE_RATE_5510, + 6620, B_AUDIO_SAMPLE_RATE_6620, + 8000, B_AUDIO_SAMPLE_RATE_8000, + 9600, B_AUDIO_SAMPLE_RATE_9600, + 11025, B_AUDIO_SAMPLE_RATE_11025, + 16000, B_AUDIO_SAMPLE_RATE_16000, + 18900, B_AUDIO_SAMPLE_RATE_18900, + 22050, B_AUDIO_SAMPLE_RATE_22050, + 27420, B_AUDIO_SAMPLE_RATE_27420, + 32000, B_AUDIO_SAMPLE_RATE_32000, + 33075, B_AUDIO_SAMPLE_RATE_33075, + 37800, B_AUDIO_SAMPLE_RATE_37800, + 44100, B_AUDIO_SAMPLE_RATE_44100, + 48000, B_AUDIO_SAMPLE_RATE_48000 }; + + struct audio_params params; + int index; + + memset(&Audio, 0, sizeof(Audio)); + + /* search an old audio device for playback */ + if (PingAudio() != AUDIO_ERROR_NONE) + return AUDIO_ERROR_NODEVICE; + + /* try to open audio device for playback */ + if ((Audio.nHandle = open(Audio.szDeviceName, O_WRONLY)) < 0) + return AUDIO_ERROR_DEVICEBUSY; + + /* setup audio playback encoding format and sampling frequency */ + if (ioctl(Audio.nHandle, B_AUDIO_GET_PARAMS, ¶ms) < 0) { + close(Audio.nHandle); + return AUDIO_ERROR_NODEVICE; + } + + for (index = 0; index < 2*13; index += 2) { + if (sample_rates[index] >= lpInfo->nSampleRate) + break; + } + lpInfo->nSampleRate = sample_rates[index]; + params.sample_rate = sample_rates[index+1]; + + lpInfo->wFormat |= AUDIO_FORMAT_STEREO | AUDIO_FORMAT_16BITS; + /* params.playback_format = B_AUDIO_FORMAT_16_BIT_STEREO; */ + + if (ioctl(Audio.nHandle, B_AUDIO_SET_PARAMS, ¶ms) < 0) { + close(Audio.nHandle); + return AUDIO_ERROR_BADFORMAT; + } + + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI CloseAudio(VOID) +{ + /* close DSP audio device */ + close(Audio.nHandle); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudio(UINT nFrames) +{ + audio_buffer_header *header = (audio_buffer_header *) Audio.aBuffer; + + /* compute frame size */ + nFrames <<= 2; + if (nFrames <= 0 || nFrames > BUFFERSIZE) + nFrames = BUFFERSIZE; + + /* send PCM samples to the DSP audio device */ + if (Audio.lpfnAudioWave != NULL) { + Audio.lpfnAudioWave(Audio.aBuffer + sizeof(*header), nFrames); + header->buffer_number = 0; + header->subscriber_count = 0; + header->reserved_1 = sizeof(*header) + nFrames; + ioctl(Audio.nHandle, B_AUDIO_WRITE_BUFFER, header); + } + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + /* set up DSP audio device user's callback function */ + Audio.lpfnAudioWave = lpfnAudioWave; + return AUDIO_ERROR_NONE; +} + + +/* + * BeOS driver public interface + */ +AUDIOWAVEDRIVER BeOSR3WaveDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudio, SetAudioCallback +}; + +AUDIODRIVER BeOSR3Driver = +{ + &BeOSR3WaveDriver, NULL +}; diff --git a/seal-hack/src/be4drv.c b/seal-hack/src/be4drv.c new file mode 100644 index 0000000..8fe07cc --- /dev/null +++ b/seal-hack/src/be4drv.c @@ -0,0 +1,185 @@ +/* + * $Id: bedrv.c 1.1 1998/10/24 18:24:26 chasan Exp $ + * + * Intel BeOS Release 4 audio driver. + * + * Copyright (C) 1998-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "BeOS/audio_driver.h" +#include "audio.h" +#include "drivers.h" + +#define BUFFERSIZE 200 /* 200 ms */ + +/* + * BeOS driver configuration structure + */ +static struct { + int nHandle; + char szDeviceName[MAXNAMLEN]; + LPBYTE lpBuffer; + int nBufferSize; + LPFNAUDIOWAVE lpfnAudioWave; + WORD wFormat; +} Audio; + + +/* + * BeOS driver API interface + */ +static UINT AIAPI GetAudioCaps(LPAUDIOCAPS lpCaps) +{ + static AUDIOCAPS Caps = + { + AUDIO_PRODUCT_BEOS, "BeOS Sound Driver", + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_1M16 | AUDIO_FORMAT_1S16 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_2M16 | AUDIO_FORMAT_2S16 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 | + AUDIO_FORMAT_4M16 | AUDIO_FORMAT_4S16 + }; + + memcpy(lpCaps, &Caps, sizeof(AUDIOCAPS)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI PingAudio(VOID) +{ + DIR *dir; + struct dirent *entry; + struct stat st; + + /* search an audio device */ + if ((dir = opendir("/dev/audio")) != 0) { + while ((entry = readdir(dir)) != 0) { + if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) { + strcat(strcpy(Audio.szDeviceName, "/dev/audio/"), entry->d_name); + if (stat(Audio.szDeviceName, &st) < 0 || S_ISDIR(st.st_mode)) + continue; + if (access(Audio.szDeviceName, W_OK) == 0) { + closedir(dir); + return AUDIO_ERROR_NONE; + } + } + } + closedir(dir); + } + return AUDIO_ERROR_NODEVICE; +} + +static UINT AIAPI OpenAudio(LPAUDIOINFO lpInfo) +{ + struct audio_format config; + + memset(&Audio, 0, sizeof(Audio)); + + /* search an old audio device for playback */ + if (PingAudio() != AUDIO_ERROR_NONE) + return AUDIO_ERROR_NODEVICE; + + /* try to open audio device for playback */ + if ((Audio.nHandle = open(Audio.szDeviceName, O_WRONLY)) < 0) + return AUDIO_ERROR_DEVICEBUSY; + + /* compute 200 ms latency buffer size */ + Audio.nBufferSize = lpInfo->nSampleRate; + if (lpInfo->wFormat & AUDIO_FORMAT_16BITS) + Audio.nBufferSize <<= 1; + if (lpInfo->wFormat & AUDIO_FORMAT_STEREO) + Audio.nBufferSize <<= 1; + Audio.nBufferSize /= (1000 / BUFFERSIZE); + Audio.nBufferSize += 15; + Audio.nBufferSize &= ~15; + + /* setup audio playback encoding format and sampling frequency */ + config.sample_rate = lpInfo->nSampleRate; + config.channels = (lpInfo->wFormat & AUDIO_FORMAT_STEREO ? 2 : 1); + config.format = (lpInfo->wFormat & AUDIO_FORMAT_16BITS ? 0x02 : 0x11); + config.big_endian = 0; + config.buf_header = 0; + config.play_buf_size = Audio.nBufferSize; + config.rec_buf_size = Audio.nBufferSize; + if (ioctl(Audio.nHandle, B_AUDIO_SET_AUDIO_FORMAT, &config) < 0) { + close(Audio.nHandle); + return AUDIO_ERROR_NODEVICE; + } + if (ioctl(Audio.nHandle, B_AUDIO_GET_AUDIO_FORMAT, &config) < 0) { + close(Audio.nHandle); + return AUDIO_ERROR_NODEVICE; + } + lpInfo->nSampleRate = config.sample_rate; + lpInfo->wFormat = AUDIO_FORMAT_8BITS | AUDIO_FORMAT_MONO; + if (config.format == 0x02) + lpInfo->wFormat |= AUDIO_FORMAT_16BITS; + if (config.channels == 2) + lpInfo->wFormat |= AUDIO_FORMAT_STEREO; + + /* allocate audio buffer area */ + if ((Audio.lpBuffer = (LPBYTE) malloc(Audio.nBufferSize)) == NULL) { + close(Audio.nHandle); + return AUDIO_ERROR_NOMEMORY; + } + + Audio.wFormat = lpInfo->wFormat; + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI CloseAudio(VOID) +{ + /* close DSP audio device */ + close(Audio.nHandle); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudio(UINT nFrames) +{ + /* compute frame size */ + if (Audio.wFormat & AUDIO_FORMAT_16BITS) nFrames <<= 1; + if (Audio.wFormat & AUDIO_FORMAT_STEREO) nFrames <<= 1; + if (nFrames <= 0 || nFrames > Audio.nBufferSize) + nFrames = Audio.nBufferSize; + + /* send PCM samples to the DSP audio device */ + if (Audio.lpfnAudioWave != NULL) { + Audio.lpfnAudioWave(Audio.lpBuffer, nFrames); + write(Audio.nHandle, Audio.lpBuffer, nFrames); + } + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + /* set up DSP audio device user's callback function */ + Audio.lpfnAudioWave = lpfnAudioWave; + return AUDIO_ERROR_NONE; +} + + +/* + * BeOS driver public interface + */ +AUDIOWAVEDRIVER BeOSWaveDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudio, SetAudioCallback +}; + +AUDIODRIVER BeOSDriver = +{ + &BeOSWaveDriver, NULL +}; diff --git a/seal-hack/src/bedrv.cpp b/seal-hack/src/bedrv.cpp new file mode 100644 index 0000000..7eb689c --- /dev/null +++ b/seal-hack/src/bedrv.cpp @@ -0,0 +1,174 @@ +/* + * $Id: bedrv.c 0.1 1998/12/19 18:24:26 chasan Exp $ + * + * Intel BeOS Release 4 audio driver using the New Media Kit. + * + * Copyright (C) 1998 Carlos Hasan. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include "audio.h" +#include "drivers.h" + +/* + * BeOS driver configuration structure + */ +static struct { + BSoundPlayer *Player; + LPFNAUDIOWAVE lpfnAudioWave; +} Audio; + + +/* + * BeOS driver API interface + */ +static UINT AIAPI GetAudioCaps(LPAUDIOCAPS lpCaps) +{ + static AUDIOCAPS Caps = + { + AUDIO_PRODUCT_BEOS, "BeOS Sound Player", + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_1M16 | AUDIO_FORMAT_1S16 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_2M16 | AUDIO_FORMAT_2S16 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 | + AUDIO_FORMAT_4M16 | AUDIO_FORMAT_4S16 + }; + + memcpy(lpCaps, &Caps, sizeof(AUDIOCAPS)); + return AUDIO_ERROR_NONE; +} + +static void PlayAudio(void *cookie, void *buffer, size_t size, + const media_raw_audio_format& fmt) +{ + static float hitable[256], lotable[256]; + static float scale = 0.0f; + + float *float_buffer = (float *) buffer; + short *short_buffer = (short *) buffer + (size >> 2); + size >>= 2; + + /* lazily build the integer to float translation table */ + if (scale == 0.0f) { + int i; + scale = 1.0f / 32768.0f; + for (i = -128; i < 128; i++) + hitable[i & 255] = scale * 256.0f * i; + for (i = 0; i < 255; i++) + lotable[i] = scale * i; + } + + /* streams of 44100 Hz, stereo, 32bit floats are supported */ + if (fmt.format != media_raw_audio_format::B_AUDIO_FLOAT || + fmt.channel_count != 2 || fmt.frame_rate != 44100 || + Audio.lpfnAudioWave == NULL) { + memset(buffer, 0, size); + } + else { + /* make 44100 Hz, stereo, 16-bit signed integer samples */ + Audio.lpfnAudioWave((LPBYTE) short_buffer, size << 1); + + /* convert to 32-bit float samples using lookup table */ + while (size >= 8) { + int *sample = (int *) short_buffer; + int s; + + /* TODO: channels will be swapped in big-endian machines */ + s = sample[0]; + float_buffer[0] = hitable[(s >> 8) & 255] + lotable[s & 255]; + float_buffer[1] = hitable[(s >> 24) & 255] + lotable[(s >> 16)&255]; + s = sample[1]; + float_buffer[2] = hitable[(s >> 8) & 255] + lotable[s & 255]; + float_buffer[3] = hitable[(s >> 24) & 255] + lotable[(s >> 16)&255]; + s = sample[2]; + float_buffer[4] = hitable[(s >> 8) & 255] + lotable[s & 255]; + float_buffer[5] = hitable[(s >> 24) & 255] + lotable[(s >> 16)&255]; + s = sample[3]; + float_buffer[6] = hitable[(s >> 8) & 255] + lotable[s & 255]; + float_buffer[7] = hitable[(s >> 24) & 255] + lotable[(s >> 16)&255]; + + short_buffer += 8; + float_buffer += 8; + size -= 8; + } + while (size-- > 0) { + short s = *short_buffer++; + *float_buffer++ = hitable[(s >> 8) & 255] + lotable[s & 255]; + } + } +} + +static UINT AIAPI PingAudio(VOID) +{ + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI OpenAudio(LPAUDIOINFO lpInfo) +{ + /* clean up local state structure */ + memset(&Audio, 0, sizeof(Audio)); + + /* create sound player */ + if ((Audio.Player = new BSoundPlayer("SEAL Player", PlayAudio)) == NULL) + return AUDIO_ERROR_NODEVICE; + + /* force default settings */ + lpInfo->nSampleRate = 44100; + lpInfo->wFormat = AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO; + + /* start sound player */ + Audio.Player->SetHasData(true); + Audio.Player->Start(); + + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI CloseAudio(VOID) +{ + if (Audio.Player != NULL) { + /* stop sound player */ + Audio.Player->Stop(); + + /* release sound player */ + delete Audio.Player; + Audio.Player = NULL; + } + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudio(UINT nFrames) +{ + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + /* set up audio device user's callback function */ + Audio.lpfnAudioWave = lpfnAudioWave; + return AUDIO_ERROR_NONE; +} + + +/* + * BeOS driver public interface + */ +AUDIOWAVEDRIVER BeOSWaveDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudio, SetAudioCallback +}; + +AUDIODRIVER BeOSDriver = +{ + &BeOSWaveDriver, NULL +}; diff --git a/seal-hack/src/drivers.h b/seal-hack/src/drivers.h new file mode 100644 index 0000000..b90b16d --- /dev/null +++ b/seal-hack/src/drivers.h @@ -0,0 +1,83 @@ +/* + * $Id: drivers.h 1.4 1996/08/05 18:51:19 chasan released $ + * + * Audio device drivers interface + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __DRIVERS_H +#define __DRIVERS_H + +#ifndef __AUDIO_H +#include "audio.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Audio device driver structures + */ + typedef struct { + UINT (AIAPI* GetAudioCaps)(LPAUDIOCAPS); + UINT (AIAPI* PingAudio)(VOID); + UINT (AIAPI* OpenAudio)(LPAUDIOINFO); + UINT (AIAPI* CloseAudio)(VOID); + UINT (AIAPI* UpdateAudio)(UINT); + UINT (AIAPI* SetAudioCallback)(LPFNAUDIOWAVE); + } AUDIOWAVEDRIVER, *LPAUDIOWAVEDRIVER; + + typedef struct { + UINT (AIAPI* GetAudioCaps)(LPAUDIOCAPS); + UINT (AIAPI* PingAudio)(VOID); + UINT (AIAPI* OpenAudio)(LPAUDIOINFO); + UINT (AIAPI* CloseAudio)(VOID); + UINT (AIAPI* UpdateAudio)(VOID); + UINT (AIAPI* OpenVoices)(UINT); + UINT (AIAPI* CloseVoices)(VOID); + UINT (AIAPI* SetAudioTimerProc)(LPFNAUDIOTIMER); + UINT (AIAPI* SetAudioTimerRate)(UINT); + UINT (AIAPI* SetAudioMixerValue)(UINT, UINT); /*NEW:1998/10/24*/ + LONG (AIAPI* GetAudioDataAvail)(VOID); + UINT (AIAPI* CreateAudioData)(LPAUDIOWAVE); + UINT (AIAPI* DestroyAudioData)(LPAUDIOWAVE); + UINT (AIAPI* WriteAudioData)(LPAUDIOWAVE, DWORD, UINT); + UINT (AIAPI* PrimeVoice)(UINT, LPAUDIOWAVE); + UINT (AIAPI* StartVoice)(UINT); + UINT (AIAPI* StopVoice)(UINT); + UINT (AIAPI* SetVoicePosition)(UINT, LONG); + UINT (AIAPI* SetVoiceFrequency)(UINT, LONG); + UINT (AIAPI* SetVoiceVolume)(UINT, UINT); + UINT (AIAPI* SetVoicePanning)(UINT, UINT); + UINT (AIAPI* GetVoicePosition)(UINT, LPLONG); + UINT (AIAPI* GetVoiceFrequency)(UINT, LPLONG); + UINT (AIAPI* GetVoiceVolume)(UINT, LPUINT); + UINT (AIAPI* GetVoicePanning)(UINT, LPUINT); + UINT (AIAPI* GetVoiceStatus)(UINT, LPBOOL); + } AUDIOSYNTHDRIVER, *LPAUDIOSYNTHDRIVER; + + typedef struct { + LPAUDIOWAVEDRIVER lpWaveDriver; + LPAUDIOSYNTHDRIVER lpSynthDriver; + } AUDIODRIVER, *LPAUDIODRIVER; + +/* + * External device-independant software drivers + */ + extern AUDIODRIVER NoneDriver; + extern AUDIOWAVEDRIVER NoneWaveDriver; + extern AUDIOSYNTHDRIVER NoneSynthDriver; + extern AUDIOSYNTHDRIVER EmuSynthDriver; + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/seal-hack/src/dsdrv.c b/seal-hack/src/dsdrv.c new file mode 100644 index 0000000..e035c36 --- /dev/null +++ b/seal-hack/src/dsdrv.c @@ -0,0 +1,313 @@ +/* + * $Id: dsdrv.c 1.5 1997/01/05 16:23:47 chasan Exp $ + * + * Microsoft DirectSound audio driver interface + * + * Copyright (c) 1996-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#define MSGBOX(text) + +#define INITGUID +#include +#include +#include +#include "audio.h" +#include "drivers.h" + +static struct { + LPDIRECTSOUND lpDirectSound; + LPDIRECTSOUNDBUFFER lpPrimaryBuffer; + LPDIRECTSOUNDBUFFER lpSoundBuffer; + LPFNAUDIOWAVE lpfnAudioWave; + DWORD dwBufferOffset; + DWORD dwBufferSize; + + WORD nSampleRate; + WORD wFormat; +} DS; + +static HRESULT _DirectSoundCreate(GUID FAR * lpGuid, + LPDIRECTSOUND *lplpDirectSound, IUnknown FAR * lpUnkOuter) +{ + HRESULT hresult; + + CoInitialize(NULL); + hresult = CoCreateInstance(&CLSID_DirectSound, lpUnkOuter, + CLSCTX_ALL, &IID_IDirectSound, lplpDirectSound); + if (!FAILED(hresult)) + hresult = IDirectSound_Initialize(*lplpDirectSound, NULL); + return hresult; +} + +static HRESULT _DirectSoundDestroy(LPDIRECTSOUND lpDirectSound) +{ + HRESULT hresult; + + hresult = IDirectSound_Release(lpDirectSound); + CoUninitialize(); + return hresult; +} + +static UINT AIAPI GetAudioCaps(LPAUDIOCAPS lpCaps) +{ + strncpy(lpCaps->szProductName, "DirectSound", + sizeof(lpCaps->szProductName)); + lpCaps->wProductId = AUDIO_PRODUCT_DSOUND; + lpCaps->dwFormats = + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_1M16 | AUDIO_FORMAT_1S16 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_2M16 | AUDIO_FORMAT_2S16 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 | + AUDIO_FORMAT_4M16 | AUDIO_FORMAT_4S16 ; + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI PingAudio(VOID) +{ + LPDIRECTSOUND lpDirectSound; + if (_DirectSoundCreate(NULL, &lpDirectSound, NULL) != DS_OK) + return AUDIO_ERROR_NODEVICE; + _DirectSoundDestroy(lpDirectSound); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI OpenAudio(LPAUDIOINFO lpInfo) +{ + DSBUFFERDESC dsbd; + DSBCAPS dsbc; + DSCAPS dsc; + WAVEFORMATEX wfx; + + memset(&DS, 0, sizeof(DS)); + + /* create the direct sound object */ + if (_DirectSoundCreate(NULL, &DS.lpDirectSound, NULL) != DS_OK) { + MSGBOX("Failed to create DirectSound COM object"); + return AUDIO_ERROR_NODEVICE; + } + + /* set direct sound cooperative level */ + if (DS.lpDirectSound->lpVtbl->SetCooperativeLevel( + DS.lpDirectSound, GetForegroundWindow(), DSSCL_PRIORITY) != DS_OK) { + MSGBOX("DirectSound SetCooperativeLevel failed"); + _DirectSoundDestroy(DS.lpDirectSound); + return AUDIO_ERROR_NODEVICE; + } + + /* get DirectSound capabilities */ + dsc.dwSize = sizeof(dsc); + if (DS.lpDirectSound->lpVtbl->GetCaps(DS.lpDirectSound, &dsc) != DS_OK) { + MSGBOX("Cannot get DirectSound capabilities"); + _DirectSoundDestroy(DS.lpDirectSound); + return AUDIO_ERROR_NODEVICE; + } + if (!(dsc.dwFlags & DSCAPS_PRIMARYSTEREO)) + lpInfo->wFormat &= ~AUDIO_FORMAT_STEREO; + if (!(dsc.dwFlags & DSCAPS_SECONDARY16BIT)) + lpInfo->wFormat &= ~AUDIO_FORMAT_16BITS; + + /* set up wave format structure */ + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = lpInfo->wFormat & AUDIO_FORMAT_STEREO ? 2 : 1; + wfx.wBitsPerSample = lpInfo->wFormat & AUDIO_FORMAT_16BITS ? 16 : 8; + wfx.nSamplesPerSec = lpInfo->nSampleRate; + wfx.nAvgBytesPerSec = lpInfo->nSampleRate; + wfx.nBlockAlign = 1; + wfx.cbSize = 0; + if (lpInfo->wFormat & AUDIO_FORMAT_STEREO) { + wfx.nAvgBytesPerSec <<= 1; + wfx.nBlockAlign <<= 1; + } + if (lpInfo->wFormat & AUDIO_FORMAT_16BITS) { + wfx.nAvgBytesPerSec <<= 1; + wfx.nBlockAlign <<= 1; + } + + /* create primary sound buffer */ + memset(&dsbd, 0, sizeof(dsbd)); + dsbd.dwSize = sizeof(dsbd); + dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; + dsbd.dwBufferBytes = 0; + dsbd.lpwfxFormat = NULL; + if (DS.lpDirectSound->lpVtbl->CreateSoundBuffer( + DS.lpDirectSound, &dsbd, &DS.lpPrimaryBuffer, NULL) != DS_OK) { + MSGBOX("Cannot create primary buffer"); + _DirectSoundDestroy(DS.lpDirectSound); + return AUDIO_ERROR_NODEVICE; + } + + /* set up primary buffer format */ + while (DS.lpPrimaryBuffer->lpVtbl->SetFormat(DS.lpPrimaryBuffer, &wfx) != DS_OK) { + if (lpInfo->nSampleRate <= 11025) { + MSGBOX("Can't change primary buffer format"); + DS.lpPrimaryBuffer->lpVtbl->Release(DS.lpPrimaryBuffer); + _DirectSoundDestroy(DS.lpDirectSound); + return AUDIO_ERROR_NODEVICE; + } + wfx.nSamplesPerSec >>= 1; + wfx.nAvgBytesPerSec >>= 1; + wfx.nBlockAlign >>= 1; + lpInfo->nSampleRate >>= 1; + } + + /* get primary buffer length */ + dsbc.dwSize = sizeof(dsbc); + if (DS.lpPrimaryBuffer->lpVtbl->GetCaps(DS.lpPrimaryBuffer, &dsbc) != DS_OK) { + MSGBOX("Can't get primary buffer capabilities"); + DS.lpPrimaryBuffer->lpVtbl->Release(DS.lpPrimaryBuffer); + _DirectSoundDestroy(DS.lpDirectSound); + return AUDIO_ERROR_NODEVICE; + } + + /* the secondary buffer size should be between 20 ms and 100 ms */ + if (dsbc.dwBufferBytes > (100L * wfx.nAvgBytesPerSec) / 1000) { + dsbc.dwBufferBytes = (100L * wfx.nAvgBytesPerSec) / 1000; + } + if (dsbc.dwBufferBytes < (20L * wfx.nAvgBytesPerSec) / 1000) { + dsbc.dwBufferBytes = (20L * wfx.nAvgBytesPerSec) / 1000; + } + + /* [1998/12/24] in emulation mode use at least 150 ms buffers */ + if (dsc.dwFlags & DSCAPS_EMULDRIVER) { + if (dsbc.dwBufferBytes < (150L * wfx.nAvgBytesPerSec) / 1000) + dsbc.dwBufferBytes = (150L * wfx.nAvgBytesPerSec) / 1000; + } + + dsbc.dwBufferBytes >>= 2; + dsbc.dwBufferBytes <<= 2; + + /* set up secondary buffer description */ + memset(&dsbd, 0, sizeof(dsbd)); + dsbd.dwSize = sizeof(dsbd); + dsbd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; + dsbd.dwBufferBytes = dsbc.dwBufferBytes; + dsbd.lpwfxFormat = &wfx; + + /* create secondary sound buffer */ + if (DS.lpDirectSound->lpVtbl->CreateSoundBuffer( + DS.lpDirectSound, &dsbd, &DS.lpSoundBuffer, NULL) != DS_OK) { + MSGBOX("Can't create secondary buffer"); + _DirectSoundDestroy(DS.lpDirectSound); + return AUDIO_ERROR_NODEVICE; + } + + /* set up buffer chunk variables */ + DS.dwBufferOffset = 0L; + DS.dwBufferSize = dsbd.dwBufferBytes; + + /* start playing the primary buffer */ + DS.lpPrimaryBuffer->lpVtbl->Play(DS.lpPrimaryBuffer, 0, 0, DSBPLAY_LOOPING); + + /* start playing the secondary buffer */ + DS.lpSoundBuffer->lpVtbl->Play(DS.lpSoundBuffer, 0, 0, DSBPLAY_LOOPING); + + /* save audio format settings */ + DS.nSampleRate = lpInfo->nSampleRate; + DS.wFormat = lpInfo->wFormat; + + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI CloseAudio(VOID) +{ + if (DS.lpDirectSound != NULL) { + /* release secondary sound buffer */ + if (DS.lpSoundBuffer != NULL) { + DS.lpSoundBuffer->lpVtbl->Stop(DS.lpSoundBuffer); + DS.lpSoundBuffer->lpVtbl->Release(DS.lpSoundBuffer); + } + + /* release primary sound buffer */ + if (DS.lpPrimaryBuffer != NULL) { + DS.lpPrimaryBuffer->lpVtbl->Stop(DS.lpPrimaryBuffer); + DS.lpPrimaryBuffer->lpVtbl->Release(DS.lpPrimaryBuffer); + } + + /* release direct sound */ + _DirectSoundDestroy(DS.lpDirectSound); + } + memset(&DS, 0, sizeof(DS)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudio(UINT nFrames) +{ + LPVOID lpPtr1, lpPtr2; + DWORD dwBytes1, dwBytes2; + DWORD dwPlayOffset, dwWriteOffset; + LONG dwBytes; + + if (DS.wFormat & AUDIO_FORMAT_STEREO) nFrames <<= 1; + if (DS.wFormat & AUDIO_FORMAT_16BITS) nFrames <<= 1; + if (nFrames <= 0 || nFrames >= DS.dwBufferSize) + nFrames = DS.dwBufferSize; + + if (DS.lpSoundBuffer->lpVtbl->GetCurrentPosition( + DS.lpSoundBuffer, &dwPlayOffset, &dwWriteOffset) == DS_OK) { + + if ((dwBytes = dwPlayOffset - DS.dwBufferOffset) < 0) + dwBytes += DS.dwBufferSize; + if (dwBytes > nFrames) + dwBytes = nFrames; + dwBytes &= ~3; + + if ((dwBytes -= 128) > 0) { + + if (DS.lpSoundBuffer->lpVtbl->Lock( + DS.lpSoundBuffer, DS.dwBufferOffset, dwBytes, + &lpPtr1, &dwBytes1, &lpPtr2, &dwBytes2, 0) == DS_OK) { + + if (DS.lpfnAudioWave != NULL) { + DS.lpfnAudioWave(lpPtr1, dwBytes1); + if (lpPtr2 != NULL) + DS.lpfnAudioWave(lpPtr2, dwBytes2); + } + else { + memset(lpPtr1, 0, dwBytes1); + if (lpPtr2 != NULL) + memset(lpPtr2, 0, dwBytes2); + } + + DS.lpSoundBuffer->lpVtbl->Unlock(DS.lpSoundBuffer, + lpPtr1, dwBytes1, lpPtr2, dwBytes2); + + if ((DS.dwBufferOffset += dwBytes) >= DS.dwBufferSize) + DS.dwBufferOffset -= DS.dwBufferSize; + } + else { + DS.lpSoundBuffer->lpVtbl->Restore(DS.lpSoundBuffer); + } + } + } + + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + DS.lpfnAudioWave = lpfnAudioWave; + return AUDIO_ERROR_NONE; +} + + + +/* + * DirectSound driver public interfaces + */ +AUDIOWAVEDRIVER DirectSoundWaveDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudio, SetAudioCallback +}; + +AUDIODRIVER DirectSoundDriver = +{ + &DirectSoundWaveDriver, NULL +}; diff --git a/seal-hack/src/dsdrv2.c b/seal-hack/src/dsdrv2.c new file mode 100644 index 0000000..644a255 --- /dev/null +++ b/seal-hack/src/dsdrv2.c @@ -0,0 +1,663 @@ +/* + * $Id: dsdrv2.c 0.4 1998/12/26 chasan Exp $ + * + * DirectSound accelerated audio driver (Experimental) + * + * Copyright (C) 1998-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include "audio.h" +#include "drivers.h" + +#if 0 +#define MSGBOX(text) MessageBox(NULL, text, "DirectSound", MB_OK) +#else +#define MSGBOX(text) +#endif + +static struct { + LPDIRECTSOUND lpDirectSound; + LPDIRECTSOUNDBUFFER lpPrimaryBuffer; + LPDIRECTSOUNDBUFFER aSoundBuffer[AUDIO_MAX_VOICES]; + LPFNAUDIOTIMER lpfnTimerHandler; + + LONG aLogVolumeTable[AUDIO_MAX_VOLUME+1]; + LONG aLogPanningTable[AUDIO_MAX_PANNING+1]; + + DWORD aFormatTable[AUDIO_MAX_VOICES]; + LONG aFrequencyTable[AUDIO_MAX_VOICES]; + UINT aVolumeTable[AUDIO_MAX_VOICES]; + UINT aPanningTable[AUDIO_MAX_VOICES]; + + LONG dwTimer; + LONG dwTimerAccum; + LONG dwTimerRate; +} DS; + + +static HRESULT _DirectSoundCreate(GUID FAR *lpGuid, + LPDIRECTSOUND *lplpDirectSound, IUnknown FAR *lpUnkOuter) +{ + HRESULT hresult; + + CoInitialize(NULL); + hresult = CoCreateInstance(&CLSID_DirectSound, lpUnkOuter, + CLSCTX_ALL, &IID_IDirectSound, lplpDirectSound); + if (!FAILED(hresult)) + hresult = IDirectSound_Initialize(*lplpDirectSound, NULL); + return hresult; +} + +static HRESULT _DirectSoundDestroy(LPDIRECTSOUND lpDirectSound) +{ + HRESULT hresult; + + hresult = IDirectSound_Release(lpDirectSound); + CoUninitialize(); + return hresult; +} + +static UINT AIAPI SetAudioMixerValue(UINT, UINT); + + +/* + * DirectSound audio driver API interface + */ +static UINT AIAPI GetAudioCaps(LPAUDIOCAPS lpCaps) +{ + static AUDIOCAPS Caps = + { + AUDIO_PRODUCT_NONE, "DirectSound (experimental)", + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_1M16 | AUDIO_FORMAT_1S16 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_2M16 | AUDIO_FORMAT_2S16 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 | + AUDIO_FORMAT_4M16 | AUDIO_FORMAT_4S16 + }; + + memcpy(lpCaps, &Caps, sizeof(AUDIOCAPS)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI PingAudio(VOID) +{ + LPDIRECTSOUND lpDirectSound; + if (_DirectSoundCreate(NULL, &lpDirectSound, NULL) != DS_OK) + return AUDIO_ERROR_NODEVICE; + _DirectSoundDestroy(lpDirectSound); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI OpenAudio(LPAUDIOINFO lpInfo) +{ + LPDIRECTSOUNDBUFFER lpPrimaryBuffer; + DSBUFFERDESC dsbd; + WAVEFORMATEX wfx; + DSCAPS dsc; + LONG nPanning; + + memset(&DS, 0, sizeof(DS)); + + if (lpInfo == NULL) + return AUDIO_ERROR_INVALPARAM; + + /* create direct sound object */ + if (_DirectSoundCreate(NULL, &DS.lpDirectSound, NULL) != DS_OK) + return AUDIO_ERROR_NODEVICE; + + /* set direct sound cooperative level */ + if (DS.lpDirectSound->lpVtbl->SetCooperativeLevel(DS.lpDirectSound, + GetForegroundWindow(), DSSCL_PRIORITY) != DS_OK) { + _DirectSoundDestroy(DS.lpDirectSound); + return AUDIO_ERROR_NODEVICE; + } + + /* get direct sound capabilities */ + dsc.dwSize = sizeof(dsc); + if (DS.lpDirectSound->lpVtbl->GetCaps(DS.lpDirectSound, &dsc) != DS_OK) { + _DirectSoundDestroy(DS.lpDirectSound); + return AUDIO_ERROR_NODEVICE; + } + + /* adjust the format settings */ + lpInfo->nSampleRate = 44100; + if (!(dsc.dwFlags & DSCAPS_PRIMARYSTEREO)) + lpInfo->wFormat &= ~AUDIO_FORMAT_STEREO; + if (!(dsc.dwFlags & DSCAPS_PRIMARY16BIT)) + lpInfo->wFormat &= ~AUDIO_FORMAT_16BITS; + + /* setup wave format structure */ + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = lpInfo->wFormat & AUDIO_FORMAT_STEREO ? 2 : 1; + wfx.wBitsPerSample = lpInfo->wFormat & AUDIO_FORMAT_16BITS ? 16 : 8; + wfx.nSamplesPerSec = lpInfo->nSampleRate; + wfx.nAvgBytesPerSec = lpInfo->nSampleRate; + wfx.nBlockAlign = 1; + wfx.cbSize = 0; + if (lpInfo->wFormat & AUDIO_FORMAT_STEREO) { + wfx.nAvgBytesPerSec <<= 1; + wfx.nBlockAlign <<= 1; + } + if (lpInfo->wFormat & AUDIO_FORMAT_16BITS) { + wfx.nAvgBytesPerSec <<= 1; + wfx.nBlockAlign <<= 1; + } + + /* create primary sound buffer */ + memset(&dsbd, 0, sizeof(dsbd)); + dsbd.dwSize = sizeof(dsbd); + dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; + dsbd.dwBufferBytes = 0; + dsbd.lpwfxFormat = NULL; + if (DS.lpDirectSound->lpVtbl->CreateSoundBuffer(DS.lpDirectSound, + &dsbd, &DS.lpPrimaryBuffer, NULL) != DS_OK) { + MSGBOX("Can't create primary buffer"); + _DirectSoundDestroy(DS.lpDirectSound); + return AUDIO_ERROR_NODEVICE; + } + + /* setup primary buffer format */ + while (DS.lpPrimaryBuffer->lpVtbl->SetFormat(DS.lpPrimaryBuffer, &wfx) != DS_OK) { + if (lpInfo->nSampleRate <= 11025) { + MSGBOX("Can't change primary buffer format"); + _DirectSoundDestroy(DS.lpDirectSound); + return AUDIO_ERROR_NODEVICE; + } + wfx.nSamplesPerSec >>= 1; + wfx.nAvgBytesPerSec >>= 1; + wfx.nBlockAlign >>= 1; + lpInfo->nSampleRate >>= 1; + } + + /* start playing primary buffer */ + DS.lpPrimaryBuffer->lpVtbl->Play(DS.lpPrimaryBuffer, 0, 0, DSBPLAY_LOOPING); + + /* set the timer settings */ + DS.dwTimer = GetTickCount(); + DS.dwTimerAccum = 0; + + /* set default master volume */ + SetAudioMixerValue(AUDIO_MIXER_MASTER_VOLUME, 96); + + /* create log panning table */ + for (nPanning = 0; nPanning <= AUDIO_MAX_PANNING; nPanning++) { + DS.aLogPanningTable[nPanning] = (2000 * (nPanning - 128)) >> 7; + } + + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI CloseAudio(VOID) +{ + UINT i; + + if (DS.lpDirectSound != NULL) { + /* stop and release primary buffer */ + if (DS.lpPrimaryBuffer != NULL) { + DS.lpPrimaryBuffer->lpVtbl->Stop(DS.lpPrimaryBuffer); + DS.lpPrimaryBuffer->lpVtbl->Release(DS.lpPrimaryBuffer); + } + + /* release duplicated sound buffers */ + for (i = 0; i < AUDIO_MAX_VOICES; i++) { + if (DS.aSoundBuffer[i] != NULL) { + DS.aSoundBuffer[i]->lpVtbl->Stop(DS.aSoundBuffer[i]); + DS.aSoundBuffer[i]->lpVtbl->Release(DS.aSoundBuffer[i]); + } + } + + /* release direct sound buffer */ + _DirectSoundDestroy(DS.lpDirectSound); + } + + /* clean up DirectSound driver variables */ + memset(&DS, 0, sizeof(DS)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudio(UINT nFrames) +{ + LONG dwTimer = GetTickCount(); + + /* call the virtual audio timer callback */ + if ((DS.dwTimerAccum += dwTimer - DS.dwTimer) >= DS.dwTimerRate) { + DS.dwTimerAccum -= DS.dwTimerRate; + if (DS.lpfnTimerHandler != NULL) + DS.lpfnTimerHandler(); + } + DS.dwTimer = dwTimer; + + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudioSynth(VOID) +{ + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioMixerValue(UINT nChannel, UINT nValue) +{ + LONG nVolume; + + if (nChannel != AUDIO_MIXER_MASTER_VOLUME && + nChannel != AUDIO_MIXER_TREBLE && + nChannel != AUDIO_MIXER_BASS && + nChannel != AUDIO_MIXER_CHORUS && + nChannel != AUDIO_MIXER_REVERB) + return AUDIO_ERROR_INVALPARAM; + + if (nChannel == AUDIO_MIXER_MASTER_VOLUME && nValue <= 256) { + DS.aLogVolumeTable[0] = -10000; + for (nVolume = 1; nVolume <= AUDIO_MAX_VOLUME; nVolume++) { + LONG value = (nValue * nVolume) >> 6; + DS.aLogVolumeTable[nVolume] = (LONG) (value == 0 ? -10000.0 : -2000.0 * log(value / 256.0) / log(1.0/256.0)); + } + } + + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI OpenVoices(UINT nVoices) +{ + if (nVoices <= AUDIO_MAX_VOICES) { + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; +} + +static UINT AIAPI CloseVoices(VOID) +{ + UINT i; + + for (i = 0; i < AUDIO_MAX_VOICES; i++) { + /* stop and release duplicated sound buffers */ + if (DS.aSoundBuffer[i] != NULL) { + DS.aSoundBuffer[i]->lpVtbl->Stop(DS.aSoundBuffer[i]); + DS.aSoundBuffer[i]->lpVtbl->Release(DS.aSoundBuffer[i]); + } + } + + /* clean up duplicated sound buffer array */ + memset(DS.aSoundBuffer, 0, sizeof(DS.aSoundBuffer)); + + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + if (lpfnAudioWave != NULL) { + } + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioTimerProc(LPFNAUDIOTIMER lpfnAudioTimer) +{ + if (lpfnAudioTimer != NULL) { + /* start up the timer settings */ + if (DS.lpfnTimerHandler == NULL) { + DS.dwTimer = GetTickCount(); + DS.dwTimerAccum = 0; + } + DS.lpfnTimerHandler = lpfnAudioTimer; + } + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioTimerRate(UINT nBPM) +{ + if (nBPM >= 0x20 && nBPM <= 0xFF) { + /* set timer rate in milliseconds */ + DS.dwTimerRate = (5 * 1000L) / (2 * nBPM); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; +} + +static LONG AIAPI GetAudioDataAvail(VOID) +{ + return 0L; +} + +static UINT AIAPI CreateAudioData(LPAUDIOWAVE lpWave) +{ + LPDIRECTSOUNDBUFFER lpSoundBuffer; + DSBUFFERDESC dsbd; + DSBCAPS dsbc; + WAVEFORMATEX wfx; + + if (lpWave != NULL) { + lpWave->dwHandle = 0; + + /* setup waveform format */ + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.nChannels = 1; + wfx.wBitsPerSample = lpWave->wFormat & AUDIO_FORMAT_16BITS ? 16 : 8; + wfx.nSamplesPerSec = lpWave->nSampleRate; + wfx.nAvgBytesPerSec = lpWave->nSampleRate; + wfx.nBlockAlign = 1; + wfx.cbSize = 0; + if (lpWave->wFormat & AUDIO_FORMAT_16BITS) { + wfx.nAvgBytesPerSec <<= 1; + wfx.nBlockAlign <<= 1; + } + + /* setup sound buffer description */ + dsbd.dwSize = sizeof(dsbd); + dsbd.dwFlags = DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | + DSBCAPS_CTRLFREQUENCY | DSBCAPS_STICKYFOCUS | + DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCSOFTWARE; + dsbd.dwBufferBytes = lpWave->dwLength; + dsbd.dwReserved = 0; + dsbd.lpwfxFormat = &wfx; + + /* create sound buffer object */ + if (DS.lpDirectSound->lpVtbl->CreateSoundBuffer(DS.lpDirectSound, + &dsbd, &lpSoundBuffer, NULL) != DS_OK) { + MSGBOX("Can't create DirectSoundBuffer object"); + return AUDIO_ERROR_NOMEMORY; + } + + lpWave->dwHandle = (DWORD) lpSoundBuffer; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; +} + +static UINT AIAPI DestroyAudioData(LPAUDIOWAVE lpWave) +{ + LPDIRECTSOUNDBUFFER lpSoundBuffer; + + if (lpWave != NULL && lpWave->dwHandle != 0) { + lpSoundBuffer = (LPDIRECTSOUNDBUFFER) lpWave->dwHandle; + lpSoundBuffer->lpVtbl->Stop(lpSoundBuffer); + lpSoundBuffer->lpVtbl->Release(lpSoundBuffer); + lpWave->dwHandle = 0; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; +} + +static UINT AIAPI WriteAudioData(LPAUDIOWAVE lpWave, DWORD dwOffset, UINT nCount) +{ + LPDIRECTSOUNDBUFFER lpSoundBuffer; + LPVOID lpPtr1, lpPtr2; + DWORD dwBytes1, dwBytes2; + UINT i; + + if (lpWave != NULL && lpWave->dwHandle != 0 && lpWave->lpData != NULL) { + if (dwOffset + nCount <= lpWave->dwLength) { + lpSoundBuffer = (LPDIRECTSOUNDBUFFER) lpWave->dwHandle; + + /* lock sound buffer in memory */ + if (lpSoundBuffer->lpVtbl->Lock(lpSoundBuffer, dwOffset, nCount, + &lpPtr1, &dwBytes1, &lpPtr2, &dwBytes2, 0) == DS_OK) { + + /* copy samples to the sound buffer (convert to unsigned) */ + if (lpWave->wFormat & AUDIO_FORMAT_16BITS) { + memcpy(lpPtr1, lpWave->lpData + dwOffset, dwBytes1); + } + else { + for (i = 0; i < dwBytes1; i++) + ((LPBYTE)lpPtr1)[i] = lpWave->lpData[dwOffset++] ^ 0x80; + } + + /* unlock the sound buffer from memory */ + lpSoundBuffer->lpVtbl->Unlock(lpSoundBuffer, lpPtr1, + dwBytes1, lpPtr2, dwBytes2); + + return AUDIO_ERROR_NONE; + } + else { + MSGBOX("Can't lock DirectSoundBuffer memory"); + lpSoundBuffer->lpVtbl->Restore(lpSoundBuffer); + } + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI PrimeVoice(UINT nVoice, LPAUDIOWAVE lpWave) +{ + LPDIRECTSOUNDBUFFER lpSoundBuffer; + + if (nVoice < AUDIO_MAX_VOICES && lpWave != NULL) { + lpSoundBuffer = (LPDIRECTSOUNDBUFFER) lpWave->dwHandle; + + /* release the sound buffer for this voice */ + if (DS.aSoundBuffer[nVoice] != NULL) { + DS.aSoundBuffer[nVoice]->lpVtbl->Stop(DS.aSoundBuffer[nVoice]); + DS.aSoundBuffer[nVoice]->lpVtbl->Release(DS.aSoundBuffer[nVoice]); + DS.aSoundBuffer[nVoice] = NULL; + } + + /* create a duplicate sound buffer */ + if (DS.lpDirectSound->lpVtbl->DuplicateSoundBuffer(DS.lpDirectSound, + lpSoundBuffer, &DS.aSoundBuffer[nVoice]) != DS_OK) { + MSGBOX("Can't duplicate DirectSoundBuffer object"); + return AUDIO_ERROR_NOMEMORY; + } + + /* setup frequency, volume and panning */ + DS.aSoundBuffer[nVoice]->lpVtbl->SetCurrentPosition(DS.aSoundBuffer[nVoice], 0); + DS.aSoundBuffer[nVoice]->lpVtbl->SetFrequency(DS.aSoundBuffer[nVoice], + DS.aFrequencyTable[nVoice]); + DS.aSoundBuffer[nVoice]->lpVtbl->SetVolume(DS.aSoundBuffer[nVoice], + DS.aLogVolumeTable[DS.aVolumeTable[nVoice]]); + DS.aSoundBuffer[nVoice]->lpVtbl->SetPan(DS.aSoundBuffer[nVoice], + DS.aLogPanningTable[DS.aPanningTable[nVoice]]); + + /* save format of the sound buffer */ + DS.aFormatTable[nVoice] = lpWave->wFormat; + + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI StartVoice(UINT nVoice) +{ + DWORD dwFlags; + + if (nVoice < AUDIO_MAX_VOICES) { + // FIXME: handle looping samples! + if (DS.aSoundBuffer[nVoice] != NULL) { + dwFlags = (DS.aFormatTable[nVoice] & AUDIO_FORMAT_LOOP ? DSBPLAY_LOOPING : 0); + if (DS.aSoundBuffer[nVoice]->lpVtbl->Play(DS.aSoundBuffer[nVoice], + 0, 0, dwFlags) != DS_OK) { + MSGBOX("Can't play DirectSoundBuffer object"); + return AUDIO_ERROR_INVALHANDLE; + } + } + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI StopVoice(UINT nVoice) +{ + if (nVoice < AUDIO_MAX_VOICES) { + if (DS.aSoundBuffer[nVoice] != NULL) { + if (DS.aSoundBuffer[nVoice]->lpVtbl->Stop(DS.aSoundBuffer[nVoice]) != DS_OK) { + MSGBOX("Can't stop DirectSoundBuffer object"); + return AUDIO_ERROR_INVALHANDLE; + } + } + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI SetVoicePosition(UINT nVoice, LONG dwPosition) +{ + if (nVoice < AUDIO_MAX_VOICES) { + if (dwPosition >= AUDIO_MIN_POSITION && + dwPosition <= AUDIO_MAX_POSITION) { + // FIXME: adjust position for 16-bit samples + if (DS.aSoundBuffer[nVoice] != NULL) { + DS.aSoundBuffer[nVoice]->lpVtbl->SetCurrentPosition(DS.aSoundBuffer[nVoice], dwPosition); + } + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI SetVoiceFrequency(UINT nVoice, LONG dwFrequency) +{ + if (nVoice < AUDIO_MAX_VOICES) { + if (dwFrequency >= AUDIO_MIN_FREQUENCY && + dwFrequency <= AUDIO_MAX_FREQUENCY) { + DS.aFrequencyTable[nVoice] = dwFrequency; + if (DS.aSoundBuffer[nVoice] != NULL) { + if (DS.aSoundBuffer[nVoice]->lpVtbl->SetFrequency(DS.aSoundBuffer[nVoice], dwFrequency) != DS_OK) + MSGBOX("Can't change DirectSoundBuffer frequency"); + } + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI SetVoiceVolume(UINT nVoice, UINT nVolume) +{ + if (nVoice < AUDIO_MAX_VOICES) { + if (nVolume < AUDIO_MAX_VOLUME) { + DS.aVolumeTable[nVoice] = nVolume; + if (DS.aSoundBuffer[nVoice] != NULL) { + if (DS.aSoundBuffer[nVoice]->lpVtbl->SetVolume(DS.aSoundBuffer[nVoice], DS.aLogVolumeTable[nVolume]) != DS_OK) + MSGBOX("Can't change DirectSoundBuffer volume"); + } + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI SetVoicePanning(UINT nVoice, UINT nPanning) +{ + if (nVoice < AUDIO_MAX_VOICES) { + if (nPanning < AUDIO_MAX_PANNING) { + DS.aPanningTable[nVoice] = nPanning; + if (DS.aSoundBuffer[nVoice] != NULL) { + if (DS.aSoundBuffer[nVoice]->lpVtbl->SetPan(DS.aSoundBuffer[nVoice], DS.aLogPanningTable[nPanning]) != DS_OK) + MSGBOX("Can't change DirectSoundBuffer panning"); + } + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoicePosition(UINT nVoice, LPLONG lpdwPosition) +{ + DWORD dwWritePosition; + + if (nVoice < AUDIO_MAX_VOICES) { + if (lpdwPosition != NULL) { + *lpdwPosition = 0L; + if (DS.aSoundBuffer[nVoice] != NULL) { + if (DS.aSoundBuffer[nVoice]->lpVtbl->GetCurrentPosition( + DS.aSoundBuffer[nVoice], lpdwPosition, &dwWritePosition) != DS_OK) + *lpdwPosition = 0L; + } + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoiceFrequency(UINT nVoice, LPLONG lpdwFrequency) +{ + if (nVoice < AUDIO_MAX_VOICES) { + if (lpdwFrequency != NULL) { + *lpdwFrequency = DS.aFrequencyTable[nVoice]; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoiceVolume(UINT nVoice, LPUINT lpnVolume) +{ + if (nVoice < AUDIO_MAX_VOICES) { + if (lpnVolume != NULL) { + *lpnVolume = DS.aVolumeTable[nVoice]; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoicePanning(UINT nVoice, LPUINT lpnPanning) +{ + if (nVoice < AUDIO_MAX_VOICES) { + if (lpnPanning != NULL) { + *lpnPanning = DS.aPanningTable[nVoice]; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoiceStatus(UINT nVoice, LPBOOL lpnStatus) +{ + if (nVoice < AUDIO_MAX_VOICES) { + if (lpnStatus != NULL) { + *lpnStatus = 1; + if (DS.aSoundBuffer[nVoice] != NULL) { + if (DS.aSoundBuffer[nVoice]->lpVtbl->GetStatus(DS.aSoundBuffer[nVoice], lpnStatus) != DS_OK) + MSGBOX("Can't getDirectSoundBuffer status");; + *lpnStatus = (*lpnStatus & DSBSTATUS_PLAYING ? 0 : 1); + } + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + + +/* + * DirectSound audio driver public interface + */ +static AUDIOWAVEDRIVER DirectSoundWaveDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudio, SetAudioCallback +}; + +static AUDIOSYNTHDRIVER DirectSoundSynthDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudioSynth, OpenVoices, CloseVoices, + SetAudioTimerProc, SetAudioTimerRate, SetAudioMixerValue, + GetAudioDataAvail, CreateAudioData, DestroyAudioData, + WriteAudioData, PrimeVoice, StartVoice, StopVoice, + SetVoicePosition, SetVoiceFrequency, SetVoiceVolume, + SetVoicePanning, GetVoicePosition, GetVoiceFrequency, + GetVoiceVolume, GetVoicePanning, GetVoiceStatus +}; + +AUDIODRIVER DirectSoundAccelDriver = +{ + &DirectSoundWaveDriver, &DirectSoundSynthDriver +}; diff --git a/seal-hack/src/gusdrv.c b/seal-hack/src/gusdrv.c new file mode 100644 index 0000000..ed59198 --- /dev/null +++ b/seal-hack/src/gusdrv.c @@ -0,0 +1,1818 @@ +/* + * $Id: gusdrv.c 1.11 1996/09/22 20:17:51 chasan released $ + * + * Advanced Gravis UltraSound (GF1 and InterWave) audio driver. + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#define INTERWAVE + +#include +#include "audio.h" +#include "drivers.h" +#include "msdos.h" + +/* + * Gravis Ultrasound register offsets + */ +/* MIDI-101 interface */ +#define GUS_MIDI_CTRL 0x100 /* (3X0) MIDI control register */ +#define GUS_MIDI_STAT 0x100 /* (3X0) MIDI status register */ +#define GUS_MIDI_DATA 0x101 /* (3X1) MIDI data register */ + +/* Joystick interface */ +#define GUS_JOYSTICK_TIMER 0x001 /* (2X1) joystick trigger timer */ +#define GUS_JOYSTICK_DATA 0x001 /* (2X1) joystick read data */ + +/* GF1 synthesizer */ +#define GUS_GF1_PAGE 0x102 /* (3X2) GF1 page register */ +#define GUS_GF1_INDEX 0x103 /* (3X3) GF1 register select */ +#define GUS_GF1_DATA_LOW 0x104 /* (3X4) GF1 data low byte */ +#define GUS_GF1_DATA_HIGH 0x105 /* (3X5) GF1 data high byte */ +#define GUS_GF1_IRQ_STAT 0x006 /* (2X6) GF1 IRQ status */ +#define GUS_GF1_TIMER_CTRL 0x008 /* (2X8) GF1 timer control */ +#define GUS_GF1_TIMER_DATA 0x009 /* (2X9) GF1 timer data */ +#define GUS_GF1_DRAM_DATA 0x107 /* (3X7) GF1 DRAM I/O register */ + +/* Board only */ +#define GUS_BOARD_MIX_CTRL 0x000 /* (2X0) mix control register */ +#define GUS_BOARD_IRQ_CTRL 0x00B /* (2XB) IRQ control register */ +#define GUS_BOARD_DMA_CTRL 0x00B /* (2XB) DMA control register */ +#define GUS_BOARD_REG_CTRL 0x00F /* (2XF) register controls (Rev 3.4) */ +#define GUS_BOARD_IRQ_CLEAR 0x00B /* (2XB) IRQ clear register (Rev 3.4) */ +#define GUS_BOARD_JUMPERS 0x00B /* (2XB) jumper register (Rev 3.4) */ +#define GUS_BOARD_VERSION 0x506 /* (7X6) board version (Rev 3.7) */ + +/* ICS2101 mixer interface (Rev 3.7) */ +#define GUS_ICS_MIXER_ADDR 0x506 /* (7X6) mixer control register */ +#define GUS_ICS_MIXER_DATA 0x106 /* (3X6) mixer data register */ + +/* CS4231 interface (UltraMax) */ +#define GUS_CODEC_BASE0 0x530 /* (530) Daughter Codec address */ +#define GUS_CODEC_BASE1 0x604 /* (604) Daughter Codec address */ +#define GUS_CODEC_BASE2 0xE80 /* (E80) Daughter Codec address */ +#define GUS_CODEC_BASE3 0xF40 /* (F40) Daughter Codec address */ +#define GUS_CODEC_BASE4 0x10C /* (3XC) UltraMax Codec address */ +#define GUS_CODEC_CTRL 0x106 /* (3X6) UltraMax Codec control */ + + +/* + * MIDI (6850 UART) control register bit fields (3X0) + */ +#define MIDI_RESET 0x03 /* MIDI master reset */ +#define MIDI_ENABLE_TX_IRQ 0x20 /* MIDI transmit IRQ enabled */ +#define MIDI_ENABLE_RX_IRQ 0x80 /* MIDI receive IRQ enabled */ + +/* + * MIDI (6850 UART) status register bit fields (3X0) + */ +#define MIDI_RECV_FULL 0x01 /* recv register full */ +#define MIDI_XMIT_EMPTY 0x02 /* xmit register empty */ +#define MIDI_FRAME_ERROR 0x10 /* framing error */ +#define MIDI_OVERRUN_ERROR 0x20 /* overrun error */ +#define MIDI_IRQ_PENDING 0x80 /* interrupt pending */ + + +/* + * GF1 global indirect register indexes (3X3) + */ +#define GF1_DRAM_DMA_CTRL 0x41 /* DRAM DMA control register */ +#define GF1_DMA_ADDR 0x42 /* DMA start address register */ +#define GF1_DRAM_ADDR_LOW 0x43 /* DRAM I/O low address register */ +#define GF1_DRAM_ADDR_HIGH 0x44 /* DRAM I/O high address register */ +#define GF1_TIMER_CTRL 0x45 /* timer control register */ +#define GF1_TIMER1_COUNT 0x46 /* timer 1 count register */ +#define GF1_TIMER2_COUNT 0x47 /* timer 2 count register */ +#define GF1_ADC_DMA_RATE 0x48 /* sampling frequency register */ +#define GF1_ADC_DMA_CTRL 0x49 /* sampling control register */ +#define GF1_JOYSTICK_DAC 0x4B /* joystick trim DAC register */ +#define GF1_MASTER_RESET 0x4C /* master reset register */ + +/* + * GF1 DRAM DMA control register bit fields (41) + */ +#define DRAM_DMA_ENABLE 0x01 /* enable DMA transfer */ +#define DRAM_DMA_DISABLE 0x00 /* disable DMA transfer */ +#define DRAM_DMA_READ 0x02 /* read DMA direction */ +#define DRAM_DMA_WRITE 0x00 /* write DMA direction */ +#define DRAM_DMA_WIDTH_16 0x04 /* 8/16 bit DMA channel */ +#define DRAM_DMA_RATE0 0x00 /* DMA rate divisor (1) */ +#define DRAM_DMA_RATE1 0x08 /* DMA rate divisor (2) */ +#define DRAM_DMA_RATE2 0x10 /* DMA rate divisor (3) */ +#define DRAM_DMA_RATE3 0x18 /* DMA rate divisor (4) */ +#define DRAM_DMA_IRQ_ENABLE 0x20 /* DMA IRQ enable */ +#define DRAM_DMA_IRQ_PENDING 0x40 /* DMA IRQ pending */ +#define DRAM_DMA_DATA_16 0x40 /* 8/16 bit data */ +#define DRAM_DMA_TWOS_COMP 0x80 /* invert MSB data */ + +/* + * GF1 timer control register bit fields (45) + */ +#define TIMER1_IRQ_ENABLE 0x04 /* enable timer 1 interrupts */ +#define TIMER2_IRQ_ENABLE 0x08 /* enable timer 2 interrupts */ + +/* + * GF1 ADC DMA sampling control register bit fields (49) + */ +#define ADC_DMA_ENABLE 0x01 /* enable sampling */ +#define ADC_DMA_DISABLE 0x00 /* disable sampling */ +#define ADC_DMA_STEREO_MODE 0x02 /* select stereo mode */ +#define ADC_DMA_MONO_MODE 0x00 /* select mono mode */ +#define ADC_DMA_WIDTH_16 0x04 /* 8/16 bit DMA channel */ +#define ADC_DMA_IRQ_ENABLE 0x20 /* DMA IRQ enable */ +#define ADC_DMA_IRQ_PENDING 0x40 /* DMA IRQ pending */ +#define ADC_DMA_TWOS_COMP 0x80 /* invert MSB data */ + +/* + * GF1 master reset register bit fields (4C) + */ +#define MASTER_RESET 0x01 /* GF1 master reset register */ +#define MASTER_ENABLE_DAC 0x02 /* master DAC output enable */ +#define MASTER_ENABLE_IRQ 0x04 /* GF1 master IRQ enable */ + + +/* + * GF1 voice indirect register indexes (3X3) + */ +#define GF1_SET_VOICE_CTRL 0x00 /* voice control register */ +#define GF1_SET_FREQ_CTRL 0x01 /* frequency control register */ +#define GF1_SET_START_HIGH 0x02 /* high start address register */ +#define GF1_SET_START_LOW 0x03 /* low start address register */ +#define GF1_SET_END_HIGH 0x04 /* high end address register */ +#define GF1_SET_END_LOW 0x05 /* low end address register */ +#define GF1_SET_VOLUME_RATE 0x06 /* volume ramp rate register */ +#define GF1_SET_VOLUME_START 0x07 /* volume ramp start register */ +#define GF1_SET_VOLUME_END 0x08 /* volume ramp end register */ +#define GF1_SET_VOLUME 0x09 /* current volume register */ +#define GF1_SET_ACCUM_HIGH 0x0A /* high accumulator register */ +#define GF1_SET_ACCUM_LOW 0x0B /* low accumulator register */ +#define GF1_SET_PANNING 0x0C /* pan position register */ +#define GF1_SET_VOLUME_CTRL 0x0D /* volume ramp control register */ +#define GF1_SET_NUMVOICES 0x0E /* active voices register */ + +#define GF1_GET_VOICE_CTRL 0x80 /* voice control register */ +#define GF1_GET_FREQ_CTRL 0x81 /* frequency control register */ +#define GF1_GET_START_HIGH 0x82 /* high start address register */ +#define GF1_GET_START_LOW 0x83 /* low start address register */ +#define GF1_GET_END_HIGH 0x84 /* high end address register */ +#define GF1_GET_END_LOW 0x85 /* low end address register */ +#define GF1_GET_VOLUME_RATE 0x86 /* volume ramp rate register */ +#define GF1_GET_VOLUME_START 0x87 /* volume ramp start register */ +#define GF1_GET_VOLUME_END 0x88 /* volume ramp end register */ +#define GF1_GET_VOLUME 0x89 /* current volume register */ +#define GF1_GET_ACCUM_HIGH 0x8A /* high accumulator register */ +#define GF1_GET_ACCUM_LOW 0x8B /* low accumulator register */ +#define GF1_GET_PANNING 0x8C /* pan position register */ +#define GF1_GET_VOLUME_CTRL 0x8D /* volume ramp control register */ +#define GF1_GET_NUMVOICES 0x8E /* active voices register */ +#define GF1_GET_IRQ_STAT 0x8F /* IRQ source register */ + +#ifdef INTERWAVE +/* + * Interwave global indirect register indexes (3X3) + */ +#define IW_LDSAHI 0x50 /* LMC DMA start addr high register */ +#define IW_LMCFI 0x52 /* local memory config register */ + +/* + * InterWave voice indirect register indexes (3X3) + */ +#define IW_SROI_WR 0x0C /* synth right offset register */ +#define IW_SROI_RD 0x8C +#define IW_SLOI_WR 0x13 /* synth left offset register */ +#define IW_SLOI_RD 0x93 +#define IW_SUAI_WR 0x10 /* synth upper address register */ +#define IW_SUAI_RD 0x90 +#define IW_SMSI_WR 0x15 /* synth mode select register */ +#define IW_SMSI_RD 0x95 +#define IW_SGMI_WR 0x19 /* synth global mode register */ +#define IW_SGMI_RD 0x99 + +/* + * InterWave synth mode select register bit fields (15,95) + */ +#define IW_SMSI_VOICE_DISABLE 0x02 /* de-activate enhanced voice */ +#define IW_SMSI_VOICE_OFFSET 0x20 /* enable smooth voice panning */ + +/* + * InterWave synth global mode register bit fields (19,99) + */ +#define IW_SGMI_ENHMODE 0x01 /* enable enhanced mode */ +#define IW_SGMI_ENABLE_LFOS 0x02 /* enable LFOs */ + +#endif + +/* + * GF1 voice control register bit fields (00,80) + */ +#define VOICE_NORMAL 0x00 /* default voice bits */ +#define VOICE_STOPPED 0x01 /* voice stopped */ +#define VOICE_STOP 0x02 /* stop voice */ +#define VOICE_DATA_16 0x04 /* 8/16 bit wave data */ +#define VOICE_LOOP 0x08 /* loop enable */ +#define VOICE_BIDILOOP 0x10 /* bidi-loop enable */ +#define VOICE_ENABLE_IRQ 0x20 /* wavetable IRQ enable */ +#define VOICE_DIRECT 0x40 /* playing direction */ +#define VOICE_IRQ_PENDING 0x80 /* wavetable IRQ pending */ + +/* + * GF1 voice volume control register bit fields (0D,8D) + */ +#define VOLUME_STOPPED 0x01 /* volume ramp stopped */ +#define VOLUME_STOP 0x02 /* stop volume ramp */ +#define VOLUME_ROLLOVER 0x04 /* rollover condition */ +#define VOLUME_LOOP 0x08 /* loop enable */ +#define VOLUME_BIDILOOP 0x10 /* bidi-loop enable */ +#define VOLUME_ENABLE_IRQ 0x20 /* volume ramp IRQ enable */ +#define VOLUME_DIRECT 0x40 /* volume ramp direction */ +#define VOLUME_IRQ_PENDING 0x80 /* volume ramp IRQ pending */ + +/* + * GF1 global interrupt source register bit fields (8F) + */ +#define STATUS_VOICE 0x1F /* interrupting voice # mask */ +#define STATUS_VOLUME_IRQ 0x40 /* volume ramp IRQ pending */ +#define STATUS_WAVETABLE_IRQ 0x80 /* wavetable IRQ pending */ + + +/* + * GF1 interrupt status register bit fields (2X6) + */ +#define IRQ_STAT_MIDI_TX 0x01 /* MIDI transmit IRQ */ +#define IRQ_STAT_MIDI_RX 0x02 /* MIDI receive IRQ */ +#define IRQ_STAT_TIMER1 0x04 /* timer 1 IRQ */ +#define IRQ_STAT_TIMER2 0x08 /* timer 2 IRQ */ +#define IRQ_STAT_WAVETABLE 0x20 /* wavetable IRQ */ +#define IRQ_STAT_VOLUME 0x40 /* volume ramp IRQ */ +#define IRQ_STAT_DMA_TC 0x80 /* DRAM or ADC DMA IRQ */ + +/* + * GF1 timer control register bit fields (2X8) + */ +#define TIMER_CTRL_SELECT 0x04 /* select timer stuff */ +#define TIMER2_CTRL_EXPIRED 0x20 /* timer 2 has expired */ +#define TIMER1_CTRL_EXPIRED 0x40 /* timer 1 has expired */ + +/* + * GF1 timer data register bit fields (2X9) + */ +#define TIMER1_START_UP 0x01 /* timer 1 start */ +#define TIMER2_START_UP 0x02 /* timer 2 start */ +#define TIMER2_MASK_OFF 0x20 /* mask off timer 2 */ +#define TIMER1_MASK_OFF 0x40 /* mask off timer 1 */ +#define TIMER1_2_RESET 0x80 /* clear timer IRQ */ + +/* + * GF1 board mix control register bit fields (2X0) + */ +#define MIXER_DISABLE_LINE_IN 0x01 /* disable line input */ +#define MIXER_DISABLE_LINE_OUT 0x02 /* disable line output */ +#define MIXER_ENABLE_MIC_IN 0x04 /* enable mic input */ +#define MIXER_ENABLE_LATCHES 0x08 /* enable IRQ/DMA latches */ +#define MIXER_COMBINE_IRQS 0x10 /* combine GF1/MIDI IRQ channels */ +#define MIXER_ENABLE_MIDI_LOOP 0x20 /* enable MIDI loopback TxD to RxD */ +#define MIXER_LATCH_DMA 0x00 /* select DMA control register */ +#define MIXER_LATCH_IRQ 0x40 /* select IRQ control register */ + +/* + * ICS2101 mixer indirect register indexes (7X6) + */ +#define ICS_MIXER_CHANNEL 0x38 /* channel register bit mask */ +#define ICS_MIXER_CTRL_LEFT 0x00 /* select left control register */ +#define ICS_MIXER_CTRL_RIGHT 0x01 /* select right control register */ +#define ICS_MIXER_ATTN_LEFT 0x02 /* select left attenuation register */ +#define ICS_MIXER_ATTN_RIGHT 0x03 /* select right attenuation register */ +#define ICS_MIXER_PANNING 0x04 /* select panning register */ +#define ICS_MIXER_MIC 0x00 /* select mic input channel */ +#define ICS_MIXER_LINE 0x08 /* select line input channel */ +#define ICS_MIXER_CD 0x10 /* select CD input channel */ +#define ICS_MIXER_GF1 0x18 /* select GF1 output channel */ +#define ICS_MIXER_MASTER 0x28 /* select master output channel */ + +/* + * UltraMax (CS4231) control register bit fields (3X6) + */ +#define CODEC_ADDR_DECODE 0x0F /* CS4231 codec address decode bits */ +#define CODEC_CAPTURE_DMA 0x10 /* 8/16 bit capture DMA channel */ +#define CODEC_PLAYBACK_DMA 0x20 /* 8/16 bit playback DMA channel */ +#define CODEC_ENABLED 0x40 /* disable/enable CS4231 codec */ + +/* + * GF1 driver DRAM memory manager defines + */ +#define DRAM_HEADER_SIZE 32 /* DRAM memory header size */ +#define DRAM_BANK_SIZE 0x40000 /* DRAM memory bank size */ +#define DMA_BUFFER_SIZE 2048 /* DRAM DMA buffer size */ +#define DMA_TIMEOUT 1024 /* DMA-TC busy-waiting timeout */ + +/* + * GF1 IRQ and DMA interface latch tables + */ +static BYTE aIrqLatchTable[] = +{ + 0x00, 0x00, 0x01, 0x03, 0x00, 0x02, 0x00, 0x04, + 0x00, 0x01, 0x00, 0x05, 0x06, 0x00, 0x00, 0x07 +}; + +static BYTE aDmaLatchTable[] = +{ + 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x04, 0x05 +}; + +/* + * GF1 sampling frequencies and linear volumes table + */ +static WORD aFrequencyTable[] = +{ + 44100, 41160, 38587, 36317, 34300, 32494, 30870, 29400, + 28063, 26843, 25725, 24696, 23746, 22866, 22050, 21289, + 20580, 19916, 19293 +}; + +static WORD aVolumeTable[65] = +{ + 0x0400, + 0x07FF, 0x0980, 0x0A40, 0x0AC0, 0x0B20, 0x0B60, 0x0BA0, 0x0BE0, + 0x0C10, 0x0C30, 0x0C50, 0x0C70, 0x0C90, 0x0CB0, 0x0CD0, 0x0CF0, + 0x0D08, 0x0D18, 0x0D28, 0x0D38, 0x0D48, 0x0D58, 0x0D68, 0x0D78, + 0x0D88, 0x0D98, 0x0DA8, 0x0DB8, 0x0DC8, 0x0DD8, 0x0DE8, 0x0DF8, + 0x0E04, 0x0E0C, 0x0E14, 0x0E1C, 0x0E24, 0x0E2C, 0x0E34, 0x0E3C, + 0x0E44, 0x0E4C, 0x0E54, 0x0E5C, 0x0E64, 0x0E6C, 0x0E74, 0x0E7C, + 0x0E84, 0x0E8C, 0x0E94, 0x0E9C, 0x0EA4, 0x0EAC, 0x0EB4, 0x0EBC, + 0x0EC4, 0x0ECC, 0x0ED4, 0x0EDC, 0x0EE4, 0x0EEC, 0x0EF4, 0x0EFC +}; + +#ifdef INTERWAVE +/* + * InterWave panning table + */ +static WORD aPanningTable[128] = +{ + 0xFFF0, 0x6FD0, 0x5FD0, 0x5670, 0x4FD0, 0x4AB0, 0x4670, 0x42E0, + 0x3FD0, 0x3D20, 0x3AB0, 0x3870, 0x3670, 0x34A0, 0x32E0, 0x3150, + 0x2FD0, 0x2E70, 0x2D20, 0x2BE0, 0x2AB0, 0x2990, 0x2870, 0x2770, + 0x2670, 0x2580, 0x24A0, 0x23C0, 0x22E0, 0x2210, 0x2150, 0x2090, + 0x1FD0, 0x1F20, 0x1E70, 0x1DC0, 0x1D20, 0x1C70, 0x1BE0, 0x1B40, + 0x1AB0, 0x1A20, 0x1990, 0x1900, 0x1870, 0x17F0, 0x1770, 0x16F0, + 0x1670, 0x1600, 0x1580, 0x1510, 0x14A0, 0x1430, 0x13C0, 0x1350, + 0x12E0, 0x1280, 0x1210, 0x11B0, 0x1150, 0x10F0, 0x1090, 0x1030, + 0x0FD0, 0x0F70, 0x0F20, 0x0EC0, 0x0E70, 0x0E10, 0x0DC0, 0x0D70, + 0x0D20, 0x0CD0, 0x0C70, 0x0C30, 0x0BE0, 0x0B90, 0x0B40, 0x0AF0, + 0x0AB0, 0x0A60, 0x0A20, 0x09D0, 0x0990, 0x0940, 0x0900, 0x08C0, + 0x0870, 0x0830, 0x07F0, 0x07B0, 0x0770, 0x0730, 0x06F0, 0x06B0, + 0x0670, 0x0640, 0x0600, 0x05C0, 0x0580, 0x0550, 0x0510, 0x04D0, + 0x04A0, 0x0460, 0x0430, 0x03F0, 0x03C0, 0x0380, 0x0350, 0x0320, + 0x02E0, 0x02B0, 0x0280, 0x0250, 0x0210, 0x01E0, 0x01B0, 0x0180, + 0x0150, 0x0120, 0x00F0, 0x00C0, 0x0090, 0x0060, 0x0030, 0x0000 +}; + +/* + * InterWave supported DRAM bank configurations + */ +static WORD aBankCfgTable[13][4] = +{ + { 256, 0, 0, 0 }, /* 0x00 - 256K */ + { 256, 256, 0, 0 }, /* 0x01 - 512K */ + { 256, 256, 256, 256 }, /* 0x02 - 1024K */ + { 256, 1024, 0, 0 }, /* 0x03 - 1280K */ + { 256, 1024, 1024, 1024 }, /* 0x04 - 3328K */ + { 256, 256, 1024, 0 }, /* 0x05 - 1536K */ + { 256, 256, 1024, 1024 }, /* 0x06 - 2560K */ + { 1024, 0, 0, 0 }, /* 0x07 - 1024K */ + { 1024, 1024, 0, 0 }, /* 0x08 - 2048K */ + { 1024, 1024, 1024, 1024 }, /* 0x09 - 4096K */ + { 4096, 0, 0, 0 }, /* 0x0A - 4096K */ + { 4096, 4096, 0, 0 }, /* 0x0B - 8192K */ + { 4096, 4096, 4096, 4096 } /* 0x0C - 16384K */ +}; +#endif + + +/* GF1 configuration and shadow registers */ +static struct { +#ifdef INTERWAVE + WORD wId; /* audio device identifier */ +#endif + WORD wPort; /* GF1 base port address */ + BYTE nIrqLine; /* GF1 interrupt line */ + BYTE nMidiIrqLine; /* MIDI interrupt line */ + BYTE nDramDmaChannel; /* DRAM DMA channel */ + BYTE nAdcDmaChannel; /* ADC DMA channel */ + DWORD dwMemorySize; /* GF1 DRAM total memory */ + LONG dwFreqDivisor; /* current frequency divisor */ + BYTE bMixControl; /* board mix control register */ + BYTE bTimerControl; /* timer control register */ + BYTE bTimerMask; /* timer data shadow register */ + BYTE bIrqControl; /* board IRQ control register */ + BYTE bDmaControl; /* board DMA control register */ + BYTE nVoices; /* active voices register */ + DWORD aVoiceStart[32]; /* voice start address registers */ + DWORD aVoiceLength[32]; /* voice length in samples */ + LONG dwTimer1Accum; /* timer #1 accumulator */ + LONG dwTimer1Rate; /* timer #1 rate */ + LONG dwTimer2Accum; /* timer #2 accumulator */ + LONG dwTimer2Rate; /* timer #2 rate */ + LPFNAUDIOTIMER lpfnTimer1Handler; /* timer #1 callback */ + LPFNAUDIOTIMER lpfnTimer2Handler; /* timer #2 callback */ +#ifdef INTERWAVE + DWORD aBankSize[4]; /* Local Memory Bank Configs */ +#endif +} GF1; + +static volatile BOOL fDramDmaPending; + + +/* + * GF1 basic programming routines + */ +static VOID GF1SelectVoice(BYTE nVoice) +{ + OUTB(GF1.wPort + GUS_GF1_PAGE, nVoice); +} + +static VOID GF1PortB(BYTE nIndex, BYTE bData) +{ + OUTB(GF1.wPort + GUS_GF1_INDEX, nIndex); + OUTB(GF1.wPort + GUS_GF1_DATA_HIGH, bData); +} + +static VOID GF1PortW(BYTE nIndex, WORD wData) +{ + OUTB(GF1.wPort + GUS_GF1_INDEX, nIndex); + OUTW(GF1.wPort + GUS_GF1_DATA_LOW, wData); +} + +static BYTE GF1PortRB(BYTE nIndex) +{ + OUTB(GF1.wPort + GUS_GF1_INDEX, nIndex); + return INB(GF1.wPort + GUS_GF1_DATA_HIGH); +} + +static WORD GF1PortRW(BYTE nIndex) +{ + OUTB(GF1.wPort + GUS_GF1_INDEX, nIndex); + return INW(GF1.wPort + GUS_GF1_DATA_LOW); +} + +static BYTE GF1GetIrqStatus(VOID) +{ + return INB(GF1.wPort + GUS_GF1_IRQ_STAT); +} + +static VOID GF1StartTimer(UINT nTimer) +{ + if (nTimer == 1) { + GF1.bTimerControl |= TIMER1_IRQ_ENABLE; + GF1.bTimerMask |= TIMER1_START_UP; + } + else { + GF1.bTimerControl |= TIMER2_IRQ_ENABLE; + GF1.bTimerMask |= TIMER2_START_UP; + } + GF1PortB(GF1_TIMER_CTRL, GF1.bTimerControl); + OUTB(GF1.wPort + GUS_GF1_TIMER_CTRL, TIMER_CTRL_SELECT); + OUTB(GF1.wPort + GUS_GF1_TIMER_DATA, GF1.bTimerMask); +} + +static VOID GF1StopTimer(UINT nTimer) +{ + if (nTimer == 1) { + GF1.bTimerControl &= ~TIMER1_IRQ_ENABLE; + GF1.bTimerMask &= ~TIMER1_START_UP; + } + else { + GF1.bTimerControl &= ~TIMER2_IRQ_ENABLE; + GF1.bTimerMask &= ~TIMER2_START_UP; + } + GF1PortB(GF1_TIMER_CTRL, GF1.bTimerControl); + OUTB(GF1.wPort + GUS_GF1_TIMER_CTRL, TIMER_CTRL_SELECT); + OUTB(GF1.wPort + GUS_GF1_TIMER_DATA, GF1.bTimerMask); +} + +static VOID GF1SetTimerRate(UINT nTimer, BYTE nCount) +{ + if (nTimer == 1) { + GF1PortB(GF1_TIMER1_COUNT, 256 - nCount); + } + else { + GF1PortB(GF1_TIMER2_COUNT, 256 - nCount); + } +} + + +/* + * GF1 board mix control programming routines + */ +static VOID GF1EnableLineIn(VOID) +{ + GF1.bMixControl &= ~MIXER_DISABLE_LINE_IN; + OUTB(GF1.wPort + GUS_BOARD_MIX_CTRL, GF1.bMixControl); +} + +static VOID GF1DisableLineIn(VOID) +{ + GF1.bMixControl |= MIXER_DISABLE_LINE_IN; + OUTB(GF1.wPort + GUS_BOARD_MIX_CTRL, GF1.bMixControl); +} + +static VOID GF1EnableLineOut(VOID) +{ + GF1.bMixControl &= ~MIXER_DISABLE_LINE_OUT; + OUTB(GF1.wPort + GUS_BOARD_MIX_CTRL, GF1.bMixControl); +} + +static VOID GF1DisableLineOut(VOID) +{ + GF1.bMixControl |= MIXER_DISABLE_LINE_OUT; + OUTB(GF1.wPort + GUS_BOARD_MIX_CTRL, GF1.bMixControl); +} + +static VOID GF1EnableMicIn(VOID) +{ + GF1.bMixControl |= MIXER_ENABLE_MIC_IN; + OUTB(GF1.wPort + GUS_BOARD_MIX_CTRL, GF1.bMixControl); +} + +static VOID GF1DisableMicIn(VOID) +{ + GF1.bMixControl &= ~MIXER_ENABLE_MIC_IN; + OUTB(GF1.wPort + GUS_BOARD_MIX_CTRL, GF1.bMixControl); +} + + +/* + * GF1 basic onboard DRAM programming routines + */ +static DWORD GF1ConvertTo16Bits(DWORD dwAddr) +{ +#ifdef INTERWAVE + if (GF1.wId == AUDIO_PRODUCT_IWAVE) + return (dwAddr >> 1); +#endif + return ((dwAddr >> 1) & 0x0001FFFFL) | (dwAddr & 0x000C0000L); +} + +static DWORD GF1ConvertFrom16Bits(DWORD dwAddr) +{ +#ifdef INTERWAVE + if (GF1.wId == AUDIO_PRODUCT_IWAVE) + return (dwAddr << 1); +#endif + return ((dwAddr << 1) & 0x0003FFFFL) | (dwAddr & 0x000C0000L); +} + +static BYTE GF1PeekB(DWORD dwAddr) +{ + GF1PortW(GF1_DRAM_ADDR_LOW, LOWORD(dwAddr)); + GF1PortB(GF1_DRAM_ADDR_HIGH, (BYTE) HIWORD(dwAddr)); + return INB(GF1.wPort + GUS_GF1_DRAM_DATA); +} + +static VOID GF1PokeB(DWORD dwAddr, BYTE bData) +{ + GF1PortW(GF1_DRAM_ADDR_LOW, LOWORD(dwAddr)); + GF1PortB(GF1_DRAM_ADDR_HIGH, (BYTE) HIWORD(dwAddr)); + OUTB(GF1.wPort + GUS_GF1_DRAM_DATA, bData); +} + +static WORD GF1PeekW(DWORD dwAddr) +{ + WORD wLoData, wHiData; + + wLoData = GF1PeekB(dwAddr + 0); + wHiData = GF1PeekB(dwAddr + 1); + return MAKEWORD(wLoData, wHiData); +} + +static VOID GF1PokeW(DWORD dwAddr, WORD wData) +{ + GF1PokeB(dwAddr + 0, LOBYTE(wData)); + GF1PokeB(dwAddr + 1, HIBYTE(wData)); +} + +static DWORD GF1PeekDW(DWORD dwAddr) +{ + DWORD dwLoData, dwHiData; + + dwLoData = GF1PeekW(dwAddr + 0); + dwHiData = GF1PeekW(dwAddr + 2); + return MAKELONG(dwLoData, dwHiData); +} + +static VOID GF1PokeDW(DWORD dwAddr, DWORD dwData) +{ + GF1PokeW(dwAddr + 0, LOWORD(dwData)); + GF1PokeW(dwAddr + 2, HIWORD(dwData)); +} + +#ifdef USEPOKE + +static VOID GF1PokeBytes(DWORD dwAddr, LPBYTE lpBuffer, UINT nSize) +{ + DWORD dwChunkSize; + + while (nSize != 0) { + dwChunkSize = 0x10000L - LOWORD(dwAddr); + if (dwChunkSize > nSize) + dwChunkSize = nSize; + nSize -= dwChunkSize; + GF1PortB(GF1_DRAM_ADDR_HIGH, (BYTE) HIWORD(dwAddr)); + GF1PortW(GF1_DRAM_ADDR_LOW, LOWORD(dwAddr)); + while (dwChunkSize--) { + OUTW(GF1.wPort + GUS_GF1_DATA_LOW, LOWORD(dwAddr)); + OUTB(GF1.wPort + GUS_GF1_DRAM_DATA, *lpBuffer++); + dwAddr++; + } + } +} + +#else + +static VOID GF1UploadData(WORD wFormat, DWORD dwAddr, + LPBYTE lpBuffer, UINT nSize) +{ + LPBYTE lpDmaBuffer; + BYTE bControl; + UINT nChannelCount, nTimeOut, nCount; + + /* + * The DRAM address must be 32-byte aligned, so we need to use + * direct I/O to poke the unaligned bytes into DRAM memory. + */ + while ((dwAddr & 0x1F) != 0x00 && nSize != 0) { + GF1PokeB(dwAddr++, *lpBuffer++); + nSize--; + } + + /* setup the DRAM DMA control bit fields */ + bControl = DRAM_DMA_ENABLE | DRAM_DMA_IRQ_ENABLE | + DRAM_DMA_WRITE | DRAM_DMA_RATE0; + if (GF1.nDramDmaChannel >= 4) + bControl |= DRAM_DMA_WIDTH_16; + if (wFormat & AUDIO_FORMAT_16BITS) + bControl |= DRAM_DMA_DATA_16; + + while (nSize != 0) { + /* setup the DMA controller and the DMA buffer data */ + if ((nCount = nSize) > DMA_BUFFER_SIZE) + nCount = DMA_BUFFER_SIZE; + + /* + * We should fill the DMA buffer before setting the DMA controller + * to start the transfer. This fixes some problems when running + * under Windows 95 or any other operating system that provides + * virtualized DMA controllers. + */ + if ((lpDmaBuffer = DosLockChannel(GF1.nDramDmaChannel)) != NULL) { + memcpy(lpDmaBuffer, lpBuffer, nCount); + DosUnlockChannel(GF1.nDramDmaChannel); + } + DosSetupChannel(GF1.nDramDmaChannel, DMA_WRITE, nCount); + fDramDmaPending = 0; + + /* setup the starting DRAM address in paragraphs */ + GF1PortW(GF1_DMA_ADDR, (bControl & DRAM_DMA_WIDTH_16 ? + GF1ConvertTo16Bits(dwAddr) : dwAddr) >> 4); + +#ifdef INTERWAVE + if (GF1.wId == AUDIO_PRODUCT_IWAVE) { + DWORD dwLDSA; + dwLDSA = bControl & DRAM_DMA_WIDTH_16 ? + GF1ConvertTo16Bits(dwAddr) : dwAddr; + /* set DRAM address bits 23:20 and 3:0 */ + GF1PortB(IW_LDSAHI, + ((dwLDSA >> 16) & 0x00F0) | (dwLDSA & 0x000F)); + } +#endif + + /* start DMA DRAM transfer */ + GF1PortB(GF1_DRAM_DMA_CTRL, bControl); + + /* wait until the DMA transfer finishes */ + for (nTimeOut = nChannelCount = 0; nTimeOut < DMA_TIMEOUT && + !fDramDmaPending; nTimeOut++) { + if (DosGetChannelCount(GF1.nDramDmaChannel) != nChannelCount) { + nChannelCount = DosGetChannelCount(GF1.nDramDmaChannel); + nTimeOut = 0; + } + } + + /* stop DMA DRAM transfer */ + GF1PortB(GF1_DRAM_DMA_CTRL, + GF1PortRB(GF1_DRAM_DMA_CTRL) & ~DRAM_DMA_ENABLE); + DosDisableChannel(GF1.nDramDmaChannel); + + /* advance the pointers to the next chunk */ + lpBuffer += nCount; + dwAddr += nCount; + nSize -= nCount; + } + +} + +#endif + + +/* + * GF1 basic synthesizer programming routines + */ +static VOID GF1Delay(VOID) +{ + UINT n; + + for (n = 0; n < 8; n++) { + INB(GF1.wPort + GUS_GF1_DRAM_DATA); + } +} + +static VOID GF1Reset(UINT nVoices) +{ + DWORD dwData; + UINT n; + + /* number of voices must be between 14 and 32 */ + if (nVoices < 14) + nVoices = 14; + else if (nVoices > 32) + nVoices = 32; + + /* reset GF1 shadow registers */ + GF1.nVoices = nVoices; + GF1.dwFreqDivisor = aFrequencyTable[nVoices - 14]; +#ifdef INTERWAVE + if (GF1.wId == AUDIO_PRODUCT_IWAVE) + /* InterWave is always at 44100 Hz */ + GF1.dwFreqDivisor = 44100; +#endif + GF1.bMixControl = MIXER_DISABLE_LINE_IN | + MIXER_DISABLE_LINE_OUT | MIXER_ENABLE_LATCHES; + GF1.bTimerControl = 0x00; + GF1.bTimerMask = 0x00; + GF1.bIrqControl = 0x00; + GF1.bDmaControl = 0x00; + + /* pull a reset on the GF1 synthesizer */ + dwData = GF1PeekDW(0L); + GF1PokeDW(0L, 0L); + GF1PortB(GF1_MASTER_RESET, 0x00); + for (n = 0; n < 16; n++) + GF1Delay(); + + /* release reset and wait */ + GF1PortB(GF1_MASTER_RESET, MASTER_RESET); + for (n = 0; n < 16; n++) + GF1Delay(); + GF1PokeDW(0L, dwData); + + /* reset MIDI ports */ + OUTB(GF1.wPort + GUS_MIDI_CTRL, MIDI_RESET); + for (n = 0; n < 16; n++) + GF1Delay(); + OUTB(GF1.wPort + GUS_MIDI_CTRL, 0x00); + +#ifdef INTERWAVE + /* force InterWave native node */ + if (GF1.wId == AUDIO_PRODUCT_IWAVE) + GF1PortB(IW_SGMI_WR, GF1PortRB(IW_SGMI_RD) | IW_SGMI_ENHMODE); +#endif + + /* clear all the GF1 interrupts */ + GF1PortB(GF1_DRAM_DMA_CTRL, 0x00); + GF1PortB(GF1_TIMER_CTRL, 0x00); + GF1PortB(GF1_ADC_DMA_CTRL, 0x00); + + /* set number of active voices */ + GF1PortB(GF1_SET_NUMVOICES, (nVoices - 1) | 0xC0); + + /* clear interrupt on voices */ + GF1GetIrqStatus(); + GF1PortRB(GF1_DRAM_DMA_CTRL); + GF1PortRB(GF1_ADC_DMA_CTRL); + GF1PortRB(GF1_GET_IRQ_STAT); + + for (n = 0; n < nVoices; n++) { + /* select proper voice */ + GF1SelectVoice(n); + + /* stop voice and volume */ + GF1PortB(GF1_SET_VOICE_CTRL, VOICE_STOPPED | VOICE_STOP); + GF1PortB(GF1_SET_VOLUME_CTRL, VOLUME_STOPPED | VOLUME_STOP); + GF1Delay(); + + /* initialize voice specific registers */ + GF1PortW(GF1_SET_FREQ_CTRL, 0x400); + GF1PortB(GF1_SET_PANNING, 0x07); + GF1PortW(GF1_SET_START_HIGH, 0x0000); + GF1PortW(GF1_SET_START_LOW, 0x0000); + GF1PortW(GF1_SET_END_HIGH, 0x0000); + GF1PortW(GF1_SET_END_LOW, 0x0000); + GF1PortB(GF1_SET_VOLUME_RATE, 0x3F); + GF1PortB(GF1_SET_VOLUME_START, 0x40); + GF1PortB(GF1_SET_VOLUME_END, 0x40); + GF1PortW(GF1_SET_VOLUME, 0x04000); + GF1PortW(GF1_SET_ACCUM_HIGH, 0x0000); + GF1PortW(GF1_SET_ACCUM_LOW, 0x0000); +#ifdef INTERWAVE + if (GF1.wId == AUDIO_PRODUCT_IWAVE) { + /* active voice smooth panning */ + GF1PortB(IW_SMSI_WR, IW_SMSI_VOICE_OFFSET); + /* InterWave synth upper address */ + GF1PortB(IW_SUAI_WR, 0x00); + /* InterWave synth left offset */ + GF1PortW(IW_SLOI_WR, aPanningTable[64]); + /* InterWave synth right offset */ + GF1PortW(IW_SROI_WR, aPanningTable[64]); + } +#endif + } + + /* clear interrupt on voices (again) */ + GF1GetIrqStatus(); + GF1PortRB(GF1_DRAM_DMA_CTRL); + GF1PortRB(GF1_ADC_DMA_CTRL); + GF1PortRB(GF1_GET_IRQ_STAT); + + /* setup GF1 synth for interrupts and enable DACs */ + GF1PortB(GF1_MASTER_RESET, MASTER_RESET | + MASTER_ENABLE_DAC | MASTER_ENABLE_IRQ); +} + +static VOID GF1SetInterface(VOID) +{ + /* set GF1/MIDI IRQ latches */ + GF1.bIrqControl |= aIrqLatchTable[GF1.nIrqLine]; + if (!GF1.nIrqLine || (GF1.nIrqLine != GF1.nMidiIrqLine)) + GF1.bIrqControl |= aIrqLatchTable[GF1.nMidiIrqLine] << 3; + else + GF1.bIrqControl |= 0x40; + + /* set DRAM/ADC DMA latches */ + GF1.bDmaControl |= aDmaLatchTable[GF1.nDramDmaChannel]; + if (!GF1.nDramDmaChannel || (GF1.nDramDmaChannel != GF1.nAdcDmaChannel)) + GF1.bDmaControl |= aDmaLatchTable[GF1.nAdcDmaChannel] << 3; + else + GF1.bDmaControl |= 0x40; + + /* setup for digital ASIC */ + OUTB(GF1.wPort + GUS_BOARD_REG_CTRL, 0x05); + OUTB(GF1.wPort + GUS_BOARD_MIX_CTRL, GF1.bMixControl | MIXER_LATCH_DMA); + OUTB(GF1.wPort + GUS_BOARD_IRQ_CLEAR, 0x00); + OUTB(GF1.wPort + GUS_BOARD_REG_CTRL, 0x00); + + /* first do DMA control register */ + OUTB(GF1.wPort + GUS_BOARD_MIX_CTRL, GF1.bMixControl | MIXER_LATCH_DMA); + OUTB(GF1.wPort + GUS_BOARD_DMA_CTRL, GF1.bDmaControl | 0x80); + + /* now do IRQ control register */ + OUTB(GF1.wPort + GUS_BOARD_MIX_CTRL, GF1.bMixControl | MIXER_LATCH_IRQ); + OUTB(GF1.wPort + GUS_BOARD_IRQ_CTRL, GF1.bIrqControl); + + /* first do DMA control register */ + OUTB(GF1.wPort + GUS_BOARD_MIX_CTRL, GF1.bMixControl | MIXER_LATCH_DMA); + OUTB(GF1.wPort + GUS_BOARD_DMA_CTRL, GF1.bDmaControl); + + /* now do IRQ control register */ + OUTB(GF1.wPort + GUS_BOARD_MIX_CTRL, GF1.bMixControl | MIXER_LATCH_IRQ); + OUTB(GF1.wPort + GUS_BOARD_IRQ_CTRL, GF1.bIrqControl); + + /* lock out writes to IRQ/DMA control registers */ + OUTB(GF1.wPort + GUS_GF1_PAGE, 0x00); + + /* enable output and interrupts, disable line & mic input */ + GF1.bMixControl |= (MIXER_DISABLE_LINE_IN | MIXER_ENABLE_LATCHES); + OUTB(GF1.wPort + GUS_BOARD_MIX_CTRL, GF1.bMixControl); + + /* lock out writes to IRQ/DMA control registers */ + OUTB(GF1.wPort + GUS_GF1_PAGE, 0x00); +} + +static VOID AIAPI GF1InterruptHandler(VOID) +{ + BYTE bIrqStatus, nPage, nRegister; + + nPage = INB(GF1.wPort + GUS_GF1_PAGE); + nRegister = INB(GF1.wPort + GUS_GF1_INDEX); + while ((bIrqStatus = GF1GetIrqStatus()) != 0x00) { + if (bIrqStatus & IRQ_STAT_TIMER1) { + GF1PortB(GF1_TIMER_CTRL, GF1.bTimerControl & ~TIMER1_IRQ_ENABLE); + GF1PortB(GF1_TIMER_CTRL, GF1.bTimerControl); + if (GF1.lpfnTimer1Handler != NULL) { + GF1.dwTimer1Accum += GF1.dwTimer1Rate; + while (GF1.dwTimer1Accum >= 0x10000L) { + GF1.dwTimer1Accum -= 0x10000L; + GF1.lpfnTimer1Handler(); + } + } + } + if (bIrqStatus & IRQ_STAT_TIMER2) { + GF1PortB(GF1_TIMER_CTRL, GF1.bTimerControl & ~TIMER2_IRQ_ENABLE); + GF1PortB(GF1_TIMER_CTRL, GF1.bTimerControl); + if (GF1.lpfnTimer2Handler != NULL) { + GF1.dwTimer2Accum += GF1.dwTimer2Rate; + while (GF1.dwTimer2Accum >= 0x10000L) { + GF1.dwTimer2Accum -= 0x10000L; + GF1.lpfnTimer2Handler(); + } + } + } + if (bIrqStatus & IRQ_STAT_DMA_TC) { + if (GF1PortRB(GF1_DRAM_DMA_CTRL) & DRAM_DMA_IRQ_PENDING) { + fDramDmaPending++; + } + } + } + OUTB(GF1.wPort + GUS_GF1_INDEX, nRegister); + OUTB(GF1.wPort + GUS_GF1_PAGE, nPage); +} + + +static BOOL GF1Probe(VOID) +{ + WORD wData, wMyData; + + /* pull a reset on the GF1 */ + GF1PortB(GF1_MASTER_RESET, 0x00); + GF1Delay(); + GF1Delay(); + + /* release reset on the GF1 */ + GF1PortB(GF1_MASTER_RESET, MASTER_RESET); + GF1Delay(); + GF1Delay(); + + /* probe on board DRAM memory */ + wData = GF1PeekW(0L); + GF1PokeW(0L, 0x55AA); + wMyData = GF1PeekW(0L); + GF1PokeW(0L, wData); + return (wMyData != 0x55AA); +} + +/* + * GF1 onboard DRAM memory manager routines + */ +static DWORD GF1MemorySize(VOID) +{ + DWORD dwAddr; + +#ifdef INTERWAVE + if (GF1.wId == AUDIO_PRODUCT_IWAVE) { + UINT nBank, nBankCfg; + + /* force InterWave enhanced mode */ + GF1PortB(IW_SGMI_WR, GF1PortRB(IW_SGMI_RD) | IW_SGMI_ENHMODE); + + /* enable full access to 16MB */ + GF1PortW(IW_LMCFI, (GF1PortRW(IW_LMCFI) & 0xFFF0) | 0x0C); + + /* clean every RAM step location */ + for (dwAddr = 0x0000000L; dwAddr < 0x1000000L; dwAddr += 0x10000L) + GF1PokeDW(dwAddr, 0x12345678L); + + /* determine amount of DRAM in each bank */ + for (nBank = 0; nBank < 4; nBank++) { + GF1.aBankSize[nBank] = 0; + dwAddr = ((DWORD) nBank) << 22; + if (GF1PeekDW(dwAddr) == 0x12345678L) { + GF1PokeDW(dwAddr, 0x55AA55AAL); + if (GF1PeekDW(dwAddr) == 0x55AA55AAL) { + /* each bank can have up to 4MB of memory */ + while ((GF1.aBankSize[nBank] += 64) < 4096) { + dwAddr += 0x10000L; + if (GF1PeekDW(dwAddr) == 0x55AA55AAL) break; + } + } + } + } + + for (nBankCfg = 0; nBankCfg < 13; nBankCfg++) { + if (aBankCfgTable[nBankCfg][0] == GF1.aBankSize[0] && + aBankCfgTable[nBankCfg][1] == GF1.aBankSize[1] && + aBankCfgTable[nBankCfg][2] == GF1.aBankSize[2] && + aBankCfgTable[nBankCfg][3] == GF1.aBankSize[3]) { + /* set up contiguous access to local memory banks */ + GF1PortW(IW_LMCFI, (GF1PortRW(IW_LMCFI) & 0xFFF0) | nBankCfg); + GF1.aBankSize[0] += + GF1.aBankSize[1] + GF1.aBankSize[2] + GF1.aBankSize[3]; + GF1.aBankSize[1] = GF1.aBankSize[2] = GF1.aBankSize[3] = 0; + return (DWORD) GF1.aBankSize[0] << 10; + } + } + + /* enable non-contiguous access to local memory banks */ + GF1PortW(IW_LMCFI, (GF1PortRW(IW_LMCFI) & 0xFFF0) | 0x0C); + return (DWORD)(GF1.aBankSize[0] + GF1.aBankSize[1] + + GF1.aBankSize[2] + GF1.aBankSize[3]) << 10; + } +#endif + dwAddr = 0x00000L; + GF1PokeDW(dwAddr, 0x12345678L); + if (GF1PeekDW(dwAddr) == 0x12345678L) { + GF1PokeDW(dwAddr, 0x00000000L); + while ((dwAddr += 0x00400L) < 0x100000L) { + GF1PokeDW(dwAddr, 0x12345678L); + if (GF1PeekDW(dwAddr) != 0x12345678L) + break; + if (GF1PeekDW(0x00000L) != 0x00000000L) + break; + } + } + return dwAddr; +} + +static LONG GF1MemAvail(VOID) +{ + DWORD dwPrevNode, dwNode, dwMemSize; + + dwMemSize = 0L; + dwPrevNode = 0L; + while ((dwNode = GF1PeekDW(dwPrevNode + 0)) != 0L) { + dwMemSize += GF1PeekDW(dwNode + 4); + dwPrevNode = dwNode; + } + return dwMemSize; +} + +static VOID GF1MemInit(VOID) +{ + DWORD dwNode, dwNextNode, dwNodeSize; + + /* get amount of GF1 DRAM memory in bytes */ + GF1.dwMemorySize = GF1MemorySize(); + +#ifdef INTERWAVE + if (GF1.wId == AUDIO_PRODUCT_IWAVE) { + DWORD nBank, dwTopMemory; + + dwNode = 0L; + dwNodeSize = DRAM_HEADER_SIZE; + dwNextNode = dwNode + dwNodeSize; + GF1PokeDW(dwNode + 0, dwNextNode); + GF1PokeDW(dwNode + 4, dwNodeSize); + + /* split DRAM banks in blocks of 256KB */ + /* WARNING: the first bank must have memory */ + nBank = 0; + dwTopMemory = (GF1.aBankSize[nBank] << 10); + while ((dwNode = dwNextNode) != 0L) { + dwNextNode = (dwNode + DRAM_BANK_SIZE) & -DRAM_BANK_SIZE; + dwNodeSize = (dwNextNode - dwNode); + if (dwNextNode >= dwTopMemory) { + dwNodeSize = (dwTopMemory - dwNode); + while (++nBank < 4 && !GF1.aBankSize[nBank]) + continue; + if (nBank < 4) { + dwNextNode = ((DWORD)nBank << 22); + dwTopMemory = dwNextNode + (GF1.aBankSize[nBank] << 10); + } + else { + dwNextNode = 0x00000L; + } + } + GF1PokeDW(dwNode + 0, dwNextNode); + GF1PokeDW(dwNode + 4, dwNodeSize); + } + return; + } +#endif + + /* setup first DRAM memory block */ + dwNode = 0x00000L; + dwNodeSize = DRAM_HEADER_SIZE; + dwNextNode = dwNode + dwNodeSize; + GF1PokeDW(dwNode + 0, dwNextNode); + GF1PokeDW(dwNode + 4, dwNodeSize); + + /* split DRAM memory in blocks of 256 kilobytes */ + while ((dwNode = dwNextNode) != 0L) { + dwNextNode = (dwNode + DRAM_BANK_SIZE) & -DRAM_BANK_SIZE; + dwNodeSize = (dwNextNode - dwNode); + if (dwNextNode >= GF1.dwMemorySize) { + dwNextNode = 0x00000L; + dwNodeSize = (GF1.dwMemorySize - dwNode); + } + GF1PokeDW(dwNode + 0, dwNextNode); + GF1PokeDW(dwNode + 4, dwNodeSize); + } +} + + +static DWORD GF1MemAlloc(DWORD dwSize) +{ + DWORD dwNode, dwPrevNode, dwNodeSize; + + if ((dwSize += DRAM_HEADER_SIZE) != 0) { + dwSize = (dwSize + DRAM_HEADER_SIZE - 1) & -DRAM_HEADER_SIZE; + dwPrevNode = 0L; + while ((dwNode = GF1PeekDW(dwPrevNode + 0)) != 0L) { + if ((dwNodeSize = GF1PeekDW(dwNode + 4)) >= dwSize) { + if (dwNodeSize == dwSize) { + GF1PokeDW(dwPrevNode + 0, GF1PeekDW(dwNode + 0L)); + } + else { + dwNodeSize -= dwSize; + GF1PokeDW(dwNode + 4, dwNodeSize); + dwNode += dwNodeSize; + GF1PokeDW(dwNode + 4, dwSize); + } + GF1PokeDW(dwNode + 0, ~dwSize); + return (dwNode + DRAM_HEADER_SIZE); + } + dwPrevNode = dwNode; + } + } + return 0L; +} + +static VOID GF1MemFree(DWORD dwAddr) +{ + DWORD dwNode, dwNextNode, dwNodeSize; + + if ((dwAddr -= DRAM_HEADER_SIZE) < (16L << 20) && + GF1PeekDW(dwAddr + 0) == ~GF1PeekDW(dwAddr + 4)) { + dwNode = 0L; + while (dwNode != (16L << 20)) { + if ((dwNextNode = GF1PeekDW(dwNode + 0L)) == 0L) + dwNextNode = (16L << 20); + if (dwAddr > dwNode && dwAddr < dwNextNode) + break; + dwNode = dwNextNode; + } + if (dwNode != (16L << 20)) { + dwNodeSize = GF1PeekDW(dwAddr + 4L); + if (dwAddr + dwNodeSize == dwNextNode && + (dwNextNode & (DRAM_BANK_SIZE-1)) != 0L) { + GF1PokeDW(dwAddr + 4, dwNodeSize + GF1PeekDW(dwNextNode + 4)); + GF1PokeDW(dwAddr + 0, GF1PeekDW(dwNextNode + 0)); + } + else { + GF1PokeDW(dwAddr + 0, dwNextNode); + } + dwNodeSize = GF1PeekDW(dwNode + 4); + if (dwNode + dwNodeSize == dwAddr && + (dwAddr & (DRAM_BANK_SIZE-1)) != 0L) { + GF1PokeDW(dwNode + 4, dwNodeSize + GF1PeekDW(dwAddr + 4)); + GF1PokeDW(dwNode + 0, GF1PeekDW(dwAddr + 0)); + } + else { + GF1PokeDW(dwNode + 0, dwAddr); + } + } + } +} + + + +/* + * GF1 low level voice programming routines + */ +static VOID GF1PrimeVoice(DWORD dwStart, DWORD dwLoopStart, + DWORD dwLoopEnd, BYTE bControl) +{ + DWORD dwTemp; + + bControl |= (VOICE_STOPPED | VOICE_STOP); + + if (dwLoopStart > dwLoopEnd) { + dwTemp = dwLoopStart; + dwLoopStart = dwLoopEnd; + dwLoopEnd = dwTemp; + bControl |= VOICE_DIRECT; + } + + if (bControl & VOICE_DATA_16) { + dwStart = GF1ConvertTo16Bits(dwStart << 1); + dwLoopStart = GF1ConvertTo16Bits(dwLoopStart << 1); + dwLoopEnd = GF1ConvertTo16Bits(dwLoopEnd << 1); + } + + GF1PortB(GF1_SET_VOICE_CTRL, bControl); + GF1Delay(); + GF1PortB(GF1_SET_VOICE_CTRL, bControl); + +#ifdef INTERWAVE + if (GF1.wId == AUDIO_PRODUCT_IWAVE) + /* select InterWave local memory bank */ + GF1PortB(IW_SUAI_WR, (dwStart >> 22) & 0x03); +#endif + + GF1PortW(GF1_SET_ACCUM_HIGH, dwStart >> 7); + GF1PortW(GF1_SET_ACCUM_LOW, dwStart << 9); + + GF1PortW(GF1_SET_START_HIGH, dwLoopStart >> 7); + GF1PortW(GF1_SET_START_LOW, dwLoopStart << 9); + + GF1PortW(GF1_SET_END_HIGH, dwLoopEnd >> 7); + GF1PortW(GF1_SET_END_LOW, dwLoopEnd << 9); +} + +static VOID GF1StartVoice(VOID) +{ + BYTE bControl; + + bControl = GF1PortRB(GF1_GET_VOICE_CTRL) & ~VOICE_ENABLE_IRQ; + bControl &= ~(VOICE_STOPPED | VOICE_STOP); + + GF1PortB(GF1_SET_VOICE_CTRL, bControl); + GF1Delay(); + GF1PortB(GF1_SET_VOICE_CTRL, bControl); + +#ifdef INTERWAVE + if (GF1.wId == AUDIO_PRODUCT_IWAVE) + /* activate voice */ + GF1PortB(IW_SMSI_WR, GF1PortRB(IW_SMSI_RD) & ~IW_SMSI_VOICE_DISABLE); +#endif +} + +static VOID GF1StopVoice(VOID) +{ + BYTE bControl; + + bControl = GF1PortRB(GF1_GET_VOICE_CTRL) & ~VOICE_ENABLE_IRQ; + bControl |= (VOICE_STOPPED | VOICE_STOP); + + GF1PortB(GF1_SET_VOICE_CTRL, bControl); + GF1Delay(); + GF1PortB(GF1_SET_VOICE_CTRL, bControl); + +#ifdef INTERWAVE + if (GF1.wId == AUDIO_PRODUCT_IWAVE) { + /* de-activate voice */ + GF1PortB(IW_SMSI_WR, GF1PortRB(IW_SMSI_RD) | IW_SMSI_VOICE_DISABLE); + } +#endif +} + +static BOOL GF1VoiceStopped(VOID) +{ + return (GF1PortRB(GF1_GET_VOICE_CTRL) & (VOICE_STOPPED | VOICE_STOP)) != 0; +} + +static VOID GF1SetVoicePosition(DWORD dwAddr) +{ + BYTE bControl; + + bControl = GF1PortRB(GF1_GET_VOICE_CTRL) & ~VOICE_ENABLE_IRQ; + if (bControl & VOICE_DATA_16) + dwAddr = GF1ConvertTo16Bits(dwAddr << 1); + + GF1PortB(GF1_SET_VOICE_CTRL, bControl | VOICE_STOP | VOICE_STOPPED); + GF1Delay(); + GF1PortB(GF1_SET_VOICE_CTRL, bControl | VOICE_STOP | VOICE_STOPPED); + +#ifdef INTERWAVE + if (GF1.wId == AUDIO_PRODUCT_IWAVE) + /* select InterWave local memory bank */ + GF1PortB(IW_SUAI_WR, (dwAddr >> 22) & 0x03); +#endif + + GF1PortW(GF1_SET_ACCUM_HIGH, dwAddr >> 7); + GF1PortW(GF1_SET_ACCUM_LOW, dwAddr << 9); + + GF1PortB(GF1_SET_VOICE_CTRL, bControl); + GF1Delay(); + GF1PortB(GF1_SET_VOICE_CTRL, bControl); +} + +static DWORD GF1GetVoicePosition(VOID) +{ + DWORD dwAddr; + UINT nTimeOut; + + for (nTimeOut = 0; nTimeOut < 4; nTimeOut++) { + dwAddr = GF1PortRW(GF1_GET_ACCUM_HIGH); + dwAddr = (dwAddr << 7) & 0xFFF80L; + dwAddr |= (GF1PortRW(GF1_GET_ACCUM_LOW) >> 9) & 0x0007FL; +#ifdef INTERWAVE + if (GF1.wId == AUDIO_PRODUCT_IWAVE) + /* retrieve InterWave local memory bank */ + dwAddr |= ((DWORD) GF1PortRB(IW_SUAI_RD) & 0x03L) << 22; +#endif + if (!(((dwAddr >> 7) ^ GF1PortRW(GF1_GET_ACCUM_HIGH)) & 0x01FFFL)) + break; + } + + return (GF1PortRB(GF1_GET_VOICE_CTRL) & VOICE_DATA_16) ? + (GF1ConvertFrom16Bits(dwAddr) >> 1) : dwAddr; +} + +static VOID GF1SetFrequency(LONG dwFrequency) +{ + DWORD FC; + + FC = ((dwFrequency << 9) + (GF1.dwFreqDivisor >> 1)) / GF1.dwFreqDivisor; + GF1PortW(GF1_SET_FREQ_CTRL, FC << 1); +} + +static LONG GF1GetFrequency(VOID) +{ + DWORD FC; + + FC = GF1PortRW(GF1_GET_FREQ_CTRL); + return ((FC >> 1) * GF1.dwFreqDivisor) >> 9; +} + +static VOID GF1SetPanning(BYTE nPanning) +{ +#ifdef INTERWAVE + if (GF1.wId == AUDIO_PRODUCT_IWAVE) { + nPanning >>= 1; + /* InterWave synth right offset */ + GF1PortW(IW_SROI_WR, aPanningTable[nPanning]); + /* InterWave synth left offset */ + GF1PortW(IW_SLOI_WR, aPanningTable[0x7F - nPanning]); + } + else +#endif + GF1PortB(GF1_SET_PANNING, nPanning >> 4); +} + +static BYTE GF1GetPanning(VOID) +{ +#ifdef INTERWAVE + if (GF1.wId == AUDIO_PRODUCT_IWAVE) { + WORD wPanValue, nPanning; + wPanValue = GF1PortRW(IW_SROI_RD); + for (nPanning = 0x00; nPanning < 0x7F; nPanning++) { + if (wPanValue <= aPanningTable[nPanning]) + break; + } + return (nPanning << 1); + } +#endif + return GF1PortRB(GF1_GET_PANNING) << 4; +} + +/* + * static VOID GF1SetVolume(WORD nVolume) + * { + * GF1PortW(GF1_SET_VOLUME, nVolume << 4); + * } + */ + +static WORD GF1GetVolume(VOID) +{ + return GF1PortRW(GF1_GET_VOLUME) >> 4; +} + +static VOID GF1RampVolume(WORD nStartVolume, WORD nEndVolume, + BYTE nVolumeRate, BYTE bControl) +{ + WORD nBeginVolume; + + bControl &= ~(VOLUME_IRQ_PENDING | VOLUME_ROLLOVER | + VOLUME_STOP | VOLUME_STOPPED); + + if ((nBeginVolume = nStartVolume) > nEndVolume) { + nStartVolume = nEndVolume; + nEndVolume = nBeginVolume; + bControl |= VOLUME_DIRECT; + } + if (nStartVolume < 0x040) + nStartVolume = 0x040; + if (nEndVolume > 0xFC0) + nEndVolume = 0xFC0; + + GF1PortB(GF1_SET_VOLUME_RATE, nVolumeRate); + GF1PortB(GF1_SET_VOLUME_START, nStartVolume >> 4); + GF1PortB(GF1_SET_VOLUME_END, nEndVolume >> 4); + GF1PortW(GF1_SET_VOLUME, nBeginVolume << 4); + + GF1PortB(GF1_SET_VOLUME_CTRL, bControl); + GF1Delay(); + GF1PortB(GF1_SET_VOLUME_CTRL, bControl); +} + + +/* + * Ultrasound GF1 driver API interface + */ +static UINT AIAPI GetAudioCaps(LPAUDIOCAPS lpCaps) +{ + static AUDIOCAPS Caps = + { + AUDIO_PRODUCT_GUS, "Ultrasound", + AUDIO_FORMAT_4S16 + }; +#ifdef INTERWAVE + static AUDIOCAPS IWCaps = + { + AUDIO_PRODUCT_IWAVE, "Ultrasound PnP (InterWave)", + AUDIO_FORMAT_4S16 + }; + + if (GF1.wId == AUDIO_PRODUCT_IWAVE) + memcpy(lpCaps, &IWCaps, sizeof(AUDIOCAPS)); + else +#endif + memcpy(lpCaps, &Caps, sizeof(AUDIOCAPS)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI PingAudio(VOID) +{ + LPSTR lpszUltrasnd; + UINT wPort, nDramDma, nAdcDma, nIrqLine, nMidiIrqLine; + + if ((lpszUltrasnd = DosGetEnvironment("ULTRASND")) != NULL) { + if ((wPort = DosParseString(lpszUltrasnd, TOKEN_HEX)) != BAD_TOKEN && + (DosParseString(NULL, TOKEN_CHAR) == ',') && + (nDramDma = DosParseString(NULL, TOKEN_DEC)) != BAD_TOKEN && + (DosParseString(NULL, TOKEN_CHAR) == ',') && + (nAdcDma = DosParseString(NULL, TOKEN_DEC)) != BAD_TOKEN && + (DosParseString(NULL, TOKEN_CHAR) == ',') && + (nIrqLine = DosParseString(NULL, TOKEN_DEC)) != BAD_TOKEN && + (DosParseString(NULL, TOKEN_CHAR) == ',') && + (nMidiIrqLine = DosParseString(NULL, TOKEN_DEC)) != BAD_TOKEN) { + GF1.wPort = wPort; + GF1.nDramDmaChannel = nDramDma; + GF1.nAdcDmaChannel = nAdcDma; + GF1.nIrqLine = nIrqLine; + GF1.nMidiIrqLine = nMidiIrqLine; +#ifdef INTERWAVE + GF1.wId = AUDIO_PRODUCT_GUS; + if (DosGetEnvironment("INTERWAVE") != NULL) + GF1.wId = AUDIO_PRODUCT_IWAVE; +#endif + return GF1Probe(); + } + } + return AUDIO_ERROR_NODEVICE; +} + +static UINT AIAPI OpenAudio(LPAUDIOINFO lpInfo) +{ + /* + * Initialize GF1 driver configuration structure + * and check if the hardware is present. + */ + if (PingAudio()) + return AUDIO_ERROR_NODEVICE; + lpInfo->wFormat = AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO; + lpInfo->nSampleRate = 44100; + + /* + * Allocate an small DMA buffer for DRAM uploading + */ +#ifndef USEPOKE + if (DosAllocChannel(GF1.nDramDmaChannel, DMA_BUFFER_SIZE)) + return AUDIO_ERROR_NOMEMORY; +#endif + + /* + * Initialize GF1 DRAM memory manager and interrupt handler + */ + GF1MemInit(); + DosSetVectorHandler(GF1.nIrqLine, GF1InterruptHandler); + + /* + * Open the GF1 synthesizer for playback + */ + GF1Reset(14); + GF1SetInterface(); + GF1EnableLineOut(); + GF1DisableLineIn(); + GF1DisableMicIn(); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI CloseAudio(VOID) +{ + /* + * Reset the GF1 synthesizer, restore the interrupt handler + * and releases the DRAM/DMA buffer used for uploading. + */ + GF1DisableLineOut(); + GF1EnableLineIn(); + GF1EnableMicIn(); + GF1Reset(14); +#ifdef INTERWAVE + if (GF1.wId == AUDIO_PRODUCT_IWAVE) + /* force GF1 compatible mode */ + GF1PortB(IW_SGMI_WR, GF1PortRB(IW_SGMI_RD) & ~IW_SGMI_ENHMODE); +#endif + DosSetVectorHandler(GF1.nIrqLine, NULL); +#ifndef USEPOKE + DosFreeChannel(GF1.nDramDmaChannel); +#endif + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudio(VOID) +{ + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioMixerValue(UINT nChannel, UINT nValue) +{ + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI OpenVoices(UINT nVoices) +{ + /* + * Open the GF1 synthesizer for playback + */ + if (nVoices < AUDIO_MAX_VOICES) { + GF1Reset(nVoices); + GF1EnableLineOut(); + GF1DisableLineIn(); + GF1DisableMicIn(); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; +} + +static UINT AIAPI CloseVoices(VOID) +{ + /* + * Reset the GF1 synthesizer and restore the interrupt handler + */ + GF1DisableLineOut(); + GF1EnableLineIn(); + GF1EnableMicIn(); + GF1Reset(14); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioTimerProc(LPFNAUDIOTIMER lpfnAudioTimer) +{ + if ((GF1.lpfnTimer2Handler = lpfnAudioTimer) != NULL) { + GF1StartTimer(2); + } + else { + GF1StopTimer(2); + } + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioTimerRate(UINT nBPM) +{ + UINT nTicks; + + if (nBPM >= 0x20 && nBPM <= 0xFF) { + nTicks = 15625 / (nBPM << 1); + GF1.dwTimer2Rate = (0x20000L * nBPM * nTicks) / 15625; + GF1SetTimerRate(2, nTicks); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; +} + +static LONG AIAPI GetAudioDataAvail(VOID) +{ + return GF1MemAvail(); +} + +static UINT AIAPI CreateAudioData(LPAUDIOWAVE lpWave) +{ + if (lpWave != NULL) { + if ((lpWave->dwHandle = GF1MemAlloc(lpWave->dwLength + 4)) != 0) + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_NODRAMMEMORY; +} + +static UINT AIAPI DestroyAudioData(LPAUDIOWAVE lpWave) +{ + if (lpWave != NULL && lpWave->dwHandle != 0) { + GF1MemFree(lpWave->dwHandle); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI WriteAudioData(LPAUDIOWAVE lpWave, DWORD dwOffset, UINT nCount) +{ + if (lpWave != NULL && lpWave->dwHandle != 0) { + if (dwOffset + nCount <= lpWave->dwLength) { +#ifndef USEPOKE + GF1UploadData(lpWave->wFormat, lpWave->dwHandle + dwOffset, + lpWave->lpData + dwOffset, nCount); +#else + GF1PokeBytes(lpWave->dwHandle + dwOffset, + lpWave->lpData + dwOffset, nCount); +#endif + /* anticlick removal workaround */ + if (lpWave->wFormat & AUDIO_FORMAT_LOOP) { + if (dwOffset <= lpWave->dwLoopEnd && + dwOffset + nCount >= lpWave->dwLoopEnd) { + GF1PokeDW(lpWave->dwHandle + lpWave->dwLoopEnd, + GF1PeekDW(lpWave->dwHandle + lpWave->dwLoopStart)); + } + } + else if (dwOffset + nCount >= lpWave->dwLength) { + GF1PokeDW(lpWave->dwHandle + lpWave->dwLength, 0); + } + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI PrimeVoice(UINT nVoice, LPAUDIOWAVE lpWave) +{ + DWORD dwStart, dwLoopStart, dwLoopEnd; + BYTE bControl; + + if (nVoice < GF1.nVoices && lpWave != NULL && lpWave->dwHandle != 0) { + dwStart = lpWave->dwHandle; + bControl = VOICE_STOP; + if (lpWave->wFormat & (AUDIO_FORMAT_LOOP | AUDIO_FORMAT_BIDILOOP)) { + dwLoopStart = lpWave->dwLoopStart; + dwLoopEnd = lpWave->dwLoopEnd; + bControl |= VOICE_LOOP; + if (lpWave->wFormat & AUDIO_FORMAT_BIDILOOP) + bControl |= VOICE_BIDILOOP; + } + else { + dwLoopStart = dwLoopEnd = lpWave->dwLength; + bControl |= VOICE_NORMAL; + } + if (lpWave->wFormat & AUDIO_FORMAT_16BITS) { + dwStart >>= 1; + dwLoopStart >>= 1; + dwLoopEnd >>= 1; + bControl |= VOICE_DATA_16; + } + GF1.aVoiceStart[nVoice] = dwStart; + GF1.aVoiceLength[nVoice] = dwLoopEnd; + GF1SelectVoice(nVoice); + GF1PrimeVoice(dwStart, dwStart + dwLoopStart, + dwStart + dwLoopEnd, bControl); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI StartVoice(UINT nVoice) +{ + if (nVoice < GF1.nVoices) { + GF1SelectVoice(nVoice); + GF1StartVoice(); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI StopVoice(UINT nVoice) +{ + if (nVoice < GF1.nVoices) { + GF1SelectVoice(nVoice); + GF1StopVoice(); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI SetVoicePosition(UINT nVoice, LONG dwPosition) +{ + if (nVoice < GF1.nVoices) { + if (dwPosition >= 0 && dwPosition <= GF1.aVoiceLength[nVoice]) { + GF1SelectVoice(nVoice); + GF1SetVoicePosition(GF1.aVoiceStart[nVoice] + dwPosition); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI SetVoiceFrequency(UINT nVoice, LONG dwFrequency) +{ + if (nVoice < GF1.nVoices) { + if (dwFrequency >= AUDIO_MIN_FREQUENCY && + dwFrequency <= AUDIO_MAX_FREQUENCY) { + GF1SelectVoice(nVoice); + GF1SetFrequency(dwFrequency); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI SetVoiceVolume(UINT nVoice, UINT nVolume) +{ + if (nVoice < GF1.nVoices) { + if (nVolume <= AUDIO_MAX_VOLUME) { + GF1SelectVoice(nVoice); + GF1RampVolume(GF1GetVolume(), aVolumeTable[nVolume], 0x3F, 0x00); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI SetVoicePanning(UINT nVoice, UINT nPanning) +{ + if (nVoice < GF1.nVoices) { + if (nPanning <= AUDIO_MAX_PANNING) { + GF1SelectVoice(nVoice); + GF1SetPanning(nPanning); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoicePosition(UINT nVoice, LPLONG lpdwPosition) +{ + if (nVoice < GF1.nVoices) { + if (lpdwPosition != NULL) { + GF1SelectVoice(nVoice); + *lpdwPosition = GF1GetVoicePosition() - GF1.aVoiceStart[nVoice]; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoiceFrequency(UINT nVoice, LPLONG lpdwFrequency) +{ + if (nVoice < GF1.nVoices) { + if (lpdwFrequency != NULL) { + GF1SelectVoice(nVoice); + *lpdwFrequency = GF1GetFrequency(); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoiceVolume(UINT nVoice, LPUINT lpnVolume) +{ + UINT nVolume, nLogVolume; + + if (nVoice < GF1.nVoices) { + if (lpnVolume != NULL) { + GF1SelectVoice(nVoice); + nLogVolume = GF1GetVolume(); + for (nVolume = 0; nVolume < AUDIO_MAX_VOLUME; nVolume++) + if (nLogVolume <= aVolumeTable[nVolume]) + break; + *lpnVolume = nVolume; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoicePanning(UINT nVoice, LPUINT lpnPanning) +{ + if (nVoice < GF1.nVoices) { + if (lpnPanning != NULL) { + GF1SelectVoice(nVoice); + *lpnPanning = GF1GetPanning(); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoiceStatus(UINT nVoice, LPBOOL lpnStatus) +{ + if (nVoice < GF1.nVoices) { + if (lpnStatus != NULL) { + GF1SelectVoice(nVoice); + *lpnStatus = GF1VoiceStopped(); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + + +/* + * Gravis Ultrasound driver public interface + */ +AUDIOSYNTHDRIVER UltraSoundSynthDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudio, OpenVoices, CloseVoices, + SetAudioTimerProc, SetAudioTimerRate, SetAudioMixerValue, + GetAudioDataAvail, CreateAudioData, DestroyAudioData, + WriteAudioData, PrimeVoice, StartVoice, StopVoice, + SetVoicePosition, SetVoiceFrequency, SetVoiceVolume, + SetVoicePanning, GetVoicePosition, GetVoiceFrequency, + GetVoiceVolume, GetVoicePanning, GetVoiceStatus +}; + +AUDIODRIVER UltraSoundDriver = +{ + NULL, &UltraSoundSynthDriver +}; diff --git a/seal-hack/src/iofile.c b/seal-hack/src/iofile.c new file mode 100644 index 0000000..bb935fb --- /dev/null +++ b/seal-hack/src/iofile.c @@ -0,0 +1,110 @@ +/* + * $Id: iofile.c 1.5 1996/08/05 18:51:19 chasan released $ + * + * Input/Output file stream routines. + * + * Copyright (c) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include "audio.h" +#include "iofile.h" + +/* + * Audio I/O file stream routines + */ +static FILE *lpStream; + +UINT AIAPI AIOOpenFile(LPSTR lpszFileName) +{ + if ((lpStream = fopen(lpszFileName, "rb")) != NULL) + return AUDIO_ERROR_NONE; + return AUDIO_ERROR_FILENOTFOUND; +} + +UINT AIAPI AIOCloseFile(VOID) +{ + fclose(lpStream); + return AUDIO_ERROR_NONE; +} + +UINT AIAPI AIOSeekFile(LONG dwOffset, UINT nWhere) +{ + fseek(lpStream, dwOffset, nWhere); + return AUDIO_ERROR_NONE; +} + +UINT AIAPI AIOReadFile(LPVOID lpData, UINT nSize) +{ + if (fread(lpData, 1, nSize, lpStream) != nSize) + memset(lpData, 0, nSize); + return AUDIO_ERROR_NONE; +} + +/* little-endian input routines */ +UINT AIAPI AIOReadChar(LPBYTE lpData) +{ + if (fread(lpData, 1, sizeof(BYTE), lpStream) != sizeof(BYTE)) + memset(lpData, 0, sizeof(BYTE)); + return AUDIO_ERROR_NONE; +} + +UINT AIAPI AIOReadShort(LPWORD lpData) +{ + if (fread(lpData, 1, sizeof(WORD), lpStream) != sizeof(WORD)) + memset(lpData, 0, sizeof(WORD)); +#ifdef __BIGENDIAN__ + *lpData = MAKEWORD(HIBYTE(*lpData), LOBYTE(*lpData)); +#endif + return AUDIO_ERROR_NONE; +} + +UINT AIAPI AIOReadLong(LPDWORD lpData) +{ + if (fread(lpData, 1, sizeof(DWORD), lpStream) != sizeof(DWORD)) + memset(lpData, 0, sizeof(DWORD)); +#ifdef __BIGENDIAN__ + *lpData = MAKELONG( + MAKEWORD(HIBYTE(HIWORD(*lpData)), LOBYTE(HIWORD(*lpData))), + MAKEWORD(HIBYTE(LOWORD(*lpData)), LOBYTE(LOWORD(*lpData)))); +#endif + return AUDIO_ERROR_NONE; +} + +/* big-endian input routines */ +UINT AIAPI AIOReadCharM(LPBYTE lpData) +{ + if (fread(lpData, 1, sizeof(BYTE), lpStream) != sizeof(BYTE)) + memset(lpData, 0, sizeof(BYTE)); + return AUDIO_ERROR_NONE; +} + +UINT AIAPI AIOReadShortM(LPWORD lpData) +{ + if (fread(lpData, 1, sizeof(WORD), lpStream) != sizeof(WORD)) + memset(lpData, 0, sizeof(WORD)); +#ifndef __BIGENDIAN__ + *lpData = MAKEWORD(HIBYTE(*lpData), LOBYTE(*lpData)); +#endif + return AUDIO_ERROR_NONE; +} + +UINT AIAPI AIOReadLongM(LPDWORD lpData) +{ + if (fread(lpData, 1, sizeof(DWORD), lpStream) != sizeof(DWORD)) + memset(lpData, 0, sizeof(DWORD)); +#ifndef __BIGENDIAN__ + *lpData = MAKELONG( + MAKEWORD(HIBYTE(HIWORD(*lpData)), LOBYTE(HIWORD(*lpData))), + MAKEWORD(HIBYTE(LOWORD(*lpData)), LOBYTE(LOWORD(*lpData)))); +#endif + return AUDIO_ERROR_NONE; +} diff --git a/seal-hack/src/iofile.h b/seal-hack/src/iofile.h new file mode 100644 index 0000000..9d034b8 --- /dev/null +++ b/seal-hack/src/iofile.h @@ -0,0 +1,43 @@ +/* + * $Id: iofile.h 1.6 1996/09/13 16:30:26 chasan released $ + * + * Input/Output file stream routines. + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __IOFILE_H +#define __IOFILE_H + +#ifdef __GNUC__ +#include +#include +#else +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + UINT AIAPI AIOOpenFile(LPSTR lpszFileName); + UINT AIAPI AIOCloseFile(VOID); + UINT AIAPI AIOSeekFile(LONG dwOffset, UINT nWhere); + UINT AIAPI AIOReadFile(LPVOID lpData, UINT nSize); + UINT AIAPI AIOReadChar(LPBYTE lpData); + UINT AIAPI AIOReadShort(LPWORD lpData); + UINT AIAPI AIOReadLong(LPDWORD lpData); + UINT AIAPI AIOReadCharM(LPBYTE lpData); + UINT AIAPI AIOReadShortM(LPWORD lpData); + UINT AIAPI AIOReadLongM(LPDWORD lpData); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/seal-hack/src/lnxdrv.c b/seal-hack/src/lnxdrv.c new file mode 100644 index 0000000..faae2f3 --- /dev/null +++ b/seal-hack/src/lnxdrv.c @@ -0,0 +1,144 @@ +/* + * $Id: lnxdrv.c 1.5 1996/08/05 18:51:19 chasan released $ + * + * Linux's Voxware audio driver. + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#ifdef __LINUX__ +#include +#endif +#ifdef __FREEBSD__ +#include +#endif +#include "audio.h" +#include "drivers.h" + + +/* + * Linux driver buffer fragments defines + */ +#define NUMFRAGS 16 +#define FRAGSIZE 12 +#define BUFFERSIZE (1 << FRAGSIZE) + +/* + * Linux driver configuration structure + */ +static struct { + int nHandle; + BYTE aBuffer[BUFFERSIZE]; + LPFNAUDIOWAVE lpfnAudioWave; + WORD wFormat; +} Audio; + + +/* + * Linux driver API interface + */ +static UINT AIAPI GetAudioCaps(LPAUDIOCAPS lpCaps) +{ + static AUDIOCAPS Caps = + { + AUDIO_PRODUCT_LINUX, "Linux Voxware", + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_1M16 | AUDIO_FORMAT_1S16 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_2M16 | AUDIO_FORMAT_2S16 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 | + AUDIO_FORMAT_4M16 | AUDIO_FORMAT_4S16 + }; + + memcpy(lpCaps, &Caps, sizeof(AUDIOCAPS)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI PingAudio(VOID) +{ + return access("/dev/dsp", W_OK) ? AUDIO_ERROR_NODEVICE : AUDIO_ERROR_NONE; +} + +static UINT AIAPI OpenAudio(LPAUDIOINFO lpInfo) +{ + int nBitsPerSample, nStereoOn, nSampleRate, nFrags; + + memset(&Audio, 0, sizeof(Audio)); + + /* try to open DSP audio device for playback */ + if ((Audio.nHandle = open("/dev/dsp", O_WRONLY | O_NDELAY)) < 0) + return AUDIO_ERROR_DEVICEBUSY; + + /* setup number and size of buffer fragments */ + nFrags = (NUMFRAGS << 16) + (FRAGSIZE); + ioctl(Audio.nHandle, SNDCTL_DSP_SETFRAGMENT, &nFrags); + + /* setup audio playback encoding format and sampling frequency */ + nBitsPerSample = lpInfo->wFormat & AUDIO_FORMAT_16BITS ? 16 : 8; + nStereoOn = lpInfo->wFormat & AUDIO_FORMAT_STEREO ? 1 : 0; + nSampleRate = lpInfo->nSampleRate; + if (ioctl(Audio.nHandle, SNDCTL_DSP_SAMPLESIZE, &nBitsPerSample) < 0 || + ioctl(Audio.nHandle, SNDCTL_DSP_STEREO, &nStereoOn) < 0 || + ioctl(Audio.nHandle, SNDCTL_DSP_SPEED, &nSampleRate) < 0) { + close(Audio.nHandle); + return AUDIO_ERROR_BADFORMAT; + } + + Audio.wFormat = lpInfo->wFormat; + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI CloseAudio(VOID) +{ + /* close DSP audio device */ + close(Audio.nHandle); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudio(UINT nFrames) +{ + /* compute frame size */ + if (Audio.wFormat & AUDIO_FORMAT_16BITS) nFrames <<= 1; + if (Audio.wFormat & AUDIO_FORMAT_STEREO) nFrames <<= 1; + if (nFrames <= 0 || nFrames > sizeof(Audio.aBuffer)) + nFrames = sizeof(Audio.aBuffer); + + /* send PCM samples to the DSP audio device */ + if (Audio.lpfnAudioWave != NULL) { + Audio.lpfnAudioWave(Audio.aBuffer, nFrames); + write(Audio.nHandle, Audio.aBuffer, nFrames); + } + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + /* set up DSP audio device user's callback function */ + Audio.lpfnAudioWave = lpfnAudioWave; + return AUDIO_ERROR_NONE; +} + + +/* + * Linux driver public interface + */ +AUDIOWAVEDRIVER LinuxWaveDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudio, SetAudioCallback +}; + +AUDIODRIVER LinuxDriver = +{ + &LinuxWaveDriver, NULL +}; diff --git a/seal-hack/src/mixdrv.c b/seal-hack/src/mixdrv.c new file mode 100644 index 0000000..2b2adec --- /dev/null +++ b/seal-hack/src/mixdrv.c @@ -0,0 +1,906 @@ +/* + * $Id: mixdrv.c 1.13 1996/09/08 21:14:54 chasan released $ + * 1.14 1998/10/24 18:20:53 chasan released (Mixer API) + * + * Software-based waveform synthesizer emulator driver. + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#define __FILTER__ + +#ifdef __GNUC__ +#include +#define cdecl +#endif +#include +#include +#include "audio.h" +#include "drivers.h" + + +/* + * Voice control bit fields + */ +#define VOICE_STOP 0x01 +#define VOICE_16BITS 0x02 +#define VOICE_LOOP 0x04 +#define VOICE_BIDILOOP 0x08 +#define VOICE_REVERSE 0x10 + +/* + * Voice pitch accurary and mixing buffer size + */ +#define ACCURACY 12 +#define BUFFERSIZE 512 + + +/* + * Waveform synthesizer voice structure + */ +typedef struct { + LPVOID lpData; + LONG dwAccum; + LONG dwFrequency; + LONG dwLoopStart; + LONG dwLoopEnd; + BYTE nVolume; + BYTE nPanning; + BYTE bControl; + BYTE bReserved; +} VOICE, *LPVOICE; + +/* + * Low level voice mixing routine prototype + */ +typedef VOID (cdecl* LPFNMIXAUDIO)(LPLONG, UINT, LPVOICE); + +/* + * Waveform synthesizer state structure + */ +static struct { + VOICE aVoices[AUDIO_MAX_VOICES]; + UINT nVoices; + UINT wFormat; + UINT nSampleRate; + LONG dwTimerRate; + LONG dwTimerAccum; + LPBYTE lpMemory; + LPFNAUDIOTIMER lpfnAudioTimer; + LPFNMIXAUDIO lpfnMixAudioProc[2]; +} Synth; + +LPLONG lpVolumeTable; +LPBYTE lpFilterTable; + +static VOID AIAPI UpdateVoices(LPBYTE lpData, UINT nCount); + +/* low level resamplation and quantization routines */ +#ifdef __ASM__ + +VOID cdecl QuantAudioData08(LPVOID lpBuffer, LPLONG lpData, UINT nCount); +VOID cdecl QuantAudioData16(LPVOID lpBuffer, LPLONG lpData, UINT nCount); +VOID cdecl MixAudioData08M(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice); +VOID cdecl MixAudioData08S(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice); +VOID cdecl MixAudioData08MI(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice); +VOID cdecl MixAudioData08SI(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice); +VOID cdecl MixAudioData16M(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice); +VOID cdecl MixAudioData16S(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice); +VOID cdecl MixAudioData16MI(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice); +VOID cdecl MixAudioData16SI(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice); + +static VOID QuantAudioData(LPVOID lpBuffer, LPLONG lpData, UINT nCount) +{ + if (Synth.wFormat & AUDIO_FORMAT_16BITS) + QuantAudioData16(lpBuffer, lpData, nCount); + else + QuantAudioData08(lpBuffer, lpData, nCount); +} + +#else + +typedef short SHORT; +typedef SHORT* LPSHORT; + +static VOID QuantAudioData(LPVOID lpBuffer, LPLONG lpData, UINT nCount) +{ + LPSHORT lpwBuffer; + LPBYTE lpbBuffer; + LONG dwSample; + + if (Synth.wFormat & AUDIO_FORMAT_16BITS) { + lpwBuffer = (LPSHORT) lpBuffer; + while (nCount-- > 0) { + dwSample = *lpData++; + if (dwSample < -32768) + dwSample = -32768; + else if (dwSample > +32767) + dwSample = +32767; + *lpwBuffer++ = (SHORT) dwSample; + } + } + else { + lpbBuffer = (LPBYTE) lpBuffer; + while (nCount-- > 0) { + dwSample = *lpData++; + if (dwSample < -32768) + dwSample = -32768; + else if (dwSample > +32767) + dwSample = +32767; + *lpbBuffer++ = (BYTE) ((dwSample >> 8) + 128); + } + } +} + +static VOID AIAPI +MixAudioData08M(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) +{ + register UINT count; + register DWORD accum, delta; + register LPLONG table, buf; + register LPBYTE data; + + accum = lpVoice->dwAccum; + delta = lpVoice->dwFrequency; + table = lpVolumeTable + ((UINT) lpVoice->nVolume << 8); + data = lpVoice->lpData; + buf = lpBuffer; + count = nCount; + + do { + *buf++ += table[data[accum >> ACCURACY]]; + accum += delta; + } while (--count != 0); + + lpVoice->dwAccum = accum; +} + +#define min(a, b) ((a) < (b) ? (a) : (b)) + +static VOID AIAPI +MixAudioData08S(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) +{ + register UINT a; + register DWORD accum, delta; + register LPLONG ltable, rtable, buf; + register LPBYTE data; + + accum = lpVoice->dwAccum; + delta = lpVoice->dwFrequency; + a = ((UINT) lpVoice->nVolume * lpVoice->nPanning) >> 8; + rtable = lpVolumeTable + (a << 8); + ltable = lpVolumeTable + ((lpVoice->nVolume - a) << 8); + data = lpVoice->lpData; + buf = lpBuffer; + + do { + a = data[accum >> ACCURACY]; + buf[0] += ltable[a]; + buf[1] += rtable[a]; + accum += delta; + buf += 2; + } while (--nCount != 0); + + lpVoice->dwAccum = accum; +} + +static VOID AIAPI +MixAudioData08MI(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) +{ + register INT a, frac; + register DWORD accum, delta; + register LPLONG table, buf; + register LPBYTE data, ftable; + + /* adaptive oversampling interpolation comparison */ + if (lpVoice->dwFrequency < -(1 << ACCURACY) || + lpVoice->dwFrequency > +(1 << ACCURACY)) { + MixAudioData08M(lpBuffer, nCount, lpVoice); + return; + } + + accum = lpVoice->dwAccum; + delta = lpVoice->dwFrequency; + table = lpVolumeTable + ((UINT) lpVoice->nVolume << 8); + data = lpVoice->lpData; + buf = lpBuffer; + +#ifdef __FILTER__ + a = (BYTE) lpVoice->bReserved; + frac = ((long) delta < 0 ? -delta : +delta) >> (ACCURACY - 5); + ftable = lpFilterTable + (frac << 8); + do { + a = (BYTE)(a + ftable[data[accum >> ACCURACY]] - ftable[a]); + *buf++ += table[a]; + accum += delta; + } while (--nCount != 0); + lpVoice->bReserved = (BYTE) a; +#else + do { + register INT b; + a = (signed char) data[accum >> ACCURACY]; + b = (signed char) data[(accum >> ACCURACY) + 1]; + frac = (accum & ((1 << ACCURACY) - 1)) >> (ACCURACY - 5); + a = (BYTE)(a + ((frac * (b - a)) >> 5)); + *buf++ += table[a]; + accum += delta; + } while (--nCount != 0); +#endif + + lpVoice->dwAccum = accum; +} + +static VOID AIAPI +MixAudioData08SI(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) +{ + register INT a, frac; + register DWORD accum, delta; + register LPLONG buf, ltable, rtable; + register LPBYTE data, ftable; + + /* adaptive oversampling interpolation comparison */ + if (lpVoice->dwFrequency < -(1 << ACCURACY) || + lpVoice->dwFrequency > +(1 << ACCURACY)) { + MixAudioData08S(lpBuffer, nCount, lpVoice); + return; + } + + accum = lpVoice->dwAccum; + delta = lpVoice->dwFrequency; + a = ((UINT) lpVoice->nVolume * lpVoice->nPanning) >> 8; + rtable = lpVolumeTable + (a << 8); + ltable = lpVolumeTable + ((lpVoice->nVolume - a) << 8); + data = lpVoice->lpData; + buf = lpBuffer; + +#ifdef __FILTER__ + a = (BYTE) lpVoice->bReserved; + frac = ((long) delta < 0 ? -delta : +delta) >> (ACCURACY - 5); + ftable = lpFilterTable + (frac << 8); + do { + a = (BYTE)(a + ftable[data[accum >> ACCURACY]] - ftable[a]); + buf[0] += ltable[a]; + buf[1] += rtable[a]; + accum += delta; + buf += 2; + } while (--nCount != 0); + lpVoice->bReserved = (BYTE) a; +#else + do { + register INT b; + a = (signed char) data[accum >> ACCURACY]; + b = (signed char) data[(accum >> ACCURACY) + 1]; + frac = (accum & ((1 << ACCURACY) - 1)) >> (ACCURACY - 5); + a = (BYTE)(a + ((frac * (b - a)) >> 5)); + buf[0] += ltable[a]; + buf[1] += rtable[a]; + accum += delta; + buf += 2; + } while (--nCount != 0); +#endif + + lpVoice->dwAccum = accum; +} + +static VOID AIAPI +MixAudioData16M(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) +{ + register UINT a, count; + register DWORD accum, delta; + register LPLONG table, buf; + register LPWORD data; + + accum = lpVoice->dwAccum; + delta = lpVoice->dwFrequency; + table = lpVolumeTable + ((UINT) lpVoice->nVolume << 8); + data = lpVoice->lpData; + buf = lpBuffer; + count = nCount; + + do { + a = data[accum >> ACCURACY]; + *buf++ += table[a >> 8]; + accum += delta; + } while (--count != 0); + + lpVoice->dwAccum = accum; +} + +static VOID AIAPI +MixAudioData16S(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) +{ + register UINT a; + register DWORD accum, delta; + register LPLONG ltable, rtable, buf; + register LPWORD data; + + accum = lpVoice->dwAccum; + delta = lpVoice->dwFrequency; + a = ((UINT) lpVoice->nVolume * lpVoice->nPanning) >> 8; + rtable = lpVolumeTable + (a << 8); + ltable = lpVolumeTable + ((lpVoice->nVolume - a) << 8); + data = lpVoice->lpData; + buf = lpBuffer; + + do { + a = data[accum >> ACCURACY]; + buf[0] += ltable[a >> 8]; + buf[1] += rtable[a >> 8]; + accum += delta; + buf += 2; + } while (--nCount != 0); + + lpVoice->dwAccum = accum; +} + + +static VOID AIAPI +MixAudioData16MI(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) +{ + register UINT frac, count; + register DWORD a, b, accum, delta; + register LPLONG table, buf; + register LPWORD data; + + /* adaptive oversampling interpolation comparison */ + if (lpVoice->dwFrequency < -(1 << ACCURACY) || + lpVoice->dwFrequency > +(1 << ACCURACY)) { + MixAudioData16M(lpBuffer, nCount, lpVoice); + return; + } + + accum = lpVoice->dwAccum; + delta = lpVoice->dwFrequency; + table = lpVolumeTable + ((UINT) lpVoice->nVolume << 8); + data = lpVoice->lpData; + buf = lpBuffer; + count = nCount; + + do { + a = data[accum >> ACCURACY]; + b = data[(accum >> ACCURACY) + 1]; + frac = (accum & ((1 << ACCURACY) - 1)) >> (ACCURACY - 5); + a = (WORD)((SHORT)a + ((frac * ((SHORT)b - (SHORT)a)) >> 5)); + *buf++ += table[a >> 8]; + accum += delta; + } while (--count != 0); + + lpVoice->dwAccum = accum; +} + +static VOID AIAPI +MixAudioData16SI(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) +{ + register UINT frac; + register DWORD a, b, accum, delta; + register LPLONG ltable, rtable, buf; + register LPWORD data; + + /* adaptive oversampling interpolation comparison */ + if (lpVoice->dwFrequency < -(1 << ACCURACY) || + lpVoice->dwFrequency > +(1 << ACCURACY)) { + MixAudioData16S(lpBuffer, nCount, lpVoice); + return; + } + + accum = lpVoice->dwAccum; + delta = lpVoice->dwFrequency; + a = ((UINT) lpVoice->nVolume * lpVoice->nPanning) >> 8; + rtable = lpVolumeTable + (a << 8); + ltable = lpVolumeTable + ((lpVoice->nVolume - a) << 8); + data = lpVoice->lpData; + buf = lpBuffer; + + do { + a = data[accum >> ACCURACY]; + b = data[(accum >> ACCURACY) + 1]; + frac = (accum & ((1 << ACCURACY) - 1)) >> (ACCURACY - 5); + a = (WORD)((SHORT)a + ((frac * ((int)(SHORT)b - (int)(SHORT)a)) >> 5)); + buf[0] += ltable[a >> 8]; + buf[1] += rtable[a >> 8]; + accum += delta; + buf += 2; + } while (--nCount != 0); + + lpVoice->dwAccum = accum; +} + +#endif + +static VOID MixAudioData(LPLONG lpBuffer, UINT nCount, LPVOICE lpVoice) +{ + UINT nSize; + + if (Synth.wFormat & AUDIO_FORMAT_STEREO) + nCount >>= 1; + + while (nCount > 0 && !(lpVoice->bControl & VOICE_STOP)) { + /* check boundary conditions */ + if (lpVoice->bControl & VOICE_REVERSE) { + if (lpVoice->dwAccum < lpVoice->dwLoopStart) { + if (lpVoice->bControl & VOICE_BIDILOOP) { + lpVoice->dwAccum = lpVoice->dwLoopStart + + (lpVoice->dwLoopStart - lpVoice->dwAccum); + lpVoice->bControl ^= VOICE_REVERSE; + continue; + } + else if (lpVoice->bControl & VOICE_LOOP) { + lpVoice->dwAccum = lpVoice->dwLoopEnd - + (lpVoice->dwLoopStart - lpVoice->dwAccum); + continue; + } + else { + lpVoice->bControl |= VOICE_STOP; + break; + } + } + } + else { + if (lpVoice->dwAccum > lpVoice->dwLoopEnd) { + if (lpVoice->bControl & VOICE_BIDILOOP) { + lpVoice->dwAccum = lpVoice->dwLoopEnd - + (lpVoice->dwAccum - lpVoice->dwLoopEnd); + lpVoice->bControl ^= VOICE_REVERSE; + continue; + } + else if (lpVoice->bControl & VOICE_LOOP) { + lpVoice->dwAccum = lpVoice->dwLoopStart + + (lpVoice->dwAccum - lpVoice->dwLoopEnd); + continue; + } + else { + lpVoice->bControl |= VOICE_STOP; + break; + } + } + } + + /* check for overflow and clip if necessary */ + nSize = nCount; + if (lpVoice->bControl & VOICE_REVERSE) { + if (nSize * lpVoice->dwFrequency > + lpVoice->dwAccum - lpVoice->dwLoopStart) + nSize = (lpVoice->dwAccum - lpVoice->dwLoopStart + + lpVoice->dwFrequency) / lpVoice->dwFrequency; + } + else { + if (nSize * lpVoice->dwFrequency > + lpVoice->dwLoopEnd - lpVoice->dwAccum) + nSize = (lpVoice->dwLoopEnd - lpVoice->dwAccum + + lpVoice->dwFrequency) / lpVoice->dwFrequency; + } + + if (lpVoice->bControl & VOICE_REVERSE) + lpVoice->dwFrequency = -lpVoice->dwFrequency; + + /* mixes chunk of data in a burst mode */ + if (lpVoice->bControl & VOICE_16BITS) { + Synth.lpfnMixAudioProc[1] (lpBuffer, nSize, lpVoice); + } + else { + Synth.lpfnMixAudioProc[0] (lpBuffer, nSize, lpVoice); + } + + if (lpVoice->bControl & VOICE_REVERSE) + lpVoice->dwFrequency = -lpVoice->dwFrequency; + + /* update mixing buffer address and counter */ + lpBuffer += nSize; + if (Synth.wFormat & AUDIO_FORMAT_STEREO) + lpBuffer += nSize; + nCount -= nSize; + } +} + +static VOID MixAudioVoices(LPLONG lpBuffer, UINT nCount) +{ + UINT nVoice, nSize; + + while (nCount > 0) { + nSize = nCount; + if (Synth.lpfnAudioTimer != NULL) { + nSize = (Synth.dwTimerRate - Synth.dwTimerAccum + 64L) & ~63L; + if (nSize > nCount) + nSize = nCount; + if ((Synth.dwTimerAccum += nSize) >= Synth.dwTimerRate) { + Synth.dwTimerAccum -= Synth.dwTimerRate; + Synth.lpfnAudioTimer(); + } + } + for (nVoice = 0; nVoice < Synth.nVoices; nVoice++) { + MixAudioData(lpBuffer, nSize, &Synth.aVoices[nVoice]); + } + lpBuffer += nSize; + nCount -= nSize; + } +} + + +/* + * High level waveform synthesizer interface + */ +static UINT AIAPI GetAudioCaps(LPAUDIOCAPS lpCaps) +{ + memset(lpCaps, 0, sizeof(AUDIOCAPS)); + return AUDIO_ERROR_NOTSUPPORTED; +} + +static UINT AIAPI PingAudio(VOID) +{ + return AUDIO_ERROR_NOTSUPPORTED; +} + +static UINT AIAPI OpenAudio(LPAUDIOINFO lpInfo) +{ + memset(&Synth, 0, sizeof(Synth)); + Synth.wFormat = lpInfo->wFormat; + Synth.nSampleRate = lpInfo->nSampleRate; + if (Synth.wFormat & AUDIO_FORMAT_FILTER) { + Synth.lpfnMixAudioProc[0] = (Synth.wFormat & AUDIO_FORMAT_STEREO) ? + MixAudioData08SI : MixAudioData08MI; + Synth.lpfnMixAudioProc[1] = (Synth.wFormat & AUDIO_FORMAT_STEREO) ? + MixAudioData16SI : MixAudioData16MI; + } + else { + Synth.lpfnMixAudioProc[0] = (Synth.wFormat & AUDIO_FORMAT_STEREO) ? + MixAudioData08S : MixAudioData08M; + Synth.lpfnMixAudioProc[1] = (Synth.wFormat & AUDIO_FORMAT_STEREO) ? + MixAudioData16S : MixAudioData16M; + } + + /* allocate volume (0-64) and filter (0-31) table */ + Synth.lpMemory = malloc(sizeof(LONG) * 65 * 256 + + sizeof(BYTE) * 32 * 256 + 1023); + if (Synth.lpMemory != NULL) { + lpVolumeTable = (LPLONG) (((DWORD) Synth.lpMemory + 1023) & ~1023); + lpFilterTable = (LPBYTE) (lpVolumeTable + 65 * 256); + ASetAudioMixerValue(AUDIO_MIXER_MASTER_VOLUME, 96); + ASetAudioCallback(UpdateVoices); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_NOMEMORY; +} + +static UINT AIAPI CloseAudio(VOID) +{ + if (Synth.lpMemory != NULL) + free(Synth.lpMemory); + memset(&Synth, 0, sizeof(Synth)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioMixerValue(UINT nChannel, UINT nMixerValue) +{ + LPBYTE lpFilter; + LPLONG lpVolume; + UINT nVolume, nSample; + LONG dwAccum, dwDelta; + + if (Synth.lpMemory == NULL) + return AUDIO_ERROR_NOTSUPPORTED; + + /* master volume must be less than 256 units */ + if (nChannel != AUDIO_MIXER_MASTER_VOLUME || nMixerValue > 256) + return AUDIO_ERROR_INVALPARAM; + + /* half dynamic range for mono output */ + if (!(Synth.wFormat & AUDIO_FORMAT_STEREO)) + nMixerValue >>= 1; + + /* build volume table (0-64) */ + lpVolume = lpVolumeTable; + dwDelta = 0; + for (nVolume = 0; nVolume <= 64; nVolume++, dwDelta += nMixerValue) { + dwAccum = 0; + for (nSample = 0; nSample < 128; nSample++, dwAccum += dwDelta) + *lpVolume++ = dwAccum >> 4; + dwAccum = -dwAccum; + for (nSample = 0; nSample < 128; nSample++, dwAccum += dwDelta) + *lpVolume++ = dwAccum >> 4; + } + +#ifdef __FILTER__ + /* build lowpass filter table (0-31) */ + lpFilter = lpFilterTable; + for (nVolume = 0; nVolume < 32; nVolume++) { + dwAccum = 0; + for (nSample = 0; nSample < 128; nSample++, dwAccum += nVolume) + *lpFilter++ = dwAccum >> 5; + dwAccum = -dwAccum; + for (nSample = 0; nSample < 128; nSample++, dwAccum += nVolume) + *lpFilter++ = dwAccum >> 5; + } +#endif + + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI OpenVoices(UINT nVoices) +{ + UINT nVoice; + + /* + * Initialize waveform synthesizer structure for playback + */ + if (nVoices >= 1 && nVoices <= AUDIO_MAX_VOICES) { + Synth.nVoices = nVoices; + for (nVoice = 0; nVoice < Synth.nVoices; nVoice++) + Synth.aVoices[nVoice].bControl = VOICE_STOP; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; +} + +static UINT AIAPI CloseVoices(VOID) +{ + UINT nVoice; + + memset(Synth.aVoices, 0, sizeof(Synth.aVoices)); + for (nVoice = 0; nVoice < AUDIO_MAX_VOICES; nVoice++) + Synth.aVoices[nVoice].bControl = VOICE_STOP; + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudio(VOID) +{ + return AUDIO_ERROR_NONE; +} + +static LONG AIAPI GetAudioDataAvail(VOID) +{ + return 0; +} + +static UINT AIAPI CreateAudioData(LPAUDIOWAVE lpWave) +{ + if (lpWave != NULL) { + lpWave->dwHandle = (DWORD) lpWave->lpData; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI DestroyAudioData(LPAUDIOWAVE lpWave) +{ + if (lpWave != NULL && lpWave->dwHandle != 0) { + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI WriteAudioData(LPAUDIOWAVE lpWave, DWORD dwOffset, UINT nCount) +{ + if (lpWave != NULL && lpWave->dwHandle != 0) { + /* anticlick removal work around */ + if (lpWave->wFormat & AUDIO_FORMAT_LOOP) { + *(LPDWORD) (lpWave->dwHandle + lpWave->dwLoopEnd) = + *(LPDWORD) (lpWave->dwHandle + lpWave->dwLoopStart); + } + else if (dwOffset + nCount >= lpWave->dwLength) { + *(LPDWORD) (lpWave->dwHandle + lpWave->dwLength) = 0; + } + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI PrimeVoice(UINT nVoice, LPAUDIOWAVE lpWave) +{ + LPVOICE lpVoice; + + if (nVoice < Synth.nVoices && lpWave != NULL && lpWave->dwHandle != 0) { + lpVoice = &Synth.aVoices[nVoice]; + lpVoice->lpData = (LPVOID) lpWave->dwHandle; + lpVoice->bControl = VOICE_STOP; + lpVoice->dwAccum = 0; + if (lpWave->wFormat & (AUDIO_FORMAT_LOOP | AUDIO_FORMAT_BIDILOOP)) { + lpVoice->dwLoopStart = lpWave->dwLoopStart; + lpVoice->dwLoopEnd = lpWave->dwLoopEnd; + lpVoice->bControl |= VOICE_LOOP; + if (lpWave->wFormat & AUDIO_FORMAT_BIDILOOP) + lpVoice->bControl |= VOICE_BIDILOOP; + } + else { + lpVoice->dwLoopStart = lpWave->dwLength; + lpVoice->dwLoopEnd = lpWave->dwLength; + } + if (lpWave->wFormat & AUDIO_FORMAT_16BITS) { + lpVoice->dwLoopStart >>= 1; + lpVoice->dwLoopEnd >>= 1; + lpVoice->bControl |= VOICE_16BITS; + } + lpVoice->dwAccum <<= ACCURACY; + lpVoice->dwLoopStart <<= ACCURACY; + lpVoice->dwLoopEnd <<= ACCURACY; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI StartVoice(UINT nVoice) +{ + if (nVoice < Synth.nVoices) { + Synth.aVoices[nVoice].bControl &= ~VOICE_STOP; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI StopVoice(UINT nVoice) +{ + if (nVoice < Synth.nVoices) { + Synth.aVoices[nVoice].bControl |= VOICE_STOP; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; + +} + +static UINT AIAPI SetVoicePosition(UINT nVoice, LONG dwPosition) +{ + if (nVoice < Synth.nVoices) { + dwPosition <<= ACCURACY; + if (dwPosition >= 0 && dwPosition < Synth.aVoices[nVoice].dwLoopEnd) { + Synth.aVoices[nVoice].dwAccum = dwPosition; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI SetVoiceFrequency(UINT nVoice, LONG dwFrequency) +{ + if (nVoice < Synth.nVoices) { + if (dwFrequency >= AUDIO_MIN_FREQUENCY && + dwFrequency <= AUDIO_MAX_FREQUENCY) { + Synth.aVoices[nVoice].dwFrequency = ((dwFrequency << ACCURACY) + + (Synth.nSampleRate >> 1)) / Synth.nSampleRate; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI SetVoiceVolume(UINT nVoice, UINT nVolume) +{ + if (nVoice < Synth.nVoices) { + if (nVolume <= AUDIO_MAX_VOLUME) { + Synth.aVoices[nVoice].nVolume = nVolume >> 1; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI SetVoicePanning(UINT nVoice, UINT nPanning) +{ + if (nVoice < Synth.nVoices) { + if (nPanning <= AUDIO_MAX_PANNING) { + Synth.aVoices[nVoice].nPanning = nPanning; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoicePosition(UINT nVoice, LPLONG lpdwPosition) +{ + if (nVoice < Synth.nVoices) { + if (lpdwPosition != NULL) { + *lpdwPosition = Synth.aVoices[nVoice].dwAccum >> ACCURACY; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoiceFrequency(UINT nVoice, LPLONG lpdwFrequency) +{ + if (nVoice < Synth.nVoices) { + if (lpdwFrequency != NULL) { + *lpdwFrequency = (Synth.aVoices[nVoice].dwFrequency * + Synth.nSampleRate) >> ACCURACY; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoiceVolume(UINT nVoice, LPUINT lpnVolume) +{ + if (nVoice < Synth.nVoices) { + if (lpnVolume != NULL) { + *lpnVolume = Synth.aVoices[nVoice].nVolume << 1; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoicePanning(UINT nVoice, LPUINT lpnPanning) +{ + if (nVoice < Synth.nVoices) { + if (lpnPanning != NULL) { + *lpnPanning = Synth.aVoices[nVoice].nPanning; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoiceStatus(UINT nVoice, LPBOOL lpnStatus) +{ + if (nVoice < Synth.nVoices) { + if (lpnStatus != NULL) { + *lpnStatus = (Synth.aVoices[nVoice].bControl & VOICE_STOP) != 0; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI SetAudioTimerProc(LPFNAUDIOTIMER lpfnAudioTimer) +{ + Synth.lpfnAudioTimer = lpfnAudioTimer; + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioTimerRate(UINT nBPM) +{ + if (nBPM >= 0x20 && nBPM <= 0xFF) { + Synth.dwTimerRate = Synth.nSampleRate; + if (Synth.wFormat & AUDIO_FORMAT_STEREO) + Synth.dwTimerRate <<= 1; + Synth.dwTimerRate = (5 * Synth.dwTimerRate) / (2 * nBPM); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; +} + +static VOID AIAPI UpdateVoices(LPBYTE lpData, UINT nCount) +{ + static LONG aBuffer[BUFFERSIZE]; + UINT nSamples; + + if (Synth.wFormat & AUDIO_FORMAT_16BITS) + nCount >>= 1; + while (nCount > 0) { + if ((nSamples = nCount) > BUFFERSIZE) + nSamples = BUFFERSIZE; + memset(aBuffer, 0, nSamples << 2); + MixAudioVoices(aBuffer, nSamples); + QuantAudioData(lpData, aBuffer, nSamples); + lpData += nSamples << ((Synth.wFormat & AUDIO_FORMAT_16BITS) != 0); + nCount -= nSamples; + } +} + + +/* + * Waveform synthesizer public interface + */ +AUDIOSYNTHDRIVER EmuSynthDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudio, OpenVoices, CloseVoices, + SetAudioTimerProc, SetAudioTimerRate, SetAudioMixerValue, + GetAudioDataAvail, CreateAudioData, DestroyAudioData, + WriteAudioData, PrimeVoice, StartVoice, StopVoice, + SetVoicePosition, SetVoiceFrequency, SetVoiceVolume, + SetVoicePanning, GetVoicePosition, GetVoiceFrequency, + GetVoiceVolume, GetVoicePanning, GetVoiceStatus +}; diff --git a/seal-hack/src/modeng.c b/seal-hack/src/modeng.c new file mode 100644 index 0000000..918d009 --- /dev/null +++ b/seal-hack/src/modeng.c @@ -0,0 +1,1651 @@ +/* + * $Id: modeng.c 1.11 1996/09/13 15:10:01 chasan released $ + * + * Extended module player engine. + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifdef __GNUC__ +#include +#endif +#include +#include +#include "audio.h" +#include "tables.h" + + +/* + * Module player state control bit fields + */ +#define AUDIO_PLAYER_JUMP 0x01 +#define AUDIO_PLAYER_BREAK 0x02 +#define AUDIO_PLAYER_DELAY 0x04 +#define AUDIO_PLAYER_BPM 0x08 +#define AUDIO_PLAYER_VOLUME 0x10 +#define AUDIO_PLAYER_PAUSE 0x20 +#define AUDIO_PLAYER_ACTIVE 0x80 + + +/* + * Tracks control bit fields + */ +#define AUDIO_CTRL_PITCH 0x01 +#define AUDIO_CTRL_VOLUME 0x02 +#define AUDIO_CTRL_PANNING 0x04 +#define AUDIO_CTRL_KEYON 0x08 +#define AUDIO_CTRL_KEYOFF 0x10 +#define AUDIO_CTRL_TOUCH 0x20 + +/* + * Some useful macro defines + */ +#define LOPARAM(x) ((BYTE)(x)&0x0F) +#define HIPARAM(x) ((BYTE)(x)>>4) +#define CLIP(x,a,b) ((x)<(a)?(a):((x)>(b)?(b):(x))) +#define ABS(x) ((x)>0?(x):-(x)) + + +/* + * Module player track structure + */ +typedef struct { + BYTE nNote; /* note index (1-96) */ + BYTE nPatch; /* patch number (1-128) */ + BYTE nVolume; /* volume command */ + BYTE nCommand; /* effect */ + BYTE bParams; /* parameters */ +} NOTE, *LPNOTE; + +typedef struct { + BYTE fKeyOn; /* key on flag */ + BYTE bControl; /* control bits */ + BYTE nVolumeCmd; /* volume command */ + BYTE nCommand; /* command */ + BYTE bParams; /* parameters */ + BYTE nPatch; /* patch number */ + BYTE nSample; /* sample number */ + BYTE nNote; /* current note */ + int nFinetune; /* current finetune */ + int nRelativeNote; /* relative note */ + int nVolume; /* current volume */ + int nOutVolume; /* output volume */ + int nFinalVolume; /* final volume */ + int nPanning; /* current panning */ + int nFinalPanning; /* final panning */ + int nPeriod; /* current period */ + int nOutPeriod; /* output period */ + int nFinalPeriod; /* final period */ + LONG dwFrequency; /* frequency */ + + LPAUDIOPATCH lpPatch; /* current patch */ + LPAUDIOSAMPLE lpSample; /* current sample */ + + /* waves & gliss control */ + BYTE bWaveCtrl; /* vibrato & tremolo control bits */ + BYTE bGlissCtrl; /* glissando control bits */ + + /* vibrato & tremolo waves */ + int nVibratoFrame; /* vibrato frame */ + int nVibratoDepth; /* vibrato depth */ + int nVibratoRate; /* vibrato rate */ + + int nTremoloFrame; /* tremolo frame */ + int nTremoloDepth; /* tremolo depth */ + int nTremoloRate; /* tremolo rate */ + + /* command parameters */ + int nPortaUp; /* portamento up rate */ + int nPortaDown; /* portamento down rate */ + int nTonePorta; /* tone portamento rate */ + int nWantedPeriod; /* tone portamento target */ + BYTE bVolumeSlide; /* volume slide rate */ + BYTE bPanningSlide; /* panning slide rate */ + BYTE nFinePortaUp; /* fine portamento up rate */ + BYTE nFinePortaDown; /* fine portamento down rate */ + BYTE nExtraPortaUp; /* extra fine porta up rate */ + BYTE nExtraPortaDown; /* extra fine porta down rate */ + BYTE nRetrigType; /* multi retrig type */ + BYTE nRetrigInterval; /* multi retrig interval */ + BYTE nRetrigFrame; /* multi retrig frame */ + BYTE bTremorParms; /* tremor parameters */ + BYTE bTremorOnOff; /* tremor on/off state */ + BYTE nTremorFrame; /* tremor frame */ + LONG dwSampleOffset; /* last sample offset */ + + /* volume fadeout */ + int nVolumeFade; /* volume fadeout level */ + int nVolumeFadeout; /* volume fadeout rate */ + + /* volume envelope */ + int nVolumeFrame; /* volume envelope frame */ + int nVolumeValue; /* volume envelope value */ + int nVolumePoint; /* volume envelope point index */ + int nVolumeSlope; /* volume envelope slope */ + + /* panning envelope */ + int nPanningFrame; /* panning envelope frame */ + int nPanningValue; /* panning envelope value */ + int nPanningPoint; /* panning envelope point index */ + int nPanningSlope; /* panning envelope slope */ + + /* automatic vibrato */ + int nAutoVibratoFrame; /* auto vibrato frame */ + int nAutoVibratoValue; /* auto vibrato envelope */ + int nAutoVibratoSlope; /* auto vibrato slope */ + + /* pattern loop variables */ + int nPatternRow; /* pattern loop row */ + int nPatternLoop; /* pattern loop counter */ +} TRACK, *LPTRACK; + +/* + * Module player run-time state structure + */ +static struct { + LPAUDIOMODULE lpModule; /* current module */ + LPBYTE lpData; /* pattern data pointer */ + TRACK aTracks[32]; /* array of tracks */ + HAC aVoices[32]; /* array of voices */ + WORD wControl; /* player control bits */ + WORD wFlags; /* module control bits */ + int nTracks; /* number of channels */ + int nFrame; /* current frame */ + int nRow; /* pattern row */ + int nRows; /* number of rows */ + int nPattern; /* pattern number */ + int nOrder; /* order number */ + int nTempo; /* current tempo */ + int nBPM; /* current BPM */ + int nVolume; /* global volume */ + int nVolumeRate; /* global volume slide */ + int nJumpOrder; /* position jump */ + int nJumpRow; /* break pattern */ + int nPatternDelay; /* pattern delay counter */ + LPFNAUDIOCALLBACK lpfnCallback; /* sync callback routine */ +} Player; + + +static VOID PlayNote(LPTRACK lpTrack); +static VOID StopNote(LPTRACK lpTrack); +static VOID RetrigNote(LPTRACK lpTrack); + +/* + * Low-level extended module player routines + */ +static LONG GetFrequencyValue(int nPeriod) +{ + UINT nNote, nOctave; + + if (nPeriod > 0) { + if (Player.wFlags & AUDIO_MODULE_LINEAR) { + nOctave = nPeriod / (12 * 16 * 4); + nNote = nPeriod % (12 * 16 * 4); + return aFrequencyTable[nNote] >> nOctave; + } + else { + return (4L * 8363L * 428L) / nPeriod; + } + } + return 0L; +} + +static int GetPeriodValue(int nNote, int nRelativeNote, int nFinetune) +{ + int nOctave; + + nNote = ((nNote + nRelativeNote - 1) << 6) + (nFinetune >> 1); + if (nNote >= 0 && nNote < 10 * 12 * 16 * 4) { + if (Player.wFlags & AUDIO_MODULE_LINEAR) { + return (10 * 12 * 16 * 4 - nNote); + } + else { + nOctave = nNote / (12 * 16 * 4); + nNote = nNote % (12 * 16 * 4); + return aPeriodTable[nNote >> 2] >> nOctave; + } + } + return 0; +} + +static VOID OnArpeggio(LPTRACK lpTrack) +{ + int nNote; + + if (lpTrack->bParams) { + nNote = lpTrack->nNote; + switch (Player.nFrame % 3) { + case 1: + nNote += HIPARAM(lpTrack->bParams); + break; + case 2: + nNote += LOPARAM(lpTrack->bParams); + break; + } + lpTrack->nOutPeriod = GetPeriodValue(nNote, + lpTrack->nRelativeNote, lpTrack->nFinetune); + lpTrack->bControl |= AUDIO_CTRL_PITCH; + } +} + +static VOID OnPortaUp(LPTRACK lpTrack) +{ + if (!Player.nFrame) { + if (lpTrack->bParams != 0x00) { + lpTrack->nPortaUp = (int) lpTrack->bParams << 2; + } + } + else { + lpTrack->nPeriod -= lpTrack->nPortaUp; + if (lpTrack->nPeriod < AUDIO_MIN_PERIOD) + lpTrack->nPeriod = AUDIO_MIN_PERIOD; + lpTrack->nOutPeriod = lpTrack->nPeriod; + lpTrack->bControl |= AUDIO_CTRL_PITCH; + } +} + +static VOID OnPortaDown(LPTRACK lpTrack) +{ + if (!Player.nFrame) { + if (lpTrack->bParams != 0x00) { + lpTrack->nPortaDown = (int) lpTrack->bParams << 2; + } + } + else { + lpTrack->nPeriod += lpTrack->nPortaDown; + if (lpTrack->nPeriod > AUDIO_MAX_PERIOD) + lpTrack->nPeriod = AUDIO_MAX_PERIOD; + lpTrack->nOutPeriod = lpTrack->nPeriod; + lpTrack->bControl |= AUDIO_CTRL_PITCH; + } +} + +static VOID OnTonePorta(LPTRACK lpTrack) +{ + if (!Player.nFrame) { + if (lpTrack->bParams != 0x00) { + lpTrack->nTonePorta = (int) lpTrack->bParams << 2; + } + lpTrack->nWantedPeriod = GetPeriodValue(lpTrack->nNote, + lpTrack->nRelativeNote, lpTrack->nFinetune); + lpTrack->bControl &= ~(AUDIO_CTRL_PITCH | AUDIO_CTRL_KEYON); + } + else { + if (lpTrack->nPeriod < lpTrack->nWantedPeriod) { + lpTrack->nPeriod += lpTrack->nTonePorta; + if (lpTrack->nPeriod > lpTrack->nWantedPeriod) { + lpTrack->nPeriod = lpTrack->nWantedPeriod; + } + } + else if (lpTrack->nPeriod > lpTrack->nWantedPeriod) { + lpTrack->nPeriod -= lpTrack->nTonePorta; + if (lpTrack->nPeriod < lpTrack->nWantedPeriod) { + lpTrack->nPeriod = lpTrack->nWantedPeriod; + } + } + /* TODO: glissando not implemented */ + lpTrack->nOutPeriod = lpTrack->nPeriod; + lpTrack->bControl |= AUDIO_CTRL_PITCH; + } +} + +static VOID OnVibrato(LPTRACK lpTrack) +{ + int nDelta, nFrame; + + if (!Player.nFrame) { + if (LOPARAM(lpTrack->bParams)) { + lpTrack->nVibratoDepth = LOPARAM(lpTrack->bParams); + } + if (HIPARAM(lpTrack->bParams)) { + lpTrack->nVibratoRate = HIPARAM(lpTrack->bParams) << 2; + } + } + else { + nFrame = (lpTrack->nVibratoFrame >> 2) & 0x1F; + switch (lpTrack->bWaveCtrl & 0x03) { + case 0x00: + nDelta = aSineTable[nFrame]; + break; + case 0x01: + nDelta = nFrame << 3; + if (lpTrack->nVibratoFrame & 0x80) + nDelta ^= 0xFF; + break; + case 0x02: + nDelta = 0xFF; + break; + default: + /* TODO: random waveform not implemented */ + nDelta = 0x00; + break; + } + nDelta = ((nDelta * lpTrack->nVibratoDepth) >> 5); + lpTrack->nOutPeriod = lpTrack->nPeriod; + if (lpTrack->nVibratoFrame & 0x80) { + lpTrack->nOutPeriod -= nDelta; + if (lpTrack->nOutPeriod < AUDIO_MIN_PERIOD) + lpTrack->nOutPeriod = AUDIO_MIN_PERIOD; + } + else { + lpTrack->nOutPeriod += nDelta; + if (lpTrack->nOutPeriod > AUDIO_MAX_PERIOD) + lpTrack->nOutPeriod = AUDIO_MAX_PERIOD; + } + lpTrack->bControl |= AUDIO_CTRL_PITCH; + lpTrack->nVibratoFrame += lpTrack->nVibratoRate; + } +} + +static VOID OnFineVibrato(LPTRACK lpTrack) +{ + int nDelta, nFrame; + + if (!Player.nFrame) { + if (LOPARAM(lpTrack->bParams)) { + lpTrack->nVibratoDepth = LOPARAM(lpTrack->bParams); + } + if (HIPARAM(lpTrack->bParams)) { + lpTrack->nVibratoRate = HIPARAM(lpTrack->bParams) << 2; + } + } + else { + nFrame = (lpTrack->nVibratoFrame >> 2) & 0x1F; + switch (lpTrack->bWaveCtrl & 0x03) { + case 0x00: + nDelta = aSineTable[nFrame]; + break; + case 0x01: + nDelta = nFrame << 3; + if (lpTrack->nVibratoFrame & 0x80) + nDelta ^= 0xFF; + break; + case 0x02: + nDelta = 0xFF; + break; + default: + /* TODO: random waveform not implemented */ + nDelta = 0x00; + break; + } + nDelta = ((nDelta * lpTrack->nVibratoDepth) >> 7); + lpTrack->nOutPeriod = lpTrack->nPeriod; + if (lpTrack->nVibratoFrame & 0x80) { + lpTrack->nOutPeriod -= nDelta; + if (lpTrack->nOutPeriod < AUDIO_MIN_PERIOD) + lpTrack->nOutPeriod = AUDIO_MIN_PERIOD; + } + else { + lpTrack->nOutPeriod += nDelta; + if (lpTrack->nOutPeriod > AUDIO_MAX_PERIOD) + lpTrack->nOutPeriod = AUDIO_MAX_PERIOD; + } + lpTrack->bControl |= AUDIO_CTRL_PITCH; + lpTrack->nVibratoFrame += lpTrack->nVibratoRate; + } +} + +static VOID OnVolumeSlide(LPTRACK lpTrack) +{ + if (!Player.nFrame) { + if (lpTrack->bParams != 0x00) { + lpTrack->bVolumeSlide = lpTrack->bParams; + } + } + else { + if (HIPARAM(lpTrack->bVolumeSlide)) { + lpTrack->nVolume += HIPARAM(lpTrack->bVolumeSlide); + if (lpTrack->nVolume > AUDIO_MAX_VOLUME) + lpTrack->nVolume = AUDIO_MAX_VOLUME; + } + else { + lpTrack->nVolume -= LOPARAM(lpTrack->bVolumeSlide); + if (lpTrack->nVolume < AUDIO_MIN_VOLUME) + lpTrack->nVolume = AUDIO_MIN_VOLUME; + } + lpTrack->nOutVolume = lpTrack->nVolume; + lpTrack->bControl |= AUDIO_CTRL_VOLUME; + } +} + +static VOID OnToneAndSlide(LPTRACK lpTrack) +{ + if (!Player.nFrame) { + OnVolumeSlide(lpTrack); + lpTrack->bControl &= ~(AUDIO_CTRL_PITCH | AUDIO_CTRL_KEYON); + } + else { + OnTonePorta(lpTrack); + OnVolumeSlide(lpTrack); + } +} + +static VOID OnVibratoAndSlide(LPTRACK lpTrack) +{ + if (!Player.nFrame) { + OnVolumeSlide(lpTrack); + } + else { + OnVibrato(lpTrack); + OnVolumeSlide(lpTrack); + } +} + +static VOID OnTremolo(LPTRACK lpTrack) +{ + int nDelta, nFrame; + + if (!Player.nFrame) { + if (LOPARAM(lpTrack->bParams)) { + lpTrack->nTremoloDepth = LOPARAM(lpTrack->bParams); + } + if (HIPARAM(lpTrack->bParams)) { + lpTrack->nTremoloRate = HIPARAM(lpTrack->bParams) << 2; + } + } + else { + nFrame = (lpTrack->nTremoloFrame >> 2) & 0x1F; + switch (lpTrack->bWaveCtrl & 0x30) { + case 0x00: + nDelta = aSineTable[nFrame]; + break; + case 0x10: + nDelta = nFrame << 3; + if (lpTrack->nTremoloFrame & 0x80) + nDelta ^= 0xFF; + break; + case 0x20: + nDelta = 0xFF; + break; + default: + /* TODO: random waveform not implemented */ + nDelta = 0x00; + break; + } + nDelta = (nDelta * lpTrack->nTremoloDepth) >> 6; + lpTrack->nOutVolume = lpTrack->nVolume; + if (lpTrack->nTremoloFrame & 0x80) { + lpTrack->nOutVolume -= nDelta; + if (lpTrack->nOutVolume < AUDIO_MIN_VOLUME) + lpTrack->nOutVolume = AUDIO_MIN_VOLUME; + } + else { + lpTrack->nOutVolume += nDelta; + if (lpTrack->nOutVolume > AUDIO_MAX_VOLUME) + lpTrack->nOutVolume = AUDIO_MAX_VOLUME; + } + lpTrack->bControl |= AUDIO_CTRL_VOLUME; + lpTrack->nTremoloFrame += lpTrack->nTremoloRate; + } +} + +static VOID OnSetPanning(LPTRACK lpTrack) +{ + if (!Player.nFrame) { + lpTrack->nPanning = lpTrack->bParams; + lpTrack->bControl |= AUDIO_CTRL_PANNING; + } +} + +static VOID OnSampleOffset(LPTRACK lpTrack) +{ + if (!Player.nFrame) { + lpTrack->dwSampleOffset = (LONG) lpTrack->bParams << 8; + lpTrack->bControl |= AUDIO_CTRL_KEYON | AUDIO_CTRL_TOUCH; + } +} + +static VOID OnJumpPosition(LPTRACK lpTrack) +{ + if (!Player.nFrame) { + if (lpTrack->bParams < Player.lpModule->nOrders) { + Player.nJumpOrder = lpTrack->bParams; + Player.wControl |= AUDIO_PLAYER_JUMP; + } + } +} + +static VOID OnSetVolume(LPTRACK lpTrack) +{ + if (!Player.nFrame) { + if ((lpTrack->nVolume = lpTrack->bParams) > AUDIO_MAX_VOLUME) + lpTrack->nVolume = AUDIO_MAX_VOLUME; + lpTrack->nOutVolume = lpTrack->nVolume; + lpTrack->bControl |= AUDIO_CTRL_VOLUME; + } +} + +static VOID OnPatternBreak(LPTRACK lpTrack) +{ + if (!Player.nFrame) { + Player.nJumpRow = 10 * HIPARAM(lpTrack->bParams) + + LOPARAM(lpTrack->bParams); + Player.wControl |= AUDIO_PLAYER_BREAK; + } +} + +static VOID OnExtraCommand(LPTRACK lpTrack) +{ + switch (HIPARAM(lpTrack->bParams)) { + case 0x0: + /* TODO: filter control not implemented */ + break; + case 0x1: + /* fine portamento up */ + if (!Player.nFrame) { + if (LOPARAM(lpTrack->bParams)) + lpTrack->nFinePortaUp = LOPARAM(lpTrack->bParams) << 2; + lpTrack->nPeriod -= lpTrack->nFinePortaUp; + if (lpTrack->nPeriod < AUDIO_MIN_PERIOD) + lpTrack->nPeriod = AUDIO_MIN_PERIOD; + lpTrack->nOutPeriod = lpTrack->nPeriod; + lpTrack->bControl |= AUDIO_CTRL_PITCH; + } + break; + case 0x2: + /* fine portamento down */ + if (!Player.nFrame) { + if (LOPARAM(lpTrack->bParams)) + lpTrack->nFinePortaDown = LOPARAM(lpTrack->bParams) << 2; + lpTrack->nPeriod += lpTrack->nFinePortaDown; + if (lpTrack->nPeriod > AUDIO_MAX_PERIOD) + lpTrack->nPeriod = AUDIO_MAX_PERIOD; + lpTrack->nOutPeriod = lpTrack->nPeriod; + lpTrack->bControl |= AUDIO_CTRL_PITCH; + } + break; + case 0x3: + /* set glissando control */ + if (!Player.nFrame) { + lpTrack->bGlissCtrl = LOPARAM(lpTrack->bParams); + } + break; + case 0x4: + /* set vibrato wave control */ + if (!Player.nFrame) { + lpTrack->bWaveCtrl &= 0xF0; + lpTrack->bWaveCtrl |= LOPARAM(lpTrack->bParams); + } + break; + case 0x5: + /* set finetune */ + if (!Player.nFrame) { + lpTrack->nFinetune = ((int) LOPARAM(lpTrack->bParams) << 4) - 0x80; + lpTrack->nOutPeriod = GetPeriodValue(lpTrack->nNote, + lpTrack->nRelativeNote, lpTrack->nFinetune); + lpTrack->bControl |= AUDIO_CTRL_PITCH; + } + break; + case 0x6: + /* set/start pattern loop */ + if (!Player.nFrame) { + if (LOPARAM(lpTrack->bParams)) { + if (lpTrack->nPatternLoop) + lpTrack->nPatternLoop--; + else + lpTrack->nPatternLoop = LOPARAM(lpTrack->bParams); + if (lpTrack->nPatternLoop) { + Player.nJumpRow = lpTrack->nPatternRow; + Player.nJumpOrder = Player.nOrder; + Player.wControl |= AUDIO_PLAYER_JUMP; + } + } + else { + lpTrack->nPatternRow = Player.nRow; + } + } + break; + case 0x7: + /* set tremolo wave control */ + if (!Player.nFrame) { + lpTrack->bWaveCtrl &= 0x0F; + lpTrack->bWaveCtrl |= LOPARAM(lpTrack->bParams) << 4; + } + break; + case 0x8: + /* set stereo panning control */ + if (!Player.nFrame) { + lpTrack->nPanning = LOPARAM(lpTrack->bParams) << 4; + lpTrack->bControl |= AUDIO_CTRL_PANNING; + } + break; + case 0x9: + /* retrig note */ + if (!Player.nFrame) { + RetrigNote(lpTrack); + } + else if (LOPARAM(lpTrack->bParams)) { + if (!(Player.nFrame % LOPARAM(lpTrack->bParams))) { + RetrigNote(lpTrack); + } + } + break; + case 0xA: + /* fine volume slide up */ + if (!Player.nFrame) { + lpTrack->nVolume += LOPARAM(lpTrack->bParams); + if (lpTrack->nVolume > AUDIO_MAX_VOLUME) + lpTrack->nVolume = AUDIO_MAX_VOLUME; + lpTrack->nOutVolume = lpTrack->nVolume; + lpTrack->bControl |= AUDIO_CTRL_VOLUME; + } + break; + case 0xB: + /* fine volume slide down */ + if (!Player.nFrame) { + lpTrack->nVolume -= LOPARAM(lpTrack->bParams); + if (lpTrack->nVolume < AUDIO_MIN_VOLUME) + lpTrack->nVolume = AUDIO_MIN_VOLUME; + lpTrack->nOutVolume = lpTrack->nVolume; + lpTrack->bControl |= AUDIO_CTRL_VOLUME; + } + break; + case 0xC: + /* note cut */ + if (Player.nFrame == LOPARAM(lpTrack->bParams)) { + lpTrack->nVolume = lpTrack->nOutVolume = 0; + lpTrack->bControl |= AUDIO_CTRL_VOLUME; + } + break; + case 0xD: + /* note delay */ + lpTrack->bControl &= AUDIO_CTRL_KEYOFF; + if (Player.nFrame == LOPARAM(lpTrack->bParams)) { + RetrigNote(lpTrack); + lpTrack->bControl |= (AUDIO_CTRL_VOLUME | AUDIO_CTRL_PANNING); + } + break; + case 0xE: + /* pattern delay */ + if (!Player.nFrame) { + if (!(Player.wControl & AUDIO_PLAYER_DELAY)) { + Player.nPatternDelay = LOPARAM(lpTrack->bParams) + 1; + Player.wControl |= AUDIO_PLAYER_DELAY; + } + } + break; + case 0xF: + /* TODO: funk it! not implemented */ + break; + } +} + +static VOID OnSetSpeed(LPTRACK lpTrack) +{ + if (!Player.nFrame) { + if (lpTrack->bParams >= 0x20) { + Player.nBPM = lpTrack->bParams; + Player.wControl |= AUDIO_PLAYER_BPM; + } + else if (lpTrack->bParams >= 0x01) { + Player.nTempo = lpTrack->bParams; + } + } +} + +static VOID OnSetGlobalVolume(LPTRACK lpTrack) +{ + if (!Player.nFrame) { + if ((Player.nVolume = lpTrack->bParams) > AUDIO_MAX_VOLUME) + Player.nVolume = AUDIO_MAX_VOLUME; + Player.wControl |= AUDIO_PLAYER_VOLUME; + } +} + +static VOID OnGlobalVolumeSlide(LPTRACK lpTrack) +{ + if (!Player.nFrame) { + if (lpTrack->bParams != 0x00) { + Player.nVolumeRate = lpTrack->bParams; + } + } + else { + if (HIPARAM(Player.nVolumeRate)) { + Player.nVolume += HIPARAM(Player.nVolumeRate); + if (Player.nVolume > AUDIO_MAX_VOLUME) + Player.nVolume = AUDIO_MAX_VOLUME; + } + else { + Player.nVolume -= LOPARAM(Player.nVolumeRate); + if (Player.nVolume < AUDIO_MIN_VOLUME) + Player.nVolume = AUDIO_MIN_VOLUME; + } + Player.wControl |= AUDIO_PLAYER_VOLUME; + } +} + +static VOID OnKeyOff(LPTRACK lpTrack) +{ + if (Player.nFrame == lpTrack->bParams) { + StopNote(lpTrack); + } +} + +static VOID OnSetEnvelope(LPTRACK lpTrack) +{ + /* TODO: set envelope position not implemented */ + if (lpTrack != NULL) { + } +} + +static VOID OnPanningSlide(LPTRACK lpTrack) +{ + if (!Player.nFrame) { + if (lpTrack->bParams != 0x00) { + lpTrack->bPanningSlide = lpTrack->bParams; + } + } + else { + if (HIPARAM(lpTrack->bPanningSlide)) { + lpTrack->nPanning += HIPARAM(lpTrack->bPanningSlide); + if (lpTrack->nPanning > AUDIO_MAX_PANNING) + lpTrack->nPanning = AUDIO_MAX_PANNING; + } + else { + lpTrack->nPanning -= LOPARAM(lpTrack->bPanningSlide); + if (lpTrack->nPanning < AUDIO_MIN_PANNING) + lpTrack->nPanning = AUDIO_MIN_PANNING; + } + lpTrack->bControl |= AUDIO_CTRL_PANNING; + } +} + +static VOID OnMultiRetrig(LPTRACK lpTrack) +{ + if (!Player.nFrame) { + if (HIPARAM(lpTrack->bParams)) + lpTrack->nRetrigType = HIPARAM(lpTrack->bParams); + if (LOPARAM(lpTrack->bParams)) + lpTrack->nRetrigInterval = LOPARAM(lpTrack->bParams); + } + else if (++lpTrack->nRetrigFrame >= lpTrack->nRetrigInterval) { + lpTrack->nRetrigFrame = 0; + lpTrack->nVolume += aRetrigTable[lpTrack->nRetrigType]; + lpTrack->nVolume *= aRetrigTable[lpTrack->nRetrigType + 16]; + lpTrack->nVolume >>= 4; + lpTrack->nVolume = CLIP(lpTrack->nVolume, + AUDIO_MIN_VOLUME, AUDIO_MAX_VOLUME); + if (lpTrack->nVolumeCmd >= 0x10 && lpTrack->nVolumeCmd <= 0x50) { + lpTrack->nVolume = lpTrack->nVolumeCmd - 0x10; + lpTrack->bControl |= AUDIO_CTRL_VOLUME; + } + if (lpTrack->nVolumeCmd >= 0xC0 && lpTrack->nVolumeCmd <= 0xCF) { + lpTrack->nPanning = LOPARAM(lpTrack->nVolumeCmd) << 4; + lpTrack->bControl |= AUDIO_CTRL_PANNING; + } + lpTrack->nOutVolume = lpTrack->nVolume; + lpTrack->bControl |= AUDIO_CTRL_VOLUME; + PlayNote(lpTrack); + } +} + +static VOID OnTremor(LPTRACK lpTrack) +{ + if (!Player.nFrame) { + if (lpTrack->bParams) { + lpTrack->bTremorParms = lpTrack->bParams; + } + } + if (!lpTrack->nTremorFrame--) { + lpTrack->nTremorFrame = lpTrack->bTremorOnOff ? + LOPARAM(lpTrack->bTremorParms) : + HIPARAM(lpTrack->bTremorParms); + lpTrack->bTremorOnOff = !lpTrack->bTremorOnOff; + } + lpTrack->nOutVolume = lpTrack->bTremorOnOff ? lpTrack->nVolume : 0x00; + lpTrack->bControl |= AUDIO_CTRL_VOLUME; +} + +static VOID OnExtraFinePorta(LPTRACK lpTrack) +{ + if (!Player.nFrame) { + if (HIPARAM(lpTrack->bParams) == 0x1) { + if (LOPARAM(lpTrack->bParams)) + lpTrack->nExtraPortaUp = LOPARAM(lpTrack->bParams); + lpTrack->nPeriod -= lpTrack->nExtraPortaUp; + if (lpTrack->nPeriod < AUDIO_MIN_PERIOD) + lpTrack->nPeriod = AUDIO_MIN_PERIOD; + lpTrack->nOutPeriod = lpTrack->nPeriod; + lpTrack->bControl |= AUDIO_CTRL_PITCH; + } + else if (HIPARAM(lpTrack->bParams) == 0x2) { + if (LOPARAM(lpTrack->bParams)) + lpTrack->nExtraPortaDown = LOPARAM(lpTrack->bParams); + lpTrack->nPeriod += lpTrack->nExtraPortaDown; + if (lpTrack->nPeriod > AUDIO_MAX_PERIOD) + lpTrack->nPeriod = AUDIO_MAX_PERIOD; + lpTrack->nOutPeriod = lpTrack->nPeriod; + lpTrack->bControl |= AUDIO_CTRL_PITCH; + } + } +} + +static VOID OnSyncMark(LPTRACK lpTrack) +{ + if (!Player.nFrame && Player.lpfnCallback) + Player.lpfnCallback(lpTrack->bParams, Player.nOrder, Player.nRow); +} + +static VOID OnNothing(LPTRACK lpTrack) +{ + /* does nothing, just avoid compiler warnings */ + if (lpTrack != NULL) { + } +} + +static VOID ExecNoteCmd(LPTRACK lpTrack) +{ + static VOID (*CommandProcTable[36])(LPTRACK) = + { + OnArpeggio, /* 0xy */ + OnPortaUp, /* 1xx */ + OnPortaDown, /* 2xx */ + OnTonePorta, /* 3xx */ + OnVibrato, /* 4xy */ + OnToneAndSlide, /* 5xy */ + OnVibratoAndSlide, /* 6xy */ + OnTremolo, /* 7xy */ + OnSetPanning, /* 8xx */ + OnSampleOffset, /* 9xx */ + OnVolumeSlide, /* Axy */ + OnJumpPosition, /* Bxx */ + OnSetVolume, /* Cxx */ + OnPatternBreak, /* Dxx */ + OnExtraCommand, /* Exy */ + OnSetSpeed, /* Fxx */ + OnSetGlobalVolume, /* Gxx */ + OnGlobalVolumeSlide, /* Hxy */ + OnNothing, /* Ixx */ + OnNothing, /* Jxx */ + OnKeyOff, /* Kxx */ + OnSetEnvelope, /* Lxx */ + OnNothing, /* Mxx */ + OnNothing, /* Nxx */ + OnNothing, /* Oxx */ + OnPanningSlide, /* Pxy */ + OnNothing, /* Qxx */ + OnMultiRetrig, /* Rxy */ + OnNothing, /* Sxx */ + OnTremor, /* Txy */ + OnFineVibrato, /* Uxy */ + OnNothing, /* Vxx */ + OnNothing, /* Wxx */ + OnExtraFinePorta, /* Xxy */ + OnNothing, /* Yxx */ + OnSyncMark /* Zxx */ + }; + + if ((lpTrack->nCommand || lpTrack->bParams) && lpTrack->nCommand < 36) { + (*CommandProcTable[lpTrack->nCommand]) (lpTrack); + } +} + +static VOID ExecVolumeCmd(LPTRACK lpTrack) +{ + UINT nCommand; + + nCommand = lpTrack->nVolumeCmd; + if (nCommand >= 0x10 && nCommand <= 0x50) { + /* set volume */ + if (!Player.nFrame) { + lpTrack->nVolume = nCommand - 0x10; + lpTrack->nOutVolume = lpTrack->nVolume; + lpTrack->bControl |= AUDIO_CTRL_VOLUME; + } + } + else if (nCommand >= 0x60 && nCommand <= 0x6F) { + /* volume slide down */ + if (Player.nFrame) { + lpTrack->nVolume -= LOPARAM(nCommand); + if (lpTrack->nVolume < AUDIO_MIN_VOLUME) + lpTrack->nVolume = AUDIO_MIN_VOLUME; + lpTrack->nOutVolume = lpTrack->nVolume; + lpTrack->bControl |= AUDIO_CTRL_VOLUME; + } + } + else if (nCommand >= 0x70 && nCommand <= 0x7F) { + /* volume slide up */ + if (Player.nFrame) { + lpTrack->nVolume += LOPARAM(nCommand); + if (lpTrack->nVolume > AUDIO_MAX_VOLUME) + lpTrack->nVolume = AUDIO_MAX_VOLUME; + lpTrack->nOutVolume = lpTrack->nVolume; + lpTrack->bControl |= AUDIO_CTRL_VOLUME; + } + } + else if (nCommand >= 0x80 && nCommand <= 0x8F) { + /* fine volume slide down */ + if (!Player.nFrame) { + lpTrack->nVolume -= LOPARAM(nCommand); + if (lpTrack->nVolume < AUDIO_MIN_VOLUME) + lpTrack->nVolume = AUDIO_MIN_VOLUME; + lpTrack->nOutVolume = lpTrack->nVolume; + lpTrack->bControl |= AUDIO_CTRL_VOLUME; + } + } + else if (nCommand >= 0x90 && nCommand <= 0x9F) { + /* fine volume slide up */ + if (!Player.nFrame) { + lpTrack->nVolume += LOPARAM(nCommand); + if (lpTrack->nVolume > AUDIO_MAX_VOLUME) + lpTrack->nVolume = AUDIO_MAX_VOLUME; + lpTrack->nOutVolume = lpTrack->nVolume; + lpTrack->bControl |= AUDIO_CTRL_VOLUME; + } + } + else if (nCommand >= 0xA0 && nCommand <= 0xAF) { + /* set vibrato speed */ + if (!Player.nFrame) { + if (LOPARAM(nCommand)) { + lpTrack->nVibratoRate = LOPARAM(nCommand) << 2; + } + } + } + else if (nCommand >= 0xB0 && nCommand <= 0xBF) { + /* vibrato */ + if (!Player.nFrame) { + if (LOPARAM(nCommand)) { + lpTrack->nVibratoDepth = LOPARAM(nCommand); + } + } + else { + OnVibrato(lpTrack); + } + } + else if (nCommand >= 0xC0 && nCommand <= 0xCF) { + /* set coarse panning */ + if (!Player.nFrame) { + lpTrack->nPanning = LOPARAM(nCommand) << 4; + lpTrack->bControl |= AUDIO_CTRL_PANNING; + } + } + else if (nCommand >= 0xD0 && nCommand <= 0xDF) { + /* panning slide left */ + if (Player.nFrame) { + lpTrack->nPanning -= LOPARAM(nCommand); + if (lpTrack->nPanning < AUDIO_MIN_PANNING) + lpTrack->nPanning = AUDIO_MIN_PANNING; + lpTrack->bControl |= AUDIO_CTRL_PANNING; + } + } + else if (nCommand >= 0xE0 && nCommand <= 0xEF) { + /* panning slide right */ + if (Player.nFrame) { + lpTrack->nPanning += LOPARAM(nCommand); + if (lpTrack->nPanning > AUDIO_MAX_PANNING) + lpTrack->nPanning = AUDIO_MAX_PANNING; + lpTrack->bControl |= AUDIO_CTRL_PANNING; + } + } + else if (nCommand >= 0xF0 && nCommand <= 0xFF) { + /* tone portamento */ + if (Player.nFrame) + OnTonePorta(lpTrack); + } +} + +static VOID StartEnvelopes(LPTRACK lpTrack) +{ + LPAUDIOPATCH lpPatch; + + /* reset vibrato and tremolo waves */ + if (!(lpTrack->bWaveCtrl & 0x04)) + lpTrack->nVibratoFrame = 0; + if (!(lpTrack->bWaveCtrl & 0x40)) + lpTrack->nTremoloFrame = 0; + + /* reset retrig and tremor frames */ + lpTrack->nRetrigFrame = 0; + lpTrack->nTremorFrame = 0; + lpTrack->bTremorOnOff = 0; + + lpPatch = lpTrack->lpPatch; + + /* start volume envelope */ + if (lpPatch != NULL && (lpPatch->Volume.wFlags & AUDIO_ENVELOPE_ON)) { + lpTrack->nVolumeFrame = -1; + lpTrack->nVolumePoint = 0; + } + + /* start panning envelope */ + if (lpPatch != NULL && (lpPatch->Panning.wFlags & AUDIO_ENVELOPE_ON)) { + lpTrack->nPanningFrame = -1; + lpTrack->nPanningPoint = 0; + } + + /* start volume fadeout */ + if (lpPatch != NULL) + lpTrack->nVolumeFadeout = lpPatch->nVolumeFadeout; + lpTrack->nVolumeFade = 0x7FFF; + + /* start automatic vibrato */ + if (lpPatch != NULL && lpPatch->nVibratoDepth) { + lpTrack->nAutoVibratoFrame = 0; + if (lpPatch->nVibratoSweep) { + lpTrack->nAutoVibratoSlope = + ((int) lpPatch->nVibratoDepth << 8) / lpPatch->nVibratoSweep; + lpTrack->nAutoVibratoValue = 0; + } + else { + lpTrack->nAutoVibratoSlope = 0; + lpTrack->nAutoVibratoValue = + ((int) lpPatch->nVibratoDepth << 8); + } + } +} + +static VOID UpdateEnvelopes(LPTRACK lpTrack) +{ + LPAUDIOPATCH lpPatch; + LPAUDIOPOINT lpPts; + int nFrames, nValue; + + /* get patch structure alias */ + lpPatch = lpTrack->lpPatch; + + /* process volume fadeout */ + if (lpPatch != NULL && !lpTrack->fKeyOn) { + if ((lpTrack->nVolumeFade -= lpTrack->nVolumeFadeout) < 0) { + lpTrack->nVolumeFadeout = 0; + lpTrack->nVolumeFade = 0; + } + lpTrack->bControl |= AUDIO_CTRL_VOLUME; + } + + /* process volume envelope */ + if (lpPatch != NULL && (lpPatch->Volume.wFlags & AUDIO_ENVELOPE_ON)) { + lpPts = lpPatch->Volume.aEnvelope; + if (++lpTrack->nVolumeFrame >= lpPts[lpTrack->nVolumePoint].nFrame) { + if ((lpPatch->Volume.wFlags & AUDIO_ENVELOPE_SUSTAIN) && + (lpTrack->nVolumePoint == lpPatch->Volume.nSustain) && + lpTrack->fKeyOn) { + lpTrack->nVolumeFrame = lpPts[lpTrack->nVolumePoint].nFrame; + lpTrack->nVolumeValue = (int) lpPts[lpTrack->nVolumePoint].nValue << 8; + } + else { + if ((lpPatch->Volume.wFlags & AUDIO_ENVELOPE_LOOP) && + (lpTrack->nVolumePoint == lpPatch->Volume.nLoopEnd)) { + lpTrack->nVolumePoint = lpPatch->Volume.nLoopStart; + } + lpTrack->nVolumeFrame = lpPts[lpTrack->nVolumePoint].nFrame; + lpTrack->nVolumeValue = (int) lpPts[lpTrack->nVolumePoint].nValue << 8; + if (lpTrack->nVolumePoint + 1 >= lpPatch->Volume.nPoints) { + lpTrack->nVolumeSlope = 0; + } + else { + if ((nFrames = lpPts[lpTrack->nVolumePoint + 1].nFrame - + lpPts[lpTrack->nVolumePoint].nFrame) <= 0) + lpTrack->nVolumeSlope = 0; + else { + lpTrack->nVolumeSlope = + (((int) lpPts[lpTrack->nVolumePoint + 1].nValue - + (int) lpPts[lpTrack->nVolumePoint].nValue) << 8) / nFrames; + } + lpTrack->nVolumePoint++; + } + } + } + else { + lpTrack->nVolumeValue += lpTrack->nVolumeSlope; + lpTrack->nVolumeValue = CLIP(lpTrack->nVolumeValue, 0, 64 * 256); + } + lpTrack->nFinalVolume = (((LONG) (lpTrack->nVolumeValue >> 8) * + lpTrack->nOutVolume) * lpTrack->nVolumeFade) >> 21; + lpTrack->bControl |= AUDIO_CTRL_VOLUME; + } + else { + lpTrack->nFinalVolume = lpTrack->nOutVolume; + if (lpTrack->nVolumeFade != 0x7FFF) + lpTrack->nFinalVolume = ((LONG) lpTrack->nFinalVolume * + lpTrack->nVolumeFade) >> 15; + } + + /* process panning envelope */ + if (lpPatch != NULL && (lpPatch->Panning.wFlags & AUDIO_ENVELOPE_ON)) { + lpPts = lpPatch->Panning.aEnvelope; + if (++lpTrack->nPanningFrame >= lpPts[lpTrack->nPanningPoint].nFrame) { + if ((lpPatch->Panning.wFlags & AUDIO_ENVELOPE_SUSTAIN) && + (lpTrack->nPanningPoint == lpPatch->Panning.nSustain) && + lpTrack->fKeyOn) { + lpTrack->nPanningFrame = lpPts[lpTrack->nPanningPoint].nFrame; + lpTrack->nPanningValue = (int) lpPts[lpTrack->nPanningPoint].nValue << 8; + } + else { + if ((lpPatch->Panning.wFlags & AUDIO_ENVELOPE_LOOP) && + (lpTrack->nPanningPoint == lpPatch->Panning.nLoopEnd)) { + lpTrack->nPanningPoint = lpPatch->Panning.nLoopStart; + } + lpTrack->nPanningFrame = lpPts[lpTrack->nPanningPoint].nFrame; + lpTrack->nPanningValue = (int) lpPts[lpTrack->nPanningPoint].nValue << 8; + if (lpTrack->nPanningPoint + 1 >= lpPatch->Panning.nPoints) { + lpTrack->nPanningSlope = 0; + } + else { + if ((nFrames = lpPts[lpTrack->nPanningPoint + 1].nFrame - + lpPts[lpTrack->nPanningPoint].nFrame) <= 0) + lpTrack->nPanningSlope = 0; + else { + lpTrack->nPanningSlope = + (((int) lpPts[lpTrack->nPanningPoint + 1].nValue - + (int) lpPts[lpTrack->nPanningPoint].nValue) << 8) / nFrames; + } + lpTrack->nPanningPoint++; + } + } + } + else { + lpTrack->nPanningValue += lpTrack->nPanningSlope; + lpTrack->nPanningValue = CLIP(lpTrack->nPanningValue, 0, 64 * 256); + } + lpTrack->nFinalPanning = lpTrack->nPanning + + ((((128L - ABS(lpTrack->nPanning - 128)) << 3) * + (lpTrack->nPanningValue - 32 * 256L)) >> 16); + lpTrack->bControl |= AUDIO_CTRL_PANNING; + } + else { + lpTrack->nFinalPanning = lpTrack->nPanning; + } + + /* process automatic vibrato */ + if (lpPatch != NULL && lpPatch->nVibratoDepth != 0) { + if (lpTrack->fKeyOn && lpTrack->nAutoVibratoSlope) { + lpTrack->nAutoVibratoValue += lpTrack->nAutoVibratoSlope; + if (lpTrack->nAutoVibratoValue > ((int) lpPatch->nVibratoDepth << 8)) { + lpTrack->nAutoVibratoValue = (int) lpPatch->nVibratoDepth << 8; + lpTrack->nAutoVibratoSlope = 0; + } + } + lpTrack->nAutoVibratoFrame += lpPatch->nVibratoRate; + nFrames = (BYTE) lpTrack->nAutoVibratoFrame; + switch (lpPatch->nVibratoType) { + case 0x00: + nValue = aAutoVibratoTable[nFrames]; + break; + case 0x01: + nValue = (nFrames & 0x80) ? +64 : -64; + break; + case 0x02: + nValue = ((64 + (nFrames >> 1)) & 0x7f) - 64; + break; + case 0x03: + nValue = ((64 - (nFrames >> 1)) & 0x7f) - 64; + break; + default: + /* unknown vibrato waveform type */ + nValue = 0; + break; + } + lpTrack->nFinalPeriod = lpTrack->nOutPeriod + + ((((LONG) nValue << 2) * lpTrack->nAutoVibratoValue) >> 16); + lpTrack->nFinalPeriod = CLIP(lpTrack->nFinalPeriod, + AUDIO_MIN_PERIOD, AUDIO_MAX_PERIOD); + lpTrack->bControl |= AUDIO_CTRL_PITCH; + } + else { + lpTrack->nFinalPeriod = lpTrack->nOutPeriod; + } +} + +static VOID PlayNote(LPTRACK lpTrack) +{ + LPAUDIOPATCH lpPatch; + LPAUDIOSAMPLE lpSample; + + lpTrack->fKeyOn = (lpTrack->nNote >= 1 && lpTrack->nNote <= AUDIO_MAX_NOTES); + if (lpTrack->fKeyOn && (lpPatch = lpTrack->lpPatch) != NULL) { + lpTrack->nSample = lpPatch->aSampleNumber[lpTrack->nNote - 1]; + if (lpTrack->nSample < lpPatch->nSamples) { + lpTrack->lpSample = &lpPatch->aSampleTable[lpTrack->nSample]; + lpSample = lpTrack->lpSample; + lpTrack->nRelativeNote = (signed char) lpSample->nRelativeNote; + lpTrack->nFinetune = (signed char) lpSample->nFinetune; + if (lpTrack->nCommand != 0x03 && lpTrack->nCommand != 0x05 && + (lpTrack->nVolumeCmd & 0xF0) != 0xF0) { + lpTrack->nPeriod = lpTrack->nOutPeriod = + GetPeriodValue(lpTrack->nNote, + lpTrack->nRelativeNote, lpTrack->nFinetune); + lpTrack->bControl |= (AUDIO_CTRL_PITCH | AUDIO_CTRL_KEYON); + } + } + else { + lpTrack->lpSample = NULL; + } + } +} + +static VOID StopNote(LPTRACK lpTrack) +{ + lpTrack->fKeyOn = 0; + if (lpTrack->lpPatch != NULL) { + if (!(lpTrack->lpPatch->Volume.wFlags & AUDIO_ENVELOPE_ON)) { + lpTrack->nVolume = lpTrack->nOutVolume = 0; + lpTrack->bControl |= (AUDIO_CTRL_VOLUME | AUDIO_CTRL_KEYOFF); + } + } + else { + lpTrack->bControl |= AUDIO_CTRL_KEYOFF; + } +} + +static VOID RetrigNote(LPTRACK lpTrack) +{ + PlayNote(lpTrack); + StartEnvelopes(lpTrack); +} + +static VOID GetPatternNote(LPNOTE lpNote) +{ + BYTE fPacking; + +#define GETBYTE *Player.lpData++ + + fPacking = (Player.lpData != NULL) ? + (Player.lpData[0] & AUDIO_PATTERN_PACKED ? GETBYTE : 0xFF) : 0x00; + lpNote->nNote = (fPacking & AUDIO_PATTERN_NOTE) ? GETBYTE : 0x00; + lpNote->nPatch = (fPacking & AUDIO_PATTERN_SAMPLE) ? GETBYTE : 0x00; + lpNote->nVolume = (fPacking & AUDIO_PATTERN_VOLUME) ? GETBYTE : 0x00; + lpNote->nCommand = (fPacking & AUDIO_PATTERN_COMMAND) ? GETBYTE : 0x00; + lpNote->bParams = (fPacking & AUDIO_PATTERN_PARAMS) ? GETBYTE : 0x00; +} + +static VOID GetTrackNote(LPTRACK lpTrack) +{ + static NOTE Note; + + /* read next packed note from pattern */ + GetPatternNote(&Note); + + /* reset frequency for vibrato and arpeggio commands */ + if (lpTrack->nCommand == 0x04 || lpTrack->nCommand == 0x06) { + if (Note.nCommand != 0x04 && Note.nCommand != 0x06) { + lpTrack->nOutPeriod = lpTrack->nPeriod; + lpTrack->bControl |= AUDIO_CTRL_PITCH; + } + } + else if (lpTrack->nCommand == 0x00 && lpTrack->bParams != 0x00) { + lpTrack->nOutPeriod = lpTrack->nPeriod; + lpTrack->bControl |= AUDIO_CTRL_PITCH; + } + + /* assign volume and effect commands */ + lpTrack->nVolumeCmd = Note.nVolume; + lpTrack->nCommand = Note.nCommand; + lpTrack->bParams = Note.bParams; + + /* change default patch instrument */ + if (Note.nPatch >= 1 && Note.nPatch <= Player.lpModule->nPatches) { + lpTrack->nPatch = Note.nPatch; + lpTrack->lpPatch = &Player.lpModule->aPatchTable[lpTrack->nPatch - 1]; + } + + /* new note pressed? */ + if (Note.nNote >= 1 && Note.nNote <= AUDIO_MAX_NOTES) { + lpTrack->nNote = Note.nNote; + PlayNote(lpTrack); + if (Note.nPatch != 0 && lpTrack->lpSample != NULL) + StartEnvelopes(lpTrack); + } + else if (Note.nNote != 0) { + StopNote(lpTrack); + } + + /* use default sample's volume and panning? */ + if (Note.nPatch != 0 && lpTrack->lpSample != NULL) { + lpTrack->nVolume = lpTrack->nOutVolume = lpTrack->lpSample->nVolume; + lpTrack->bControl |= AUDIO_CTRL_VOLUME; + if (!(Player.wFlags & AUDIO_MODULE_PANNING)) { + lpTrack->nPanning = lpTrack->lpSample->nPanning; + lpTrack->bControl |= AUDIO_CTRL_PANNING; + } + } +} + +static VOID SendNoteMesg(HAC hVoice, LPTRACK lpTrack) +{ + if (lpTrack->bControl & (AUDIO_CTRL_KEYON | AUDIO_CTRL_TOUCH)) { + if (lpTrack->lpSample != NULL) { + APrimeVoice(hVoice, &lpTrack->lpSample->Wave); + if (lpTrack->bControl & AUDIO_CTRL_TOUCH) + ASetVoicePosition(hVoice, lpTrack->dwSampleOffset); + } + } + if (lpTrack->bControl & AUDIO_CTRL_KEYOFF) { + AStopVoice(hVoice); + } + if (lpTrack->bControl & AUDIO_CTRL_PITCH) { + ASetVoiceFrequency(hVoice, GetFrequencyValue(lpTrack->nFinalPeriod)); + } + if (lpTrack->bControl & AUDIO_CTRL_VOLUME) { + ASetVoiceVolume(hVoice, (lpTrack->nFinalVolume * Player.nVolume) >> 6); + } + if (lpTrack->bControl & AUDIO_CTRL_PANNING) { + ASetVoicePanning(hVoice, lpTrack->nFinalPanning); + } + if (lpTrack->bControl & AUDIO_CTRL_KEYON) { + AStartVoice(hVoice); + } + lpTrack->bControl = 0x00; +} + +static VOID GetNextPatternRow(VOID) +{ + static NOTE Note; + LPAUDIOPATTERN lpPattern; + int n, m; + + Player.nFrame = 0; + if (Player.wControl & AUDIO_PLAYER_DELAY) + return; + + if (++Player.nRow >= Player.nRows) { + Player.wControl |= AUDIO_PLAYER_BREAK; + } + if (Player.wControl & AUDIO_PLAYER_JUMP) { + Player.nRow = Player.nJumpRow; + Player.nJumpRow = 0; + Player.nOrder = Player.nJumpOrder; + } + else if (Player.wControl & AUDIO_PLAYER_BREAK) { + Player.nRow = Player.nJumpRow; + Player.nJumpRow = 0; + Player.nOrder++; + } + if (Player.wControl & (AUDIO_PLAYER_BREAK | AUDIO_PLAYER_JUMP)) { + Player.wControl &= ~(AUDIO_PLAYER_BREAK | AUDIO_PLAYER_JUMP); + if (Player.nOrder >= Player.lpModule->nOrders) { + Player.nOrder = Player.lpModule->nRestart; + if (Player.nOrder >= Player.lpModule->nOrders) { + Player.nOrder = 0x00; + Player.wControl |= AUDIO_PLAYER_PAUSE; + return; + } + } + Player.nPattern = Player.lpModule->aOrderTable[Player.nOrder]; + if (Player.nPattern < Player.lpModule->nPatterns) { + lpPattern = &Player.lpModule->aPatternTable[Player.nPattern]; + Player.nRows = lpPattern->nRows; + Player.lpData = lpPattern->lpData; + if (Player.nRow >= Player.nRows) { + Player.nRow = 0x00; + } + for (m = 0; m < Player.nRow; m++) { + for (n = 0; n < Player.nTracks; n++) + GetPatternNote(&Note); + } + } + else { + Player.nRows = 64; + Player.lpData = NULL; + } + } + for (n = 0; n < Player.nTracks; n++) { + GetTrackNote(&Player.aTracks[n]); + } +} + +static VOID AIAPI PlayNextFrame(VOID) +{ + int n; + + if (!(Player.wControl & AUDIO_PLAYER_PAUSE)) { + if (++Player.nFrame >= Player.nTempo) { + GetNextPatternRow(); + } + + for (n = 0; n < Player.nTracks; n++) { + ExecVolumeCmd(&Player.aTracks[n]); + ExecNoteCmd(&Player.aTracks[n]); + UpdateEnvelopes(&Player.aTracks[n]); + } + + if (Player.wControl & AUDIO_PLAYER_DELAY) { + if (!Player.nFrame && !--Player.nPatternDelay) + Player.wControl &= ~AUDIO_PLAYER_DELAY; + } + + if (Player.wControl & AUDIO_PLAYER_VOLUME) { + Player.wControl &= ~AUDIO_PLAYER_VOLUME; + for (n = 0; n < Player.nTracks; n++) + Player.aTracks[n].bControl |= AUDIO_CTRL_VOLUME; + } + + if (Player.wControl & AUDIO_PLAYER_BPM) { + Player.wControl &= ~AUDIO_PLAYER_BPM; + ASetAudioTimerRate(Player.nBPM); + } + + for (n = 0; n < Player.nTracks; n++) { + SendNoteMesg(Player.aVoices[n], &Player.aTracks[n]); + } + } +} + + +/* + * High-level extended module player routines + */ +UINT AIAPI APlayModule(LPAUDIOMODULE lpModule) +{ + int n; + + if (!(Player.wControl & AUDIO_PLAYER_ACTIVE)) { + if (lpModule != NULL) { + memset(&Player, 0, sizeof(Player)); + Player.lpModule = lpModule; + Player.nTracks = lpModule->nTracks; + Player.wFlags = lpModule->wFlags; + Player.nTempo = lpModule->nTempo; + Player.nBPM = lpModule->nBPM; + Player.nVolume = AUDIO_MAX_VOLUME; + Player.wControl = AUDIO_PLAYER_ACTIVE | AUDIO_PLAYER_JUMP; + for (n = 0; n < Player.nTracks; n++) { + if (ACreateAudioVoice(&Player.aVoices[n]) != AUDIO_ERROR_NONE) { + AStopModule(); + return AUDIO_ERROR_NOMEMORY; + } + Player.aTracks[n].nPanning = lpModule->aPanningTable[n]; + ASetVoicePanning(Player.aVoices[n], Player.aTracks[n].nPanning); + } + ASetAudioTimerRate(Player.nBPM); + ASetAudioTimerProc(PlayNextFrame); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_NOTSUPPORTED; +} + +UINT AIAPI AStopModule(VOID) +{ + int n; + + if (Player.wControl & AUDIO_PLAYER_ACTIVE) { + for (n = 0; n < Player.nTracks; n++) { + AStopVoice(Player.aVoices[n]); + ADestroyAudioVoice(Player.aVoices[n]); + } + memset(&Player, 0, sizeof(Player)); + ASetAudioTimerProc(NULL); + ASetAudioTimerRate(125); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_NOTSUPPORTED; +} + +UINT AIAPI APauseModule(VOID) +{ + int n; + + if (Player.wControl & AUDIO_PLAYER_ACTIVE) { + Player.wControl |= AUDIO_PLAYER_PAUSE; + for (n = 0; n < Player.nTracks; n++) + ASetVoiceVolume(Player.aVoices[n], 0x00); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_NOTSUPPORTED; +} + +UINT AIAPI AResumeModule(VOID) +{ + if (Player.wControl & AUDIO_PLAYER_ACTIVE) { + Player.wControl &= ~AUDIO_PLAYER_PAUSE; + Player.wControl |= AUDIO_PLAYER_VOLUME; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_NOTSUPPORTED; +} + +UINT AIAPI ASetModuleVolume(UINT nVolume) +{ + if (Player.wControl & AUDIO_PLAYER_ACTIVE) { + if (nVolume <= AUDIO_MAX_VOLUME) { + Player.nVolume = nVolume; + if (!(Player.wControl & AUDIO_PLAYER_PAUSE)) { + Player.wControl |= AUDIO_PLAYER_VOLUME; + } + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_NOTSUPPORTED; +} + +UINT AIAPI ASetModulePosition(UINT nOrder, UINT nRow) +{ + if (Player.wControl & AUDIO_PLAYER_ACTIVE) { + Player.nJumpOrder = nOrder; + Player.nJumpRow = nRow; + Player.wControl |= AUDIO_PLAYER_JUMP; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_NOTSUPPORTED; +} + +UINT AIAPI AGetModuleVolume(LPUINT lpnVolume) +{ + if (Player.wControl & AUDIO_PLAYER_ACTIVE) { + if (lpnVolume != NULL) { + *lpnVolume = Player.nVolume; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_NOTSUPPORTED; +} + +UINT AIAPI AGetModulePosition(LPUINT lpnOrder, LPUINT lpnRow) +{ + if (Player.wControl & AUDIO_PLAYER_ACTIVE) { + if (lpnOrder != NULL && lpnRow != NULL) { + *lpnOrder = Player.nOrder; + *lpnRow = Player.nRow; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_NOTSUPPORTED; +} + +UINT AIAPI AGetModuleStatus(LPBOOL lpnStatus) +{ + if (Player.wControl & AUDIO_PLAYER_ACTIVE) { + if (lpnStatus != NULL) { + *lpnStatus = ((Player.wControl & AUDIO_PLAYER_PAUSE) != 0); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_NOTSUPPORTED; +} + +UINT AIAPI ASetModuleCallback(LPFNAUDIOCALLBACK lpfnAudioCallback) +{ + if (Player.wControl & AUDIO_PLAYER_ACTIVE) { + Player.lpfnCallback = lpfnAudioCallback; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_NOTSUPPORTED; +} + +UINT AIAPI AFreeModuleFile(LPAUDIOMODULE lpModule) +{ + LPAUDIOPATTERN lpPattern; + LPAUDIOPATCH lpPatch; + LPAUDIOSAMPLE lpSample; + UINT n, m; + + if (lpModule != NULL) { + if ((lpPattern = lpModule->aPatternTable) != NULL) { + for (n = 0; n < lpModule->nPatterns; n++, lpPattern++) { + if (lpPattern->lpData != NULL) + free(lpPattern->lpData); + } + free(lpModule->aPatternTable); + } + if ((lpPatch = lpModule->aPatchTable) != NULL) { + for (n = 0; n < lpModule->nPatches; n++, lpPatch++) { + lpSample = lpPatch->aSampleTable; + for (m = 0; m < lpPatch->nSamples; m++, lpSample++) { + ADestroyAudioData(&lpSample->Wave); + } + free(lpPatch->aSampleTable); + } + free(lpModule->aPatchTable); + } + free(lpModule); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; +} + +UINT AIAPI ALoadModuleFile(LPSTR lpszFileName, + LPAUDIOMODULE *lplpModule, DWORD dwOffset) +{ + extern UINT AIAPI ALoadModuleXM(LPSTR, LPAUDIOMODULE*, DWORD); + extern UINT AIAPI ALoadModuleS3M(LPSTR, LPAUDIOMODULE*, DWORD); + extern UINT AIAPI ALoadModuleMOD(LPSTR, LPAUDIOMODULE*, DWORD); + extern UINT AIAPI ALoadModuleMTM(LPSTR, LPAUDIOMODULE*, DWORD); + UINT nErrorCode; + + if (lpszFileName != NULL && lplpModule != NULL) { + *lplpModule = NULL; + printf("Will load %s\n", lpszFileName); + nErrorCode = ALoadModuleXM(lpszFileName, lplpModule, dwOffset); + if (nErrorCode == AUDIO_ERROR_BADFILEFORMAT) + nErrorCode = ALoadModuleS3M(lpszFileName, lplpModule, dwOffset); + if (nErrorCode == AUDIO_ERROR_BADFILEFORMAT) + nErrorCode = ALoadModuleMOD(lpszFileName, lplpModule, dwOffset); + if (nErrorCode == AUDIO_ERROR_BADFILEFORMAT) + nErrorCode = ALoadModuleMTM(lpszFileName, lplpModule, dwOffset); + return nErrorCode; + } + return AUDIO_ERROR_INVALPARAM; +} + +/*** NEW: 04/12/98 ***/ +UINT AIAPI AGetModuleTrack(UINT nTrack, LPAUDIOTRACK lpTrack) +{ + if (Player.wControl & AUDIO_PLAYER_ACTIVE) { + if (nTrack < 32 && lpTrack != NULL) { + lpTrack->nNote = Player.aTracks[nTrack].nNote; + lpTrack->nPatch = Player.aTracks[nTrack].nPatch; + lpTrack->nSample = Player.aTracks[nTrack].nSample; + lpTrack->nCommand = Player.aTracks[nTrack].nCommand; + lpTrack->nVolumeCmd = Player.aTracks[nTrack].nVolumeCmd; + lpTrack->bParams = Player.aTracks[nTrack].bParams; + lpTrack->nVolume = Player.aTracks[nTrack].nFinalVolume; + lpTrack->nPanning = Player.aTracks[nTrack].nFinalPanning; + lpTrack->wPeriod = Player.aTracks[nTrack].nFinalPeriod; + lpTrack->dwFrequency = Player.aTracks[nTrack].dwFrequency; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_NOTSUPPORTED; +} + diff --git a/seal-hack/src/modfile.c b/seal-hack/src/modfile.c new file mode 100644 index 0000000..08dce4d --- /dev/null +++ b/seal-hack/src/modfile.c @@ -0,0 +1,309 @@ +/* + * $Id: modfile.c 1.5 1996/09/13 15:10:01 chasan released $ + * + * Protracker/Fastracker module file loader routines. + * + * Copyright (c) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include "audio.h" +#include "iofile.h" + + +/* + * Protracker module file structures + */ +typedef struct { + CHAR aSampleName[22]; + WORD wLength; + BYTE nFinetune; + BYTE nVolume; + WORD wLoopStart; + WORD wLoopLength; +} MODSAMPLEHEADER; + +typedef struct { + CHAR aModuleName[20]; + MODSAMPLEHEADER aSampleTable[31]; + BYTE nSongLength; + BYTE nRestart; + BYTE aOrderTable[128]; + CHAR aMagic[4]; +} MODFILEHEADER; + + +/* + * Extended Protracker logarithmic period table + */ +static WORD aMODPeriodTable[96] = +{ + 6848, 6464, 6096, 5760, 5424, 5120, 4832, 4560, 4304, 4064, 3840, 3624, + 3424, 3232, 3048, 2880, 2712, 2560, 2416, 2280, 2152, 2032, 1920, 1812, + 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, + 53, 50, 47, 45, 42, 40, 37, 35, 33, 31, 30, 28 +}; + +/* + * Protracker module header signatures table + */ +static struct { + CHAR aMagic[4]; + UINT nTracks; +} aFmtTable[] = { + { "M.K.", 4 }, { "M!K!", 4 }, + { "M&K!", 4 }, { "OCTA", 4 }, + { "FLT4", 4 }, { "6CHN", 6 }, + { "8CHN", 8 }, { "FLT8", 8 }, + { "10CH", 10 }, { "12CH", 12 }, + { "14CH", 14 }, { "16CH", 16 }, + { "18CH", 18 }, { "20CH", 20 }, + { "22CH", 22 }, { "24CH", 24 }, + { "26CH", 26 }, { "28CH", 28 }, + { "30CH", 30 }, { "32CH", 32 } +}; + + +/* + * Protracker module file loader routines + */ +static UINT MODGetNoteValue(UINT nPeriod) +{ + UINT nNote; + + if (nPeriod != 0) { + for (nNote = 0; nNote < 96; nNote++) + if (nPeriod >= aMODPeriodTable[nNote]) + return nNote + 1; + } + return 0; +} + +static UINT MODLoadPattern(UINT nTracks, LPAUDIOPATTERN lpPattern) +{ + UINT nSize, fPacking, nNote, nSample, nCommand, nParams; + LPBYTE lpData, lpFTData; + + /* initialize pattern header structure */ + nSize = 4 * 64 * nTracks; + lpPattern->nPacking = 0; + lpPattern->nTracks = nTracks; + lpPattern->nRows = 64; + lpPattern->nSize = nSize + 64 * nTracks; + if ((lpPattern->lpData = malloc(lpPattern->nSize)) == NULL) + return AUDIO_ERROR_NOMEMORY; + + /* load MOD pattern data from disk */ + lpData = lpPattern->lpData + 64 * nTracks; + lpFTData = lpPattern->lpData; + AIOReadFile(lpData, nSize); + + while (nSize != 0) { + /* grab MOD note event from the pattern */ + nNote = MODGetNoteValue(((lpData[0] & 0x0F) << 8) + lpData[1]); + nSample = (lpData[0] & 0xF0) + ((lpData[2] >> 4) & 0x0F); + nCommand = (lpData[2] & 0x0F); + nParams = lpData[3]; + lpData += 4; + nSize -= 4; + + /* remove some dummy MOD command effects */ + switch ((nCommand << 8) + nParams) { + case 0x100: + case 0x200: + case 0xA00: + case 0xE10: + case 0xE20: + case 0xEA0: + case 0xEB0: + nCommand = nParams = 0x00; + break; + } + + /* convert DMP-style panning command */ + if (nCommand == 0x8) { + if (nParams > 0x80) + nParams = 0x80; + else if (nParams < 0x80) + nParams <<= 1; + else + nParams = 0xFF; + } + + /* insert packed note event */ + fPacking = AUDIO_PATTERN_PACKED; + if (nNote) + fPacking |= AUDIO_PATTERN_NOTE; + if (nSample) + fPacking |= AUDIO_PATTERN_SAMPLE; + if (nCommand) + fPacking |= AUDIO_PATTERN_COMMAND; + if (nParams) + fPacking |= AUDIO_PATTERN_PARAMS; + *lpFTData++ = fPacking; + if (nNote) + *lpFTData++ = nNote; + if (nSample) + *lpFTData++ = nSample; + if (nCommand) + *lpFTData++ = nCommand; + if (nParams) + *lpFTData++ = nParams; + } + + lpPattern->nSize = (lpFTData - lpPattern->lpData); + if ((lpPattern->lpData = realloc(lpPattern->lpData, lpPattern->nSize)) == NULL) { + return AUDIO_ERROR_NOMEMORY; + } + return AUDIO_ERROR_NONE; +} + +UINT AIAPI ALoadModuleMOD(LPSTR lpszFileName, + LPAUDIOMODULE *lplpModule, DWORD dwFileOffset) +{ + static MODFILEHEADER Header; + static MODSAMPLEHEADER Sample; + LPAUDIOMODULE lpModule; + LPAUDIOPATTERN lpPattern; + LPAUDIOPATCH lpPatch; + LPAUDIOSAMPLE lpSample; + UINT n, nErrorCode; + + if (AIOOpenFile(lpszFileName)) { + return AUDIO_ERROR_FILENOTFOUND; + } + AIOSeekFile(dwFileOffset, SEEK_SET); + + if ((lpModule = (LPAUDIOMODULE) calloc(1, sizeof(AUDIOMODULE))) == NULL) { + AIOCloseFile(); + return AUDIO_ERROR_NOMEMORY; + } + + /* load MOD module header */ + AIOReadFile(Header.aModuleName, sizeof(Header.aModuleName)); + for (n = 0; n < 31; n++) { + AIOReadFile(Header.aSampleTable[n].aSampleName, + sizeof(Header.aSampleTable[n].aSampleName)); + AIOReadShortM(&Header.aSampleTable[n].wLength); + AIOReadCharM(&Header.aSampleTable[n].nFinetune); + AIOReadCharM(&Header.aSampleTable[n].nVolume); + AIOReadShortM(&Header.aSampleTable[n].wLoopStart); + AIOReadShortM(&Header.aSampleTable[n].wLoopLength); + } + AIOReadCharM(&Header.nSongLength); + AIOReadCharM(&Header.nRestart); + AIOReadFile(Header.aOrderTable, sizeof(Header.aOrderTable)); + AIOReadFile(Header.aMagic, sizeof(Header.aMagic)); + for (n = 0; n < sizeof(aFmtTable) / sizeof(aFmtTable[0]); n++) { + if (!memcmp(Header.aMagic, aFmtTable[n].aMagic, sizeof(DWORD))) { + lpModule->nTracks = aFmtTable[n].nTracks; + break; + } + } + if (lpModule->nTracks == 0) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_BADFILEFORMAT; + } + + /* initialize the module structure */ + strncpy(lpModule->szModuleName, Header.aModuleName, + sizeof(Header.aModuleName)); + lpModule->wFlags = AUDIO_MODULE_AMIGA | AUDIO_MODULE_PANNING; + lpModule->nOrders = Header.nSongLength; + lpModule->nRestart = Header.nRestart; + lpModule->nPatches = 31; + lpModule->nTempo = 6; + lpModule->nBPM = 125; + for (n = 0; n < sizeof(Header.aOrderTable); n++) { + lpModule->aOrderTable[n] = Header.aOrderTable[n]; + if (lpModule->nPatterns < Header.aOrderTable[n]) + lpModule->nPatterns = Header.aOrderTable[n]; + } + lpModule->nPatterns++; + for (n = 0; n < lpModule->nTracks; n++) { + lpModule->aPanningTable[n] = + ((n & 3) == 0 || (n & 3) == 3) ? 0x00 : 0xFF; + } + if ((lpModule->aPatternTable = (LPAUDIOPATTERN) + calloc(lpModule->nPatterns, sizeof(AUDIOPATTERN))) == NULL) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_NOMEMORY; + } + if ((lpModule->aPatchTable = (LPAUDIOPATCH) + calloc(lpModule->nPatches, sizeof(AUDIOPATCH))) == NULL) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_NOMEMORY; + } + + /* load MOD pattern sheets */ + lpPattern = lpModule->aPatternTable; + for (n = 0; n < lpModule->nPatterns; n++, lpPattern++) { + if ((nErrorCode = MODLoadPattern(lpModule->nTracks, lpPattern)) != 0) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return nErrorCode; + } + } + + /* load MOD sample waveforms */ + lpPatch = lpModule->aPatchTable; + for (n = 0; n < lpModule->nPatches; n++, lpPatch++) { + memcpy(&Sample, &Header.aSampleTable[n], sizeof(MODSAMPLEHEADER)); + strncpy(lpPatch->szPatchName, Sample.aSampleName, + sizeof(Sample.aSampleName)); + if (Sample.wLength != 0) { + if ((lpSample = (LPAUDIOSAMPLE) + calloc(1, sizeof(AUDIOSAMPLE))) == NULL) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_NOMEMORY; + } + lpPatch->nSamples = 1; + lpPatch->aSampleTable = lpSample; + + /* initialize sample structure */ + lpSample->Wave.wFormat = AUDIO_FORMAT_8BITS; + lpSample->Wave.dwLength = (DWORD) Sample.wLength << 1; + lpSample->Wave.nSampleRate = 8363; + if (Sample.wLoopLength > 1 && Sample.wLoopStart < Sample.wLength) { + lpSample->Wave.wFormat |= AUDIO_FORMAT_LOOP; + lpSample->Wave.dwLoopStart = (DWORD) Sample.wLoopStart << 1; + lpSample->Wave.dwLoopEnd = (DWORD) Sample.wLoopStart << 1; + lpSample->Wave.dwLoopEnd += (DWORD) Sample.wLoopLength << 1; + if (lpSample->Wave.dwLoopEnd > lpSample->Wave.dwLength) + lpSample->Wave.dwLoopEnd = lpSample->Wave.dwLength; + } + lpSample->nVolume = Sample.nVolume <= 64 ? Sample.nVolume : 64; + lpSample->nFinetune = (Sample.nFinetune & 0x0F) << 4; + lpSample->nPanning = 0x80; + + nErrorCode = ACreateAudioData(&lpSample->Wave); + if (nErrorCode != AUDIO_ERROR_NONE) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return nErrorCode; + } + + /* upload waveform data */ + AIOReadFile(lpSample->Wave.lpData, lpSample->Wave.dwLength); + AWriteAudioData(&lpSample->Wave, 0, lpSample->Wave.dwLength); + } + } + + AIOCloseFile(); + *lplpModule = lpModule; + return AUDIO_ERROR_NONE; +} diff --git a/seal-hack/src/mp b/seal-hack/src/mp new file mode 100755 index 0000000..7a9f68f Binary files /dev/null and b/seal-hack/src/mp differ diff --git a/seal-hack/src/mp.c b/seal-hack/src/mp.c new file mode 100644 index 0000000..8c5f11d --- /dev/null +++ b/seal-hack/src/mp.c @@ -0,0 +1,270 @@ +/* + * $Id: mp.c 1.13 1996/09/13 18:18:38 chasan released $ + * + * Module player demonstration + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include "audio.h" + +#if defined(__DOS16__) || defined(__DPMI__) || defined(__WINDOWS__) +#include +#else +#define kbhit() 0 +#endif + +#ifdef __SDL__ +#include"SDL.h" +#endif + +struct { + AUDIOINFO Info; + AUDIOCAPS Caps; + LPAUDIOMODULE lpModule; + UINT nVolume; + BOOL bStopped; +} State; + +void Assert(UINT nErrorCode) +{ + static CHAR szText[80]; + + if (nErrorCode != AUDIO_ERROR_NONE) { + AGetErrorText(nErrorCode, szText, sizeof(szText) - 1); + printf("%s\n", szText); + exit(1); + } +} + +#ifdef __MSC__ +void __cdecl CleanUp(void) +#else + void CleanUp(void) +#endif +{ + ACloseAudio(); +} + +void Banner(void) +{ + +/* BeOS R3 */ +#ifdef __BEOS__ +#define _SYSTEM_ "BeOS" +#endif +/* OS/2 MMPM */ +#ifdef __OS2__ +#define _SYSTEM_ "OS/2 MMPM" +#endif +/* Linux/386 */ +#ifdef __LINUX__ +#define _SYSTEM_ "Linux" +#endif + +/* Darwin/x86_64 */ +#ifdef __OSX__ +#define _SYSTEM_ "MacOS X" +#endif + +/* FreeBSD/386 */ +#ifdef __FREEBSD__ +#define _SYSTEM_ "FreeBSD" +#endif + +/* SunOS 4.1.x */ +#ifdef __SPARC__ +#define _SYSTEM_ "SPARC/SunOS" +#endif + +/* Solaris 2.x */ +#ifdef __SOLARIS__ +#define _SYSTEM_ "SPARC/Solaris" +#endif + +/* IRIX 4.x */ +#ifdef __SILICON__ +#define _SYSTEM_ "SGI/Irix" +#endif + +/* Win32 */ +#if defined(__WINDOWS__) && defined(__FLAT__) +#ifdef __BORLANDC__ +#define _SYSTEM_ "Win32/BC32" +#endif +#ifdef __WATCOMC__ +#define _SYSTEM_ "Win32/WC32" +#endif +#ifdef __MSC__ +#define _SYSTEM_ "Win32/MSC32" +#endif +#endif + +/* Win16 */ +#if defined(__WINDOWS__) && defined(__LARGE__) +#ifdef __BORLANDC__ +#define _SYSTEM_ "Win16/BC16" +#endif +#ifdef __WATCOMC__ +#define _SYSTEM_ "Win16/WC16" +#endif +#endif + +/* DPMI32 */ +#if defined(__DPMI__) && defined(__FLAT__) +#ifdef __BORLANDC__ +#define _SYSTEM_ "DPMI32/BC32" +#endif +#ifdef __WATCOMC__ +#define _SYSTEM_ "DOS4GW/WC32" +#endif +#endif +#if defined(__DPMI__) && defined(__DJGPP__) +#define _SYSTEM_ "DPMI32/DJGPP" +#endif + +/* DPMI16 */ +#if defined(__DPMI__) && defined(__LARGE__) +#ifdef __BORLANDC__ +#define _SYSTEM_ "DPMI16/BC16" +#endif +#endif + +/* DOS */ +#if defined(__DOS16__) && defined(__LARGE__) +#ifdef __BORLANDC__ +#define _SYSTEM_ "DOS/BC16" +#endif +#ifdef __WATCOMC__ +#define _SYSTEM_ "DOS/WC16" +#endif +#endif + +#ifndef _SYSTEM_ +#define _SYSTEM_ "UNKNOWN" +#endif + + printf("MOD/MTM/S3M/XM Module Player Version 0.6 (" _SYSTEM_ " version)\n"); + printf("Please send bug reports to: chasan@dcc.uchile.cl\n"); +} + +void Usage(void) +{ + UINT n; + + printf("Usage: mp [options] file...\n"); + printf(" -c device select audio device\n"); + for (n = 0; n < AGetAudioNumDevs(); n++) { + AGetAudioDevCaps(n, &State.Caps); + printf("\t\t%d=%s\n", n, State.Caps.szProductName); + } + printf(" -r rate set sampling rate\n"); + printf(" -v volume change global volume\n"); + printf(" -8 8-bit sample precision\n"); + printf(" -m monophonic output\n"); + printf(" -i enable filtering\n"); + printf("\n"); + exit(0); +} + +int main(int argc, char *argv[]) +{ + LPSTR lpszOption, lpszOptArg, lpszFileName; + int n; + + /* initialize the audio system library */ + AInitialize(); + + /* display program information */ + Banner(); + if (argc < 2) Usage(); + + /* setup default initialization parameters */ + State.Info.nDeviceId = AUDIO_DEVICE_MAPPER; + State.Info.wFormat = AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO; + State.Info.nSampleRate = 44100; + State.nVolume = 96; + + /* parse command line options */ + for (n = 1; n < argc && (lpszOption = argv[n])[0] == '-'; n++) { + lpszOptArg = &lpszOption[2]; + if (strchr("crv", lpszOption[1]) && !lpszOptArg[0] && n < argc - 1) + lpszOptArg = argv[++n]; + switch (lpszOption[1]) { + case 'c': + State.Info.nDeviceId = atoi(lpszOptArg); + break; + case '8': + State.Info.wFormat &= ~AUDIO_FORMAT_16BITS; + break; + case 'm': + State.Info.wFormat &= ~AUDIO_FORMAT_STEREO; + break; + case 'i': + State.Info.wFormat |= AUDIO_FORMAT_FILTER; + break; + case 'r': + State.Info.nSampleRate = (UINT) atoi(lpszOptArg); + if (State.Info.nSampleRate < 1000) + State.Info.nSampleRate *= 1000; + break; + case 'v': + State.nVolume = atoi(lpszOptArg); + break; + default: + Usage(); + break; + } + } + + /* initialize and open the audio system */ + Assert(AOpenAudio(&State.Info)); + atexit(CleanUp); + + /* display playback audio device information */ + Assert(AGetAudioDevCaps(State.Info.nDeviceId, &State.Caps)); + printf("%s playing at %d-bit %s %u Hz\n", State.Caps.szProductName, + State.Info.wFormat & AUDIO_FORMAT_16BITS ? 16 : 8, + State.Info.wFormat & AUDIO_FORMAT_STEREO ? "stereo" : "mono", + State.Info.nSampleRate); + + while (n < argc && (lpszFileName = argv[n++]) != NULL) { + /* load module file from disk */ + printf("Loading: %s\n", lpszFileName); + Assert(ALoadModuleFile(lpszFileName, &State.lpModule, 0L)); + + /* play the module file */ + printf("Playing: %s\n", State.lpModule->szModuleName); + Assert(AOpenVoices(State.lpModule->nTracks)); + Assert(APlayModule(State.lpModule)); + Assert(ASetAudioMixerValue(AUDIO_MIXER_MASTER_VOLUME, State.nVolume)); +#if defined(__WINDOWS__) || defined(__BEOS__) + printf("Press enter to quit\n"); + getchar(); +#else + while (!kbhit()) { + Assert(AGetModuleStatus(&State.bStopped)); + if (State.bStopped) break; + Assert(AUpdateAudio()); +#ifdef __SDL__ + SDL_Delay(10); /* don't peg the cpu, 'k? */ +#endif + } +#endif + Assert(AStopModule()); + Assert(ACloseVoices()); + + /* release the module file */ + Assert(AFreeModuleFile(State.lpModule)); + } + + return 0; +} diff --git a/seal-hack/src/msdos.c b/seal-hack/src/msdos.c new file mode 100644 index 0000000..463a74e --- /dev/null +++ b/seal-hack/src/msdos.c @@ -0,0 +1,560 @@ +/* + * $Id: msdos.c 1.7 1996/08/15 02:33:44 chasan released $ + * + * MS-DOS hardware programming API interface. + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include "audio.h" +#include "msdos.h" + + +/* + * MS-DOS direct memory access API routines + */ +static BYTE aDmaSingle[8] = +{ + DMA1_SNGL, DMA1_SNGL, DMA1_SNGL, DMA1_SNGL, + DMA2_SNGL, DMA2_SNGL, DMA2_SNGL, DMA2_SNGL +}; + +static BYTE aDmaMode[8] = +{ + DMA1_MODE, DMA1_MODE, DMA1_MODE, DMA1_MODE, + DMA2_MODE, DMA2_MODE, DMA2_MODE, DMA2_MODE +}; + +static BYTE aDmaClear[8] = +{ + DMA1_CLRFF, DMA1_CLRFF, DMA1_CLRFF, DMA1_CLRFF, + DMA2_CLRFF, DMA2_CLRFF, DMA2_CLRFF, DMA2_CLRFF +}; + +static BYTE aDmaPage[8] = +{ + DMA0_PAGE, DMA1_PAGE, DMA2_PAGE, DMA3_PAGE, + DMA4_PAGE, DMA5_PAGE, DMA6_PAGE, DMA7_PAGE +}; + +static BYTE aDmaAddr[8] = +{ + DMA0_ADDR, DMA1_ADDR, DMA2_ADDR, DMA3_ADDR, + DMA4_ADDR, DMA5_ADDR, DMA6_ADDR, DMA7_ADDR +}; + +static BYTE aDmaCount[8] = +{ + DMA0_CNT, DMA1_CNT, DMA2_CNT, DMA3_CNT, + DMA4_CNT, DMA5_CNT, DMA6_CNT, DMA7_CNT +}; + +static DWORD aDmaLinearAddress[8] = +{ + 0x00000, 0x00000, 0x00000, 0x00000, + 0x00000, 0x00000, 0x00000, 0x00000 +}; + +static WORD aDmaBufferLength[8] = +{ + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + + +VOID AIAPI DosSetupChannel(UINT nChannel, BYTE nMode, WORD nCount) +{ + WORD wAddr; + BYTE nPage; + + if (nChannel <= 7) { + /* check out the count parameter */ + if (nCount <= 0 || nCount >= aDmaBufferLength[nChannel]) + nCount = aDmaBufferLength[nChannel]; + + /* get buffer physical address and length */ + if (nChannel >= 4) { + wAddr = LOWORD(aDmaLinearAddress[nChannel] >> 1); + nPage = (BYTE) HIWORD(aDmaLinearAddress[nChannel]); + nCount >>= 1; + } + else { + wAddr = LOWORD(aDmaLinearAddress[nChannel]); + nPage = (BYTE) HIWORD(aDmaLinearAddress[nChannel]); + } + nCount--; + + /* disable DMA channel before setting parameters */ + OUTB(aDmaSingle[nChannel], (nChannel & 0x03) | DMA_DISABLE); + + /* set DMA channel transfer mode */ + OUTB(aDmaMode[nChannel], (nChannel & 0x03) | nMode); + + /* set DMA channel buffer physical address */ + OUTB(aDmaClear[nChannel], 0x00); + OUTB(aDmaAddr[nChannel], LOBYTE(wAddr)); + OUTB(aDmaAddr[nChannel], HIBYTE(wAddr)); + OUTB(aDmaPage[nChannel], nPage); + + /* set DMA channel buffer length */ + OUTB(aDmaClear[nChannel], 0x00); + OUTB(aDmaCount[nChannel], LOBYTE(nCount)); + OUTB(aDmaCount[nChannel], HIBYTE(nCount)); + + /* enable DMA channel for transfers */ + OUTB(aDmaSingle[nChannel], (nChannel & 0x03) | DMA_ENABLE); + } +} + +VOID AIAPI DosDisableChannel(UINT nChannel) +{ + if (nChannel <= 7) { + OUTB(aDmaSingle[nChannel], (nChannel & 0x03) | DMA_DISABLE); + } +} + +VOID AIAPI DosEnableChannel(UINT nChannel) +{ + if (nChannel <= 7) { + OUTB(aDmaSingle[nChannel], (nChannel & 0x03) | DMA_ENABLE); + } +} + +UINT AIAPI DosGetChannelCount(UINT nChannel) +{ + INT nTimeOut, nCount, nDelta, nLoData, nHiData; + + if (nChannel <= 7) { + /* clear DMA channel flip-flop register */ + OUTB(aDmaClear[nChannel], 0x00); + + for (nTimeOut = 0; nTimeOut < 1024; nTimeOut++) { + /* poll DMA channel count register */ + nLoData = INB(aDmaCount[nChannel]); + nHiData = INB(aDmaCount[nChannel]); + nCount = MAKEWORD(nLoData, nHiData); + nLoData = INB(aDmaCount[nChannel]); + nHiData = INB(aDmaCount[nChannel]); + nDelta = MAKEWORD(nLoData, nHiData); + if ((nDelta -= nCount) > -16 && nDelta < +16) + break; + } + + /* adjust counter for 16 bit DMA channels */ + if (nChannel >= 4) + nCount <<= 1; + return nCount + 1; + } + return 0; +} + + +/* + * 16-bit real mode custom DMA programming API routines + */ + +#ifdef __DOS16__ + +static LPVOID aDmaBufferAddr[8] = +{ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +UINT AIAPI DosAllocChannel(UINT nChannel, WORD nCount) +{ + DWORD dwAddress; + + /* + * Allocate DOS memory using standard memory allocation + * routines for Borland C++ 3.1 in real mode. + */ + if (nChannel <= 7 && + (aDmaBufferAddr[nChannel] = malloc(nCount << 1)) != NULL) { + dwAddress = ((DWORD) FP_SEG(aDmaBufferAddr[nChannel]) << 4) + + FP_OFF(aDmaBufferAddr[nChannel]); + if ((dwAddress & 0xFFFFL) + nCount > 0x10000L) + dwAddress += 0x10000L - (dwAddress & 0xFFFFL); + aDmaLinearAddress[nChannel] = dwAddress; + aDmaBufferLength[nChannel] = nCount; + return 0; + } + return 1; +} + +VOID AIAPI DosFreeChannel(UINT nChannel) +{ + if (nChannel <= 7 && aDmaBufferAddr[nChannel]) { + free(aDmaBufferAddr[nChannel]); + aDmaBufferAddr[nChannel] = NULL; + } +} + +LPVOID AIAPI DosLockChannel(UINT nChannel) +{ + DWORD dwAddress; + + if (nChannel <= 7) { + dwAddress = aDmaLinearAddress[nChannel]; + return MK_FP((unsigned) (dwAddress >> 4), + (unsigned) (dwAddress & 0x000F)); + } + return NULL; +} + +VOID AIAPI DosUnlockChannel(UINT nChannel) +{ + if (nChannel <= 7) { + } +} + +#endif + + +/* + * 16/32-bit protected mode DPMI custom DMA programming API routines + */ + +#if defined(__DPMI__) && !defined(__DJGPP__) + +static WORD aDmaBufferSelector[8] = +{ + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +UINT AIAPI DosAllocChannel(UINT nChannel, WORD nCount) +{ + static DOSREGS r; + DWORD dwAddress; + + /* + * Allocate DOS memory using a DPMI system call, works with DOS/4GW + * and PMODE/W 32-bit DOS extenders, Borland's DPMI16 and DPMI32, + * and with DJGPP V2 32-bit DPMI host. + */ + if (nChannel <= 7) { + r.ax = 0x0100; + r.bx = ((nCount << 1) + 15) >> 4; + DosIntVector(0x31, &r); + if (!r.cflag) { + dwAddress = (DWORD) r.ax << 4; + if ((dwAddress & 0xFFFF) + nCount > 0x10000L) + dwAddress += 0x10000L - (dwAddress & 0xFFFFL); + aDmaBufferSelector[nChannel] = r.dx; + aDmaLinearAddress[nChannel] = dwAddress; + aDmaBufferLength[nChannel] = nCount; + return 0; + } + } + return 1; +} + +VOID AIAPI DosFreeChannel(UINT nChannel) +{ + static DOSREGS r; + + if (nChannel <= 7 && aDmaBufferSelector[nChannel]) { + r.ax = 0x0101; + r.dx = aDmaBufferSelector[nChannel]; + DosIntVector(0x31, &r); + aDmaBufferSelector[nChannel] = 0x0000; + } +} + +LPVOID AIAPI DosLockChannel(UINT nChannel) +{ + if (nChannel <= 7) { +#ifdef __FLAT__ + /* TODO: This only works in DOS4GW and PMODEW extenders. */ + return (LPVOID) aDmaLinearAddress[nChannel]; +#else + return MK_FP(aDmaBufferSelector[nChannel], 0x0000); +#endif + } + return NULL; +} + +VOID AIAPI DosUnlockChannel(UINT nChannel) +{ + if (nChannel <= 7) { + } +} + +#endif + + +/* + * DJGPP V2 custom DMA programming routines + */ + +#ifdef __DJGPP__ + +static WORD aDmaBufferSelector[8] = +{ + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +UINT AIAPI DosAllocChannel(UINT nChannel, WORD nCount) +{ + DWORD dwAddress; + UINT nSelector; + + /* + * Allocate DOS memory using a DPMI system call + * for DJGPP V2 in 32-bit protected mode. + */ + if (nChannel <= 7) { + if (__dpmi_allocate_dos_memory(((nCount << 1) + 15) >> 4, &nSelector) != -1) { + __dpmi_get_segment_base_address(nSelector, &dwAddress); + if ((dwAddress & 0xFFFFL) + nCount > 0x10000L) + dwAddress += 0x10000L - (dwAddress & 0xFFFFL); + aDmaBufferSelector[nChannel] = nSelector; + aDmaLinearAddress[nChannel] = dwAddress; + aDmaBufferLength[nChannel] = nCount; + return 0; + } + } + return 1; +} + +VOID AIAPI DosFreeChannel(UINT nChannel) +{ + if (nChannel <= 7 && aDmaBufferSelector[nChannel]) { + __dpmi_free_dos_memory(aDmaBufferSelector[nChannel]); + aDmaBufferSelector[nChannel] = 0x0000; + } +} + +LPVOID AIAPI DosLockChannel(UINT nChannel) +{ + if (nChannel <= 7 && ((_crt0_startup_flags & _CRT0_FLAG_NEARPTR) || + __djgpp_nearptr_enable())) { + return (LPVOID) (aDmaLinearAddress[nChannel] + + __djgpp_conventional_base); + } + return NULL; +} + +VOID AIAPI DosUnlockChannel(UINT nChannel) +{ + if (nChannel <= 7 && !(_crt0_startup_flags & _CRT0_FLAG_NEARPTR)) { + __djgpp_nearptr_disable(); + } +} +#endif + + + +/* + * MS-DOS interrupt programming API routines + */ + +#ifdef __BORLANDC__ +typedef VOID __interrupt (*LPFNHARDWAREVECTOR)(VOID); +#endif + +#ifdef __WATCOMC__ +typedef VOID (__interrupt* LPFNHARDWAREVECTOR)(VOID); +#endif + +#ifdef __DJGPP__ +typedef _go32_dpmi_seginfo LPFNHARDWAREVECTOR; +#define __interrupt +#endif + +static BYTE aIrqSlotNumber[16] = +{ + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77 +}; + +static LPFNUSERVECTOR aUserVector[16] = +{ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +static LPFNHARDWAREVECTOR aHardwareVector[16]; + + +static VOID MasterWrapVector(UINT nIrqLine) +{ + if (aUserVector[nIrqLine] != NULL) + (*aUserVector[nIrqLine])(); + if (nIrqLine >= 8) + OUTB(0xA0, 0x20); + OUTB(0x20, 0x20); +} + +#define WRAPVECTOR(name, num) \ +static VOID __interrupt name (VOID) { MasterWrapVector(num); } + +WRAPVECTOR(Wrap0Vector, 0x00) + WRAPVECTOR(Wrap1Vector, 0x01) + WRAPVECTOR(Wrap2Vector, 0x02) + WRAPVECTOR(Wrap3Vector, 0x03) + WRAPVECTOR(Wrap4Vector, 0x04) + WRAPVECTOR(Wrap5Vector, 0x05) + WRAPVECTOR(Wrap6Vector, 0x06) + WRAPVECTOR(Wrap7Vector, 0x07) + WRAPVECTOR(Wrap8Vector, 0x08) + WRAPVECTOR(Wrap9Vector, 0x09) + WRAPVECTOR(WrapAVector, 0x0A) + WRAPVECTOR(WrapBVector, 0x0B) + WRAPVECTOR(WrapCVector, 0x0C) + WRAPVECTOR(WrapDVector, 0x0D) + WRAPVECTOR(WrapEVector, 0x0E) + WRAPVECTOR(WrapFVector, 0x0F) + +#ifdef __DJGPP__ + static LPFNUSERVECTOR aWrapVector[16] = +#else +static LPFNHARDWAREVECTOR aWrapVector[16] = +#endif +{ + Wrap0Vector, Wrap1Vector, Wrap2Vector, Wrap3Vector, + Wrap4Vector, Wrap5Vector, Wrap6Vector, Wrap7Vector, + Wrap8Vector, Wrap9Vector, WrapAVector, WrapBVector, + WrapCVector, WrapDVector, WrapEVector, WrapFVector +}; + + +VOID AIAPI DosEnableVectorHandler(UINT nIrqLine) +{ + WORD wIrqMask; + + if (nIrqLine <= 15) { + if (nIrqLine == 2) nIrqLine = 9; + wIrqMask = MAKEWORD(INB(0x21), INB(0xA1)) & ~(1 << nIrqLine); + OUTB(0x21, LOBYTE(wIrqMask)); + OUTB(0xA1, HIBYTE(wIrqMask)); + } +} + +VOID AIAPI DosDisableVectorHandler(UINT nIrqLine) +{ + WORD wIrqMask; + + if (nIrqLine <= 15) { + if (nIrqLine == 2) nIrqLine = 9; + wIrqMask = MAKEWORD(INB(0x21), INB(0xA1)) | (1 << nIrqLine); + OUTB(0x21, LOBYTE(wIrqMask)); + OUTB(0xA1, HIBYTE(wIrqMask)); + } +} + +VOID AIAPI DosSetVectorHandler(UINT nIrqLine, LPFNUSERVECTOR lpfnUserVector) +{ +#ifdef __DJGPP__ + _go32_dpmi_seginfo wrapper; +#endif + UINT nIntr; + + if (nIrqLine <= 15) { + if (nIrqLine == 2) nIrqLine = 9; + nIntr = aIrqSlotNumber[nIrqLine]; + if (lpfnUserVector != NULL) { + if (!aUserVector[nIrqLine]) { +#ifdef __DJGPP__ + _go32_dpmi_get_protected_mode_interrupt_vector(nIntr, &aHardwareVector[nIrqLine]); + wrapper.pm_offset = (DWORD) aWrapVector[nIrqLine]; + wrapper.pm_selector = _go32_my_cs(); + _go32_dpmi_allocate_iret_wrapper(&wrapper); + _go32_dpmi_set_protected_mode_interrupt_vector(nIntr, &wrapper); +#else + aHardwareVector[nIrqLine] = _dos_getvect(nIntr); + _dos_setvect(nIntr, aWrapVector[nIrqLine]); +#endif + DosEnableVectorHandler(nIrqLine); + } + } + else { + if (aUserVector[nIrqLine]) { + DosDisableVectorHandler(nIrqLine); +#ifdef __DJGPP__ + _go32_dpmi_get_protected_mode_interrupt_vector(nIntr, &wrapper); + _go32_dpmi_set_protected_mode_interrupt_vector(nIntr, &aHardwareVector[nIrqLine]); + _go32_dpmi_free_iret_wrapper(&wrapper); +#else + _dos_setvect(nIntr, aHardwareVector[nIrqLine]); +#endif + } + } + aUserVector[nIrqLine] = lpfnUserVector; + } +} + +VOID AIAPI DosIntVector(UINT nIntr, LPDOSREGS lpRegs) +{ + static union REGS r; + + memset(&r, 0, sizeof(r)); +#ifdef __FLAT__ + r.w.ax = lpRegs->ax; + r.w.bx = lpRegs->bx; + r.w.cx = lpRegs->cx; + r.w.dx = lpRegs->dx; + r.w.si = lpRegs->si; + r.w.di = lpRegs->di; + int386(nIntr, &r, &r); + lpRegs->ax = r.w.ax; + lpRegs->bx = r.w.bx; + lpRegs->cx = r.w.cx; + lpRegs->dx = r.w.dx; + lpRegs->si = r.w.si; + lpRegs->di = r.w.di; + lpRegs->cflag = r.x.cflag; +#else + r.x.ax = lpRegs->ax; + r.x.bx = lpRegs->bx; + r.x.cx = lpRegs->cx; + r.x.dx = lpRegs->dx; + r.x.si = lpRegs->si; + r.x.di = lpRegs->di; + int86(nIntr, &r, &r); + lpRegs->ax = r.x.ax; + lpRegs->bx = r.x.bx; + lpRegs->cx = r.x.cx; + lpRegs->dx = r.x.dx; + lpRegs->si = r.x.si; + lpRegs->di = r.x.di; + lpRegs->cflag = r.x.cflag; +#endif +} + + +LPSTR AIAPI DosGetEnvironment(LPSTR lpszKeyName) +{ + return getenv(lpszKeyName); +} + +UINT AIAPI DosParseString(LPSTR lpszText, UINT nToken) +{ + static LPSTR lpszString = NULL; + + if (lpszText != NULL) + lpszString = lpszText; + + if (lpszString != NULL) { + if (nToken == TOKEN_CHAR) { + return *lpszString++; + } + if (nToken == TOKEN_DEC) { + return strtol(lpszString, &lpszString, 10); + } + if (nToken == TOKEN_HEX) { + return strtol(lpszString, &lpszString, 0x10); + } + } + return BAD_TOKEN; +} + diff --git a/seal-hack/src/msdos.h b/seal-hack/src/msdos.h new file mode 100644 index 0000000..ea5ff0d --- /dev/null +++ b/seal-hack/src/msdos.h @@ -0,0 +1,179 @@ +/* + * $Id: msdos.h 1.5 1996/08/05 18:51:19 chasan released $ + * + * MS-DOS hardware programming API interface. + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __MSDOS_H +#define __MSDOS_H + +#ifdef __BORLANDC__ +#include +#include +#endif + +#ifdef __WATCOMC__ +#include +#include +#include +#endif + +#ifdef __DJGPP__ +#include +#include +#include +#include +#include +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * I/O address space macro routines + */ +#ifdef __BORLANDC__ +#define INB inportb +#define INW inport +#define OUTB outportb +#define OUTW outport +#endif + +#ifdef __WATCOMC__ +#define INB inp +#define INW inpw +#define OUTB outp +#define OUTW outpw +#endif + +#ifdef __DJGPP__ +#define INB inportb +#define INW inportw +#define OUTB outportb +#define OUTW outportw +#endif + +/* + * 8-bit DMA controller register ports + */ +#define DMA1_STAT 0x08 +#define DMA1_WCMD 0x08 +#define DMA1_WREQ 0x09 +#define DMA1_SNGL 0x0A +#define DMA1_MODE 0x0B +#define DMA1_CLRFF 0x0C +#define DMA1_MCLR 0x0D +#define DMA1_CLRM 0x0E +#define DMA1_WRTALL 0x0F + +/* + * 16-bit DMA controller register ports + */ +#define DMA2_STAT 0xD0 +#define DMA2_WCMD 0xD0 +#define DMA2_WREQ 0xD2 +#define DMA2_SNGL 0xD4 +#define DMA2_MODE 0xD6 +#define DMA2_CLRFF 0xD8 +#define DMA2_MCLR 0xDA +#define DMA2_CLRM 0xDC +#define DMA2_WRTALL 0xDE + +/* + * DMA controllers base address and count registers + */ +#define DMA0_ADDR 0x00 +#define DMA0_CNT 0x01 +#define DMA1_ADDR 0x02 +#define DMA1_CNT 0x03 +#define DMA2_ADDR 0x04 +#define DMA2_CNT 0x05 +#define DMA3_ADDR 0x06 +#define DMA3_CNT 0x07 +#define DMA4_ADDR 0xC0 +#define DMA4_CNT 0xC2 +#define DMA5_ADDR 0xC4 +#define DMA5_CNT 0xC6 +#define DMA6_ADDR 0xC8 +#define DMA6_CNT 0xCA +#define DMA7_ADDR 0xCC +#define DMA7_CNT 0xCE + +#define DMA0_PAGE 0x87 +#define DMA1_PAGE 0x83 +#define DMA2_PAGE 0x81 +#define DMA3_PAGE 0x82 +#define DMA4_PAGE 0x8F +#define DMA5_PAGE 0x8B +#define DMA6_PAGE 0x89 +#define DMA7_PAGE 0x8A + +/* + * DMA controller mode bit fields + */ +#define DMA_ENABLE 0x00 +#define DMA_DISABLE 0x04 +#define DMA_AUTOINIT 0x10 +#define DMA_READ 0x44 +#define DMA_WRITE 0x48 + +/* + * PIC hardware interrupt callback routine + */ + typedef VOID (AIAPI* LPFNUSERVECTOR)(VOID); + + typedef struct { + WORD ax; + WORD bx; + WORD cx; + WORD dx; + WORD si; + WORD di; + WORD cflag; + } DOSREGS, *LPDOSREGS; + + +/* + * DOS environment parsing token types + */ +#define TOKEN_CHAR 0x00 +#define TOKEN_DEC 0x01 +#define TOKEN_HEX 0x02 +#define BAD_TOKEN 0xFFFFU + + +/* + * MS-DOS hardware programming API interface + */ + VOID AIAPI DosSetVectorHandler(UINT nIrqLine, LPFNUSERVECTOR lpfnUserVector); + VOID AIAPI DosEnableVectorHandler(UINT nIrqLine); + VOID AIAPI DosDisableVectorHandler(UINT nIrqLine); + + VOID AIAPI DosSetupChannel(UINT nChannel, BYTE nMode, WORD nCount); + VOID AIAPI DosDisableChannel(UINT nChannel); + VOID AIAPI DosEnableChannel(UINT nChannel); + UINT AIAPI DosGetChannelCount(UINT nChannel); + UINT AIAPI DosAllocChannel(UINT nChannel, WORD nCount); + VOID AIAPI DosFreeChannel(UINT nChannel); + LPVOID AIAPI DosLockChannel(UINT nChannel); + VOID AIAPI DosUnlockChannel(UINT nChannel); + + VOID AIAPI DosIntVector(UINT nIntr, LPDOSREGS lpRegs); + + LPSTR AIAPI DosGetEnvironment(LPSTR lpszKeyName); + UINT AIAPI DosParseString(LPSTR lpszText, UINT nToken); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/seal-hack/src/mtmfile.c b/seal-hack/src/mtmfile.c new file mode 100644 index 0000000..f0054f4 --- /dev/null +++ b/seal-hack/src/mtmfile.c @@ -0,0 +1,299 @@ +/* + * $Id: mtmfile.c 1.1 1996/09/25 17:19:14 chasan released $ + * + * Multitracker 1.0 module file loader + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include "audio.h" +#include "iofile.h" + +/* + * MTM file header signature defines + */ +#define MTM_SIGN_PATTERN 0x104D544DL +#define MTM_SIGN_MASK 0xF0FFFFFFL + +/* + * MTM module header structure + */ +typedef struct { + DWORD dwMTM; + CHAR szModuleName[20]; + WORD nSeqTracks; + BYTE nPatterns; + BYTE nOrders; + WORD nMesgSize; + BYTE nSamples; + BYTE bFlags; + BYTE nBeatsPerTrack; + BYTE nChannels; + BYTE aPanningTable[32]; +} MTMHEADER, *LPMTMHEADER; + +/* + * MTM sample header structure + */ +typedef struct { + CHAR szSampleName[22]; + DWORD dwLength; + DWORD dwLoopStart; + DWORD dwLoopEnd; + BYTE nFinetune; + BYTE nVolume; + BYTE bFlags; +} MTMSAMPLE, *LPMTMSAMPLE; + +/* + * MTM track data structure + */ +typedef struct { + BYTE aData[3*64]; +} MTMTRACK, *LPMTMTRACK; + + +static UINT MTMMakePattern(UINT nTracks, UINT nSeqTracks, + LPAUDIOPATTERN lpPattern, WORD aPatSeqTable[32], LPMTMTRACK lpTrackTable) +{ + LPBYTE lpData, lpEvent; + UINT nRowOfs, nTrack; + UINT fFlags, nNote, nSample, nCommand, nParams; + + if ((lpData = (LPBYTE) malloc(64*5*nTracks)) == NULL) + return AUDIO_ERROR_NOMEMORY; + + lpPattern->lpData = lpData; + lpPattern->nPacking = 0; + lpPattern->nTracks = nTracks; + lpPattern->nRows = 64; + for (nRowOfs = 0; nRowOfs < 3*64; nRowOfs += 3) { + for (nTrack = 0; nTrack < nTracks; nTrack++) { + if (aPatSeqTable[nTrack] >= 1 && + aPatSeqTable[nTrack] <= nSeqTracks) { + lpEvent = &lpTrackTable[aPatSeqTable[nTrack]-1].aData[nRowOfs]; + nNote = (lpEvent[0] >> 2) & 0x3F; + nSample = ((lpEvent[0] & 0x03) << 4) | (lpEvent[1] >> 4); + nCommand = (lpEvent[1] & 0x0F); + nParams = lpEvent[2]; + fFlags = AUDIO_PATTERN_PACKED; + if (nNote) { + nNote += 12*2 + 1; + fFlags |= AUDIO_PATTERN_NOTE; + } + if (nSample) + fFlags |= AUDIO_PATTERN_SAMPLE; + if (nCommand) + fFlags |= AUDIO_PATTERN_COMMAND; + if (nParams) + fFlags |= AUDIO_PATTERN_PARAMS; + *lpData++ = fFlags; + if (fFlags & AUDIO_PATTERN_NOTE) + *lpData++ = nNote; + if (fFlags & AUDIO_PATTERN_SAMPLE) + *lpData++ = nSample; + if (fFlags & AUDIO_PATTERN_COMMAND) + *lpData++ = nCommand; + if (fFlags & AUDIO_PATTERN_PARAMS) + *lpData++ = nParams; + } + else { + *lpData++ = AUDIO_PATTERN_PACKED; + } + } + } + + lpPattern->nSize = lpData - lpPattern->lpData; + if ((lpPattern->lpData = (LPBYTE) + realloc(lpPattern->lpData, lpPattern->nSize)) == NULL) + return AUDIO_ERROR_NOMEMORY; + + return AUDIO_ERROR_NONE; +} + +static UINT MTMMakeSample(LPAUDIOPATCH lpPatch, LPMTMSAMPLE lpMTMSample) +{ + LPAUDIOSAMPLE lpSample; + LPBYTE lpData; + DWORD dwCount; + UINT rc; + + strncpy(lpPatch->szPatchName, lpMTMSample->szSampleName, + sizeof(lpMTMSample->szSampleName)); + if (lpMTMSample->dwLength) { + if ((lpSample = (LPAUDIOSAMPLE) calloc(1, sizeof(AUDIOSAMPLE))) == NULL) + return AUDIO_ERROR_NOMEMORY; + + lpPatch->nSamples = 1; + lpPatch->aSampleTable = lpSample; + lpSample->Wave.wFormat = AUDIO_FORMAT_8BITS | AUDIO_FORMAT_MONO; + lpSample->Wave.dwLength = lpMTMSample->dwLength; + lpSample->nVolume = lpMTMSample->nVolume; + lpSample->nFinetune = lpMTMSample->nFinetune; + lpSample->nPanning = 0x80; + if (lpMTMSample->dwLoopStart + 2 < lpMTMSample->dwLoopEnd && + lpMTMSample->dwLoopEnd <= lpMTMSample->dwLength) { + lpSample->Wave.wFormat |= AUDIO_FORMAT_LOOP; + lpSample->Wave.dwLoopStart = lpMTMSample->dwLoopStart; + lpSample->Wave.dwLoopEnd = lpMTMSample->dwLoopEnd; + } + if ((rc = ACreateAudioData(&lpSample->Wave)) != AUDIO_ERROR_NONE) + return rc; + AIOReadFile(lpSample->Wave.lpData, lpSample->Wave.dwLength); + lpData = lpSample->Wave.lpData; + dwCount = lpSample->Wave.dwLength; + while (dwCount--) + *lpData++ ^= 0x80; + AWriteAudioData(&lpSample->Wave, 0, lpSample->Wave.dwLength); + } + return AUDIO_ERROR_NONE; +} + +UINT AIAPI ALoadModuleMTM(LPSTR lpszFileName, + LPAUDIOMODULE* lplpModule, DWORD dwFileOffset) +{ + LPAUDIOMODULE lpModule; + static MTMHEADER Header; + LPMTMSAMPLE lpSampleTable; + LPMTMTRACK lpTrackTable; + static WORD aPatSeqTable[32]; + UINT n, rc; + + if (AIOOpenFile(lpszFileName)) { + return AUDIO_ERROR_FILENOTFOUND; + } + AIOSeekFile(dwFileOffset, SEEK_SET); + + if ((lpModule = (LPAUDIOMODULE) calloc(1, sizeof(AUDIOMODULE))) == NULL) { + AIOCloseFile(); + return AUDIO_ERROR_NOMEMORY; + } + + /* load MTM module header data */ + AIOReadLong(&Header.dwMTM); + AIOReadFile(Header.szModuleName, sizeof(Header.szModuleName)); + AIOReadShort(&Header.nSeqTracks); + AIOReadChar(&Header.nPatterns); + AIOReadChar(&Header.nOrders); + AIOReadShort(&Header.nMesgSize); + AIOReadChar(&Header.nSamples); + AIOReadChar(&Header.bFlags); + AIOReadChar(&Header.nBeatsPerTrack); + AIOReadChar(&Header.nChannels); + AIOReadFile(Header.aPanningTable, sizeof(Header.aPanningTable)); + + /* check MTM file header signature and other fields */ + if ((Header.dwMTM & MTM_SIGN_MASK) != MTM_SIGN_PATTERN || +/*** (Header.nPatterns > AUDIO_MAX_PATTERNS) || FIX: avoid warnings ***/ +/*** (Header.nOrders > AUDIO_MAX_ORDERS) || FIX: avoid warnings ***/ + (Header.nSamples > AUDIO_MAX_PATCHES) || + (Header.nChannels > AUDIO_MAX_VOICES) || + (Header.nBeatsPerTrack != 64)) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_BADFILEFORMAT; + } + + /* build the local module header structure */ + strncpy(lpModule->szModuleName, Header.szModuleName, + sizeof(Header.szModuleName)); + lpModule->wFlags = AUDIO_MODULE_AMIGA | AUDIO_MODULE_PANNING; + lpModule->nOrders = Header.nOrders + 1; + lpModule->nRestart = AUDIO_MAX_ORDERS; + lpModule->nTracks = Header.nChannels; + lpModule->nPatterns = Header.nPatterns + 1; + lpModule->nPatches = Header.nSamples; + lpModule->nTempo = 6; + lpModule->nBPM = 125; + for (n = 0; n < lpModule->nTracks; n++) { + lpModule->aPanningTable[n] = Header.aPanningTable[n] << 4; + } + + /* allocate space for local patterns and patches */ + if ((lpModule->aPatternTable = (LPAUDIOPATTERN) + calloc(lpModule->nPatterns, sizeof(AUDIOPATTERN))) == NULL) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_NOMEMORY; + } + if ((lpModule->aPatchTable = (LPAUDIOPATCH) + calloc(lpModule->nPatches, sizeof(AUDIOPATCH))) == NULL) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_NOMEMORY; + } + + /* allocate space for MTM samples and track structures */ + if ((lpSampleTable = (LPMTMSAMPLE) + calloc(Header.nSamples, sizeof(MTMSAMPLE))) == NULL) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_NOMEMORY; + } + if ((lpTrackTable = (LPMTMTRACK) + calloc(Header.nSeqTracks, sizeof(MTMTRACK))) == NULL) { + free(lpSampleTable); + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_NOMEMORY; + } + + /* load MTM sample header structures */ + for (n = 0; n < lpModule->nPatches; n++) { + AIOReadFile(lpSampleTable[n].szSampleName, + sizeof(lpSampleTable[n].szSampleName)); + AIOReadLong(&lpSampleTable[n].dwLength); + AIOReadLong(&lpSampleTable[n].dwLoopStart); + AIOReadLong(&lpSampleTable[n].dwLoopEnd); + AIOReadChar(&lpSampleTable[n].nFinetune); + AIOReadChar(&lpSampleTable[n].nVolume); + AIOReadChar(&lpSampleTable[n].bFlags); + } + + /* load the MTM module order list */ + AIOReadFile(lpModule->aOrderTable, 128); + + /* load MTM module tracks from disk */ + AIOReadFile(lpTrackTable, sizeof(MTMTRACK) * Header.nSeqTracks); + + /* build module patterns from tracks */ + for (n = 0; n < lpModule->nPatterns; n++) { + AIOReadFile(aPatSeqTable, sizeof(aPatSeqTable)); + rc = MTMMakePattern(lpModule->nTracks, Header.nSeqTracks, + &lpModule->aPatternTable[n], aPatSeqTable, lpTrackTable); + if (rc != AUDIO_ERROR_NONE) { + free(lpTrackTable); + free(lpSampleTable); + AFreeModuleFile(lpModule); + AIOCloseFile(); + return rc; + } + } + free(lpTrackTable); + + /* skip MTM comment message data */ + AIOSeekFile(Header.nMesgSize, SEEK_CUR); + + /* build module patches and samples structures */ + for (n = 0; n < lpModule->nPatches; n++) { + rc = MTMMakeSample(&lpModule->aPatchTable[n], &lpSampleTable[n]); + if (rc != AUDIO_ERROR_NONE) { + free(lpSampleTable); + AFreeModuleFile(lpModule); + AIOCloseFile(); + return rc; + } + } + free(lpSampleTable); + + *lplpModule = lpModule; + return AUDIO_ERROR_NONE; +} diff --git a/seal-hack/src/nondrv.c b/seal-hack/src/nondrv.c new file mode 100644 index 0000000..b4c3406 --- /dev/null +++ b/seal-hack/src/nondrv.c @@ -0,0 +1,360 @@ +/* + * $Id: nondrv.c 1.6 1997/01/09 23:08:57 chasan Exp $ + * 1.7 1998/10/24 18:20:54 chasan Exp (Mixer API) + * + * Silence(tm) audio driver. + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include "audio.h" +#include "drivers.h" + +#ifndef __DPMI__ +#include +#else +#include "msdos.h" +#define AAD(val) (((val)&15)+10*((val)>>4)) +typedef unsigned long time_t; +static time_t time(time_t *t) +{ + long secs, val; + + /* secs */ + OUTB(0x70, 0x00); + val = INB(0x71); + secs = AAD(val); + + /* min */ + OUTB(0x70, 0x02); + val = INB(0x71); + secs += 60L * AAD(val); + + /* hour */ + OUTB(0x70, 0x04); + val = INB(0x71); + secs += 60L * 60L * AAD(val); + + /* day */ + OUTB(0x70, 0x07); + val = INB(0x71); + secs += 24L * 60L * 60L * AAD(val); + + /* month */ + OUTB(0x70, 0x08); + val = INB(0x71); + secs += 30L * 24L * 60L * 60L * AAD(val); + + if (t != NULL) *t = secs; + return secs; +} +#endif + + + +static struct { + LONG dwTimer; + LONG dwTimerAccum; + LONG dwTimerRate; + LPFNAUDIOTIMER lpfnTimerHandler; +} none; + + +/* + * Silence(tm) audio driver API interface + */ +static UINT AIAPI GetAudioCaps(LPAUDIOCAPS lpCaps) +{ + static AUDIOCAPS Caps = + { + AUDIO_PRODUCT_NONE, "Silence", + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_1M16 | AUDIO_FORMAT_1S16 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_2M16 | AUDIO_FORMAT_2S16 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 | + AUDIO_FORMAT_4M16 | AUDIO_FORMAT_4S16 + }; + + memcpy(lpCaps, &Caps, sizeof(AUDIOCAPS)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI PingAudio(VOID) +{ + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI OpenAudio(LPAUDIOINFO lpInfo) +{ + memset(&none, 0, sizeof(none)); + none.dwTimer = 1000L * time(NULL); + return (lpInfo != NULL) ? AUDIO_ERROR_NONE : AUDIO_ERROR_INVALPARAM; +} + +static UINT AIAPI CloseAudio(VOID) +{ + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudio(UINT nFrames) +{ + LONG dwTimer = 1000L * time(NULL); + + if ((none.dwTimerAccum += dwTimer - none.dwTimer) >= none.dwTimerRate) { + none.dwTimerAccum -= none.dwTimerRate; + if (none.lpfnTimerHandler != NULL) + none.lpfnTimerHandler(); + } + none.dwTimer = dwTimer; + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudioSynth(VOID) +{ + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioMixerValue(UINT nChannel, UINT nValue) +{ + if (nChannel != AUDIO_MIXER_MASTER_VOLUME && + nChannel != AUDIO_MIXER_TREBLE && + nChannel != AUDIO_MIXER_BASS && + nChannel != AUDIO_MIXER_CHORUS && + nChannel != AUDIO_MIXER_REVERB) + return AUDIO_ERROR_INVALPARAM; + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI OpenVoices(UINT nVoices) +{ + if (nVoices < AUDIO_MAX_VOICES) { + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; +} + +static UINT AIAPI CloseVoices(VOID) +{ + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + if (lpfnAudioWave != NULL) { + } + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioTimerProc(LPFNAUDIOTIMER lpfnAudioTimer) +{ + if (lpfnAudioTimer != NULL) { + none.lpfnTimerHandler = lpfnAudioTimer; + } + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioTimerRate(UINT nRate) +{ + if (nRate >= 0x20 && nRate <= 0xFF) { + /* set timer rate in milliseconds */ + none.dwTimerRate = 60000L / (24 * nRate); + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; +} + +static LONG AIAPI GetAudioDataAvail(VOID) +{ + return 0L; +} + +static UINT AIAPI CreateAudioData(LPAUDIOWAVE lpWave) +{ + if (lpWave != NULL) { + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; +} + +static UINT AIAPI DestroyAudioData(LPAUDIOWAVE lpWave) +{ + if (lpWave != NULL) { + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; +} + +static UINT AIAPI WriteAudioData(LPAUDIOWAVE lpWave, DWORD dwOffset, UINT nCount) +{ + if (lpWave != NULL && lpWave->lpData != NULL) { + if (dwOffset + nCount < lpWave->dwLength) { + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI PrimeVoice(UINT nVoice, LPAUDIOWAVE lpWave) +{ + if (nVoice < AUDIO_MAX_VOICES && lpWave != NULL) { + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI StartVoice(UINT nVoice) +{ + if (nVoice < AUDIO_MAX_VOICES) { + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI StopVoice(UINT nVoice) +{ + if (nVoice < AUDIO_MAX_VOICES) { + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI SetVoicePosition(UINT nVoice, LONG dwPosition) +{ + if (nVoice < AUDIO_MAX_VOICES) { + if (dwPosition >= AUDIO_MIN_POSITION && + dwPosition <= AUDIO_MAX_POSITION) { + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI SetVoiceFrequency(UINT nVoice, LONG dwFrequency) +{ + if (nVoice < AUDIO_MAX_VOICES) { + if (dwFrequency >= AUDIO_MIN_FREQUENCY && + dwFrequency <= AUDIO_MAX_FREQUENCY) { + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI SetVoiceVolume(UINT nVoice, UINT nVolume) +{ + if (nVoice < AUDIO_MAX_VOICES) { + if (nVolume < AUDIO_MAX_VOLUME) { + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI SetVoicePanning(UINT nVoice, UINT nPanning) +{ + if (nVoice < AUDIO_MAX_VOICES) { + if (nPanning < AUDIO_MAX_PANNING) { + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoicePosition(UINT nVoice, LPLONG lpdwPosition) +{ + if (nVoice < AUDIO_MAX_VOICES) { + if (lpdwPosition != NULL) { + *lpdwPosition = 0L; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoiceFrequency(UINT nVoice, LPLONG lpdwFrequency) +{ + if (nVoice < AUDIO_MAX_VOICES) { + if (lpdwFrequency != NULL) { + *lpdwFrequency = 0L; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoiceVolume(UINT nVoice, LPUINT lpnVolume) +{ + if (nVoice < AUDIO_MAX_VOICES) { + if (lpnVolume != NULL) { + *lpnVolume = 0; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoicePanning(UINT nVoice, LPUINT lpnPanning) +{ + if (nVoice < AUDIO_MAX_VOICES) { + if (lpnPanning != NULL) { + *lpnPanning = 0; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + +static UINT AIAPI GetVoiceStatus(UINT nVoice, LPBOOL lpnStatus) +{ + if (nVoice < AUDIO_MAX_VOICES) { + if (lpnStatus != NULL) { + *lpnStatus = 1; + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_INVALPARAM; + } + return AUDIO_ERROR_INVALHANDLE; +} + + +/* + * Silence(tm) audio driver public interface + */ +AUDIOWAVEDRIVER NoneWaveDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudio, SetAudioCallback +}; + +AUDIOSYNTHDRIVER NoneSynthDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudioSynth, OpenVoices, CloseVoices, + SetAudioTimerProc, SetAudioTimerRate, SetAudioMixerValue, + GetAudioDataAvail, CreateAudioData, DestroyAudioData, + WriteAudioData, PrimeVoice, StartVoice, StopVoice, + SetVoicePosition, SetVoiceFrequency, SetVoiceVolume, + SetVoicePanning, GetVoicePosition, GetVoiceFrequency, + GetVoiceVolume, GetVoicePanning, GetVoiceStatus +}; + +AUDIODRIVER NoneDriver = +{ + &NoneWaveDriver, &NoneSynthDriver +}; diff --git a/seal-hack/src/os2drv.c b/seal-hack/src/os2drv.c new file mode 100644 index 0000000..1b2650b --- /dev/null +++ b/seal-hack/src/os2drv.c @@ -0,0 +1,323 @@ +/* + * $Id: os2drv.c 1.0 1998/10/18 14:06:31 chasan Exp $ + * + * OS/2 MMPM audio driver. + * + * Copyright (C) 1998 by Martin Amodeo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#define INCL_DOS +#include +#define INCL_OS2MM +#include + +#define WINAPI +typedef VOID* LPVOID; +typedef CHAR* LPCHAR; +typedef INT* LPINT; +typedef LONG* LPLONG; +typedef BOOL* LPBOOL; +typedef BYTE* LPBYTE; +typedef WORD* LPWORD; +typedef UINT* LPUINT; +typedef DWORD* LPDWORD; + +#undef LPSTR +#include "audio.h" +#include "drivers.h" + + +/* + * OS/2 MMPM driver defines + */ +#define BUFFER_SIZE 15 // buffer length in milliseconds / 2 +#define THREAD_STACK_SIZE 32768 // thread stack size in bytes + +#define SEMWAIT_OPERATION 9 // Semaphore wait operation for playlist +#define SEMPOST_OPERATION 10 // Semaphore post operation for playlist + +/* + * OS/2 MMPM driver global state + */ +static struct { + LPVOID lpBuffer[2]; + ULONG nBufferSize; + HEV semNeedsBuffer[2]; + HEV semHasBuffer[2]; + HEV semAudioPing; + ULONG ulThread; + LPCHAR aThreadStack; + MCI_OPEN_PARMS mop; + LPFNAUDIOWAVE lpfnCallback; + struct { + ULONG operation; + ULONG operand1; + ULONG operand2; + ULONG operand3; + } playlist[8]; +} OS2; + + +/* + * OS/2 MMPM driver API interface + */ +static UINT AIAPI GetAudioCaps(LPAUDIOCAPS lpCaps) +{ + static AUDIOCAPS Caps = + { + AUDIO_PRODUCT_OS2MMPM, "OS/2 MMPM", + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_1M16 | AUDIO_FORMAT_1S16 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_2M16 | AUDIO_FORMAT_2S16 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 | + AUDIO_FORMAT_4M16 | AUDIO_FORMAT_4S16 + }; + memcpy(lpCaps, &Caps, sizeof(AUDIOCAPS)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI PingAudio(VOID) +{ + return AUDIO_ERROR_NONE; +} + +static void ThreadProc(void *data) +{ + int i, junk; + for (i = 0; ; i ^= 1) { + /* wait until the buffer needs data */ + DosWaitEventSem(OS2.semNeedsBuffer[i], -1); + DosResetEventSem(OS2.semNeedsBuffer[i], &junk); + DosResetEventSem(OS2.semAudioPing, &junk); + + /* fill the needed buffer with samples */ + DosEnterCritSec(); + if (OS2.lpfnCallback != NULL) + (*OS2.lpfnCallback)(OS2.lpBuffer[i], OS2.nBufferSize); + else + memset(OS2.lpBuffer[i], 0, OS2.nBufferSize); + DosExitCritSec(); + + /* now the buffer has data */ + DosPostEventSem(OS2.semAudioPing); + DosPostEventSem(OS2.semHasBuffer[i]); + } +} + +static UINT AIAPI OpenAudio(LPAUDIOINFO lpInfo) +{ + MCI_WAVE_SET_PARMS wsp; + MCI_PLAY_PARMS mpp; + + /* clean the OS/2 driver state */ + memset(&OS2, 0, sizeof(OS2)); + + /* compute the buffer length in bytes */ +#if 1 + OS2.nBufferSize = ( 266 * lpInfo->nSampleRate / 22050 ) * + (lpInfo->wFormat & AUDIO_FORMAT_16BITS ? 2 : 1) * + (lpInfo->wFormat & AUDIO_FORMAT_STEREO ? 2 : 1); +#else + OS2.nBufferSize = lpInfo->nSampleRate / (1000 / BUFFERSIZE); + if (lpInfo->wFormat & AUDIO_FORMAT_16BITS) + OS2.nBufferSize <<= 1; + if (lpInfo->wFormat & AUDIO_FORMAT_STEREO) + OS2.nBufferSize <<= 1; +#endif + OS2.nBufferSize = (OS2.nBufferSize + 3) & ~3; + + /* allocate memory for double buffering */ + if ((OS2.lpBuffer[0] = (LPVOID) malloc(OS2.nBufferSize)) == NULL || + (OS2.lpBuffer[1] = (LPVOID) malloc(OS2.nBufferSize)) == NULL) + return AUDIO_ERROR_NOMEMORY; + + if ((OS2.aThreadStack = (LPCHAR) malloc(THREAD_STACK_SIZE)) == NULL ) + return AUDIO_ERROR_NOMEMORY; + + /* create consumer/producer buffer semaphores */ + DosCreateEventSem("\\SEM32\\Buffer1NeedsData", + &OS2.semNeedsBuffer[0], DC_SEM_SHARED, 1); + + DosCreateEventSem("\\SEM32\\Buffer2NeedsData", + &OS2.semNeedsBuffer[1], DC_SEM_SHARED, 1); + + DosCreateEventSem("\\SEM32\\Buffer1HasData", + &OS2.semHasBuffer[0], DC_SEM_SHARED, 0); + + DosCreateEventSem("\\SEM32\\Buffer2HasData", + &OS2.semHasBuffer[1], DC_SEM_SHARED, 0); + + /* Ping semaphore for synchronization of streamed audio */ + DosCreateEventSem("\\SEM32\\AudioPing", + &OS2.semAudioPing, DC_SEM_SHARED, 0); + + /* create MCI audio playlist commands */ + + /* wait until first buffer has data */ + OS2.playlist[0].operation = SEMWAIT_OPERATION; + OS2.playlist[0].operand1 = OS2.semHasBuffer[0]; + OS2.playlist[0].operand2 = -1; + OS2.playlist[0].operand3 = 0; + + /* play the first buffer data */ + OS2.playlist[1].operation = DATA_OPERATION; + OS2.playlist[1].operand1 = (long) OS2.lpBuffer[0]; + OS2.playlist[1].operand2 = OS2.nBufferSize; + OS2.playlist[1].operand3 = 0; + + /* tell first buffer needs data */ + OS2.playlist[2].operation = SEMPOST_OPERATION; + OS2.playlist[2].operand1 = OS2.semNeedsBuffer[0]; + OS2.playlist[2].operand2 = 0; + OS2.playlist[2].operand3 = 0; + + /* wait until second buffer has data */ + OS2.playlist[3].operation = SEMWAIT_OPERATION; + OS2.playlist[3].operand1 = OS2.semHasBuffer[1]; + OS2.playlist[3].operand2 = -1; + OS2.playlist[3].operand3 = 0; + + /* play the second buffer data */ + OS2.playlist[4].operation = DATA_OPERATION; + OS2.playlist[4].operand1 = (long) OS2.lpBuffer[1]; + OS2.playlist[4].operand2 = OS2.nBufferSize; + OS2.playlist[4].operand3 = 0; + + /* tell second buffer needs data */ + OS2.playlist[5].operation = SEMPOST_OPERATION; + OS2.playlist[5].operand1 = OS2.semNeedsBuffer[1]; + OS2.playlist[5].operand2 = 0; + OS2.playlist[5].operand3 = 0; + + /* branch to the first playlist entry */ + OS2.playlist[6].operation = BRANCH_OPERATION; + OS2.playlist[6].operand1 = 0; + OS2.playlist[6].operand2 = 0; // goto OS2.playlist[0] + OS2.playlist[6].operand3 = 0; + + /* exit the playlist */ + OS2.playlist[7].operation = EXIT_OPERATION; + + /* open the MCI waveform audio device */ + OS2.mop.usDeviceID = 0; + OS2.mop.pszDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO_NAME; + OS2.mop.pszElementName = (LPCHAR) &OS2.playlist[0]; + + if (mciSendCommand(0, MCI_OPEN, MCI_WAIT | MCI_OPEN_SHAREABLE | + MCI_OPEN_PLAYLIST, &OS2.mop, 0) != MCIERR_SUCCESS) + return AUDIO_ERROR_DEVICEBUSY; + + /* setup the MCI waveform device parameters */ + wsp.hwndCallback = 0; + wsp.ulSamplesPerSec = lpInfo->nSampleRate; + wsp.usBitsPerSample = (lpInfo->wFormat & AUDIO_FORMAT_16BITS ? 16 : 8); + wsp.usChannels = (lpInfo->wFormat & AUDIO_FORMAT_STEREO ? 2 : 1); + + if (mciSendCommand(OS2.mop.usDeviceID, MCI_SET, + MCI_WAIT | + MCI_WAVE_SET_SAMPLESPERSEC | + MCI_WAVE_SET_BITSPERSAMPLE | + MCI_WAVE_SET_CHANNELS, + &wsp, 0) != MCIERR_SUCCESS) + return AUDIO_ERROR_DEVICEBUSY; + + /* start the OS/2 driver thread routine */ + OS2.ulThread = _beginthread(ThreadProc, OS2.aThreadStack, + THREAD_STACK_SIZE, NULL); + + DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, OS2.ulThread); + + /* start playing the MCI audio device */ + mpp.hwndCallback = 0; + mpp.ulFrom = 0; + if (mciSendCommand(OS2.mop.usDeviceID, MCI_PLAY, + 0, &mpp, 0) != MCIERR_SUCCESS) + return AUDIO_ERROR_DEVICEBUSY; + + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI CloseAudio(VOID) +{ + MCI_GENERIC_PARMS mgp; + + /* kill the OS/2 driver thread routine */ + DosKillThread(OS2.ulThread); + + /* let the branch fall through to the exit function */ + OS2.playlist[6].operand2 = 7; + + /* "fill" the buffers to unlock the playlist */ + DosPostEventSem(OS2.semHasBuffer[0]); + DosPostEventSem(OS2.semHasBuffer[1]); + + /* Unblock any threads that may be synchronizing */ + DosPostEventSem(OS2.semAudioPing); + + + /* close the MCI waveform audio device */ + mgp.hwndCallback = 0; + mciSendCommand(OS2.mop.usDeviceID, MCI_CLOSE, MCI_WAIT, &mgp, 0); + + /* destroy the read/write buffer semaphores */ + DosCloseEventSem(OS2.semNeedsBuffer[0]); + DosCloseEventSem(OS2.semNeedsBuffer[1]); + DosCloseEventSem(OS2.semHasBuffer[0]); + DosCloseEventSem(OS2.semHasBuffer[1]); + + /* release the memory buffers */ + if (OS2.lpBuffer[0] != NULL) + free(OS2.lpBuffer[0]); + if (OS2.lpBuffer[1] != NULL) + free(OS2.lpBuffer[1]); + if (OS2.aThreadStack != NULL) + free(OS2.aThreadStack); + + /* clean the OS/2 driver state */ + memset(&OS2, 0, sizeof(OS2)); + + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudio(UINT nFrames) +{ + ULONG junk; + DosResetEventSem(OS2.semAudioPing, &junk); + DosWaitEventSem(OS2.semAudioPing, -1); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + /* set the user lpfnCallback routine */ + OS2.lpfnCallback = lpfnAudioWave; + return AUDIO_ERROR_NONE; +} + + +/* + * OS/2 MMPM driver public interface + */ +AUDIOWAVEDRIVER OS2MMPMWaveDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudio, SetAudioCallback +}; + +AUDIODRIVER OS2MMPMDriver = +{ + &OS2MMPMWaveDriver, NULL +}; diff --git a/seal-hack/src/osxdrv.c b/seal-hack/src/osxdrv.c new file mode 100644 index 0000000..b517488 --- /dev/null +++ b/seal-hack/src/osxdrv.c @@ -0,0 +1,183 @@ +/* + * $Id: lnxdrv.c 1.5 1996/08/05 18:51:19 chasan released $ + * + * SDL audio driver. Turns SEAL into a mixer on top of SDL. + * + * Copyright 2002 Greg Velichansky (hmaon@bumba.net) + * + * Based in part on the Linux Voxware driver, + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +#include "SDL.h" + +#include "audio.h" +#include "drivers.h" + + +/* + * fragments defines + */ +#define NUMFRAGS 16 +#define FRAGSIZE 11 +#define BUFFERSIZE (1 << FRAGSIZE) + +/* + * configuration structure + */ +static struct AudioStruct { + SDL_AudioSpec desired, spec; + BYTE aBuffer[BUFFERSIZE*4]; + LPFNAUDIOWAVE lpfnAudioWave; + WORD wFormat; +} Audio; + + +/* + * Linux driver API interface + */ +static UINT AIAPI GetAudioCaps(LPAUDIOCAPS lpCaps) +{ + static AUDIOCAPS Caps = + { + AUDIO_PRODUCT_LINUX, "MacOS X - SDL", + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_1M16 | AUDIO_FORMAT_1S16 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_2M16 | AUDIO_FORMAT_2S16 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 | + AUDIO_FORMAT_4M16 | AUDIO_FORMAT_4S16 + }; + + memcpy(lpCaps, &Caps, sizeof(AUDIOCAPS)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI PingAudio(VOID) +{ + return 0; +/* return (SDL_INIT_AUDIO == SDL_WasInit(SDL_INIT_AUDIO)); */ +} + +static void updatecallback(void *userdata, Uint8 *stream, int len); + +static UINT AIAPI OpenAudio(LPAUDIOINFO lpInfo) +{ + int nBitsPerSample, nStereoOn, nSampleRate, nFrags; + + memset(&Audio, 0, sizeof(Audio)); + + if (!SDL_WasInit(SDL_INIT_EVERYTHING)) + { + SDL_Init(SDL_INIT_AUDIO); + } else + { + if (!SDL_WasInit(SDL_INIT_AUDIO) && SDL_InitSubSystem(SDL_INIT_AUDIO)) + return AUDIO_ERROR_NODEVICE; + } + if (SDL_INIT_AUDIO != SDL_WasInit(SDL_INIT_AUDIO)) + return AUDIO_ERROR_NODEVICE; + + + nBitsPerSample = lpInfo->wFormat & AUDIO_FORMAT_16BITS ? 16 : 8; + nStereoOn = lpInfo->wFormat & AUDIO_FORMAT_STEREO ? 1 : 0; + /*nSampleRate = lpInfo->nSampleRate;*/ + + Audio.desired.freq = lpInfo->nSampleRate; + Audio.desired.samples = 512; + Audio.desired.channels = nStereoOn ? 2 : 1; + + Audio.desired.format = (lpInfo->wFormat & AUDIO_FORMAT_16BITS) ? AUDIO_U16SYS : AUDIO_U8; + + Audio.desired.userdata = (void*)&Audio; + + Audio.desired.callback = updatecallback; + + SDL_OpenAudio(&(Audio.desired), &(Audio.spec)); + + /* we should probably do something here... blah... whatever :/ */ + + /* setup number and size of buffer fragments */ + /*nFrags = (NUMFRAGS << 16) + (FRAGSIZE); + ioctl(Audio.nHandle, SNDCTL_DSP_SETFRAGMENT, &nFrags);*/ + + /* setup audio playback encoding format and sampling frequency */ + /*if (ioctl(Audio.nHandle, SNDCTL_DSP_SAMPLESIZE, &nBitsPerSample) < 0 || + ioctl(Audio.nHandle, SNDCTL_DSP_STEREO, &nStereoOn) < 0 || + ioctl(Audio.nHandle, SNDCTL_DSP_SPEED, &nSampleRate) < 0) { + close(Audio.nHandle); + return AUDIO_ERROR_BADFORMAT; + }*/ + + /*Audio.wFormat = lpInfo->wFormat;*/ + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI CloseAudio(VOID) +{ + SDL_CloseAudio(); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudio(UINT nFrames) +{ + /* compute frame size */ + /*if (Audio.wFormat & AUDIO_FORMAT_16BITS) nFrames <<= 1; + if (Audio.wFormat & AUDIO_FORMAT_STEREO) nFrames <<= 1; + if (nFrames <= 0 || nFrames > sizeof(Audio.aBuffer)) + nFrames = sizeof(Audio.aBuffer);*/ + + /* send PCM samples to the DSP audio device */ + /*if (Audio.lpfnAudioWave != NULL) { + Audio.lpfnAudioWave(Audio.aBuffer, nFrames); + write(Audio.nHandle, Audio.aBuffer, nFrames); + }*/ + + SDL_PauseAudio(0); /* the only use I can think of for UpdateAudio() ...*/ + + return AUDIO_ERROR_NONE; +} + + + +static void updatecallback(void *userdata, Uint8 *stream, int len) +{ + struct AudioStruct *aud = userdata; + /* maybe this isn't necessary, we know where Audio is, after all... */ + aud->lpfnAudioWave(stream, len); /* God speed... */ +} + + + +static UINT AIAPI SetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + /* set up DSP audio device user's callback function */ + Audio.lpfnAudioWave = lpfnAudioWave; + return AUDIO_ERROR_NONE; +} + + +/* + * Linux driver public interface + */ +AUDIOWAVEDRIVER MacOSXWaveDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudio, SetAudioCallback +}; + +AUDIODRIVER MacOSXDriver = +{ + &MacOSXWaveDriver, NULL +}; diff --git a/seal-hack/src/pasdrv.c b/seal-hack/src/pasdrv.c new file mode 100644 index 0000000..e20ace7 --- /dev/null +++ b/seal-hack/src/pasdrv.c @@ -0,0 +1,586 @@ +/* + * $Id: pasdrv.c 1.5 1996/08/05 18:51:19 chasan released $ + * + * Pro Audio Spectrum series audio driver. + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include "audio.h" +#include "drivers.h" +#include "msdos.h" + +/* + * Pro Audio Spectrum cards default I/O base addresses + */ +#define PAS_DEFAULT_BASE 0x0388 /* default base port address */ +#define PAS_ALT_BASE_1 0x0384 /* first alternative base address */ +#define PAS_ALT_BASE_2 0x038C /* second alternative base address */ +#define PAS_ALT_BASE_3 0x0288 /* third alternative base address */ + +/* + * Pro Audio Spectrum direct register offsets + */ +#define PAS_AUDIOMXR 0x0B88 /* audio mixer control register */ +#define PAS_AUDIOFILT 0x0B8A /* audio filter control register */ +#define PAS_INTRSTAT 0x0B89 /* interrupt status register */ +#define PAS_INTRCTLR 0x0B8B /* interrupt control register */ +#define PAS_PCMDATA 0x0F88 /* PCM data PIO register */ +#define PAS_CROSSCHANNEL 0x0F8A /* cross channel control register */ +#define PAS_SAMPLERATE 0x1388 /* sample rate timer register */ +#define PAS_SAMPLECNT 0x1389 /* sample count register */ +#define PAS_SPKRTMR 0x138A /* local speaker timer address */ +#define PAS_TMRCTLR 0x138B /* local timer control register */ + +/* + * Pro Audio Spectrum PAS2/CDPC (digital ASIC) direct register offsets + */ +#define PAS_MASTERCHIPR 0xFF88 /* master chip revision */ +#define PAS_ENHSCSI 0x7F89 /* Enhanced SCSI detect port */ +#define PAS_SYSCONFIG2 0x8389 /* system configuration register */ +#define PAS_COMPATREGE 0xF788 /* compatible register enable */ +#define PAS_MASTERMODRD 0xFF8B /* master mode read */ +#define PAS_SLAVEMODRD 0xEF8B /* slave mode read */ + +/* + * Interrupt control register bit fields + */ +#define IC_INTRMASK 0x1F /* interrupt mask bit fields */ +#define IC_REVBITS 0xE0 /* revision mask bit fields */ +#define IC_LEFTFM 0x01 /* left FM interrupt enable */ +#define IC_RIGHTFM 0x02 /* right FM interrupt enable */ +#define IC_SAMPRATE 0x04 /* sample rate timer intr enable */ +#define IC_SAMPBUFF 0x08 /* sample buffer timer intr enable */ +#define IC_MIDI 0x10 /* MIDI interrupt enable */ + +/* + * Interrupt status register bit fields + */ +#define IS_INTRMASK 0x1F /* interrupts mask bit fields */ +#define IS_LEFTFM 0x01 /* FM left interrupt active */ +#define IS_RIGHTFM 0x02 /* FM right interrupt active */ +#define IS_SAMPRATE 0x04 /* sample rate interrupt active */ +#define IS_SAMPBUFF 0x08 /* sample buffer interrupt active */ +#define IS_MIDI 0x10 /* MIDI interrupt active */ +#define IS_PCMLR 0x20 /* PCM channel interrupt active */ +#define IS_ACTIVE 0x40 /* hardware is active */ +#define IS_CLIPPING 0x80 /* sample clipping has occured */ + +/* + * Audio filter select register bit fields + */ +#define AF_FILTMASK 0x1F /* filter select and decode bits */ +#define AF_FILT1 0x01 /* select 17897 Hz filter */ +#define AF_FILT2 0x02 /* select 15909 Hz filter */ +#define AF_FILT3 0x09 /* select 11931 Hz filter */ +#define AF_FILT4 0x11 /* select 8948 Hz filter */ +#define AF_FILT5 0x19 /* select 5965 Hz filter */ +#define AF_FILT6 0x04 /* select 2982 Hz filter */ +#define AF_UNMUTE 0x20 /* filter unmute control */ +#define AF_SAMPRATE 0x40 /* sample rate timer enable */ +#define AF_SAMPBUFF 0x80 /* sample buffer counter enable */ + +/* + * Cross channel control register bit fields + */ +#define CC_CROSSMASK 0x0F /* cross channels bit fields */ +#define CC_PCMMASK 0xF0 /* PCM/DMA control bit fields */ +#define CC_R2R 0x01 /* cross channel right->right */ +#define CC_L2R 0x02 /* cross channel left->right */ +#define CC_R2L 0x04 /* cross channel right->left */ +#define CC_L2L 0x08 /* cross channel left->left */ +#define CC_DAC 0x10 /* select DAC output mode */ +#define CC_ADC 0x00 /* select ADC input mode */ +#define CC_MONO 0x20 /* select mono mode */ +#define CC_STEREO 0x00 /* select stereo mode */ +#define CC_ENAPCM 0x40 /* enable PCM machine */ +#define CC_DRQ 0x80 /* enable DMA transfers */ + +/* + * Local timer control register bit fields + */ +#define TC_BIN 0x00 /* select binary counting mode */ +#define TC_BCD 0x01 /* select BCD counting mode */ +#define TC_SQUAREWAVE 0x04 /* select square wave generator */ +#define TC_RATE 0x06 /* select rate generator */ +#define TC_16BIT 0x30 /* set first LSB and then MSB */ +#define TC_SAMPRATE 0x00 /* select sample rate timer */ +#define TC_SAMPBUFF 0x40 /* select buffer counter timer */ +#define TC_PCSPKR 0x80 /* select PC speaker counter timer */ + +/* + * Sample size and oversampling register bit fields + */ +#define SC2_OVRSMP 0x03 /* oversampling bit fields */ +#define SC2_OVRSMP1X 0x00 /* select over sampling rate to 1X */ +#define SC2_OVRSMP2X 0x01 /* select over sampling rate to 2X */ +#define SC2_OVRSMP4X 0x03 /* select over sampling rate to 4X */ +#define SC2_16BIT 0x04 /* select 16 bit audio */ +#define SC2_12BIT 0x08 /* select 12 bit interleaving */ + +/* + * Compatible register enable bit fields + */ +#define CP_MPUEMUL 0x01 /* MPU-401 emulation enabled */ +#define CP_SBEMUL 0x02 /* SB emulation enabled */ + +/* + * Slave mode read register bit fields + */ +#define SMRD_DRVTYPE 0x03 /* driver interface type */ +#define SMRD_FMTYPE 0x04 /* 3812(0) or OPL3(1) FM chip */ +#define SMRD_DACTYPE 0x08 /* 8-bit DAC(0) or 16-bit DAC(1) */ +#define SMRD_IMIDI 0x10 /* use internal MIDI */ +#define SMRD_SWREP 0x80 /* switch is auto repeating */ + +/* + * Master mode read register bit fields + */ +#define MMRD_ATPS2 0x01 /* PS2(0) or AT(1) bus */ +#define MMRD_TMREMUL 0x02 /* timer emulation enabled */ +#define MMRD_MSMD 0x04 /* master(0) or slave(1) mode */ +#define MMRD_SLAVE 0x08 /* slave power on or device present */ +#define MMRD_ATTIM 0x10 /* XT/AT timing */ +#define MMRD_MSTREV 0xE0 /* master revision level */ + +/* + * Pro Audio Spectrum product feature bits + */ +#define MVA508 0x0001 /* MVA508(1) or National(0) */ +#define MVPS2 0x0002 /* PS2(1) or AT(0) bus */ +#define MVSLAVE 0x0004 /* CDPC slave device */ +#define MVSCSI 0x0008 /* SCSI interface */ +#define MVENHSCSI 0x0010 /* Enhanced SCSI interface */ +#define MVSONY 0x0020 /* Sony 535 interface */ +#define MVDAC16 0x0040 /* 16 bit DAC */ +#define MVSBEMUL 0x0080 /* SB hardware emulation */ +#define MVMPUEMUL 0x0100 /* MPU-401 hardware emulation */ +#define MVOPL3 0x0200 /* OPL3(1) or 3812(0) chip */ +#define MV101 0x0400 /* MV101 ASIC */ +#define MV101_REV_BITS 0x3800 /* MV101 revision bit fields */ + +/* + * Pro Audio Spectrum product feature lists + */ +#define PRODUCT_PROAUDIO (MVSCSI) +#define PRODUCT_PROPLUS (MV101|MVSCSI|MVENHSCSI|MVSBEMUL|MVOPL3) +#define PRODUCT_PRO16 (MV101|MVA508|MVSCSI|MVENHSCSI|MVSBEMUL|MVDAC16|MVOPL3) +#define PRODUCT_CDPC (MV101|MVSLAVE|MVSONY|MVSBEMUL|MVDAC16|MVOPL3) +#define PRODUCT_CAREBITS (MVA508|MVDAC16|MVOPL3|MV101) + +/* + * PAS clock source frequency and buffer size + */ +#define CLOCKFREQ 1193180 /* clock frequency in Hertz */ +#define BUFFERSIZE 50 /* buffer length in milliseconds */ +#define BUFFRAGSIZE 32 /* buffer fragment size in bytes */ + + +/* + * Pro Audio Spectrum configuration structure + */ +static struct { + WORD wFormat; /* playback encoding format */ + WORD nSampleRate; /* sampling frequency */ + WORD wId; /* audio device identifier */ + WORD wProduct; /* product feature bits */ + WORD wPort; /* device base port */ + BYTE nIrqLine; /* interrupt line */ + BYTE nDmaChannel; /* output DMA channel */ + LPBYTE lpBuffer; /* DMA buffer address */ + UINT nBufferSize; /* DMA buffer length */ + UINT nPosition; /* DMA buffer playing position */ + LPFNAUDIOWAVE lpfnAudioWave; /* user callback routine */ +} PAS; + + +/* + * Pro Audio Spectrum low level routines + */ +static VOID PASPortB(WORD nIndex, BYTE bData) +{ + OUTB(PAS.wPort ^ nIndex, bData); +} + +static BYTE PASPortRB(WORD nIndex) +{ + return INB(PAS.wPort ^ nIndex); +} + +static UINT PASProbe(VOID) +{ + DWORD dwSampleRate; + BYTE nRevId, mmrd, smrd; + + /* + * Probe PAS hardware checking the revision ID code from + * the interrupt mask register (it should be read only). + */ + if ((nRevId = PASPortRB(PAS_INTRCTLR)) == 0xFF) + return AUDIO_ERROR_NODEVICE; + PASPortB(PAS_INTRCTLR, nRevId ^ IC_REVBITS); + if (PASPortRB(PAS_INTRCTLR) != nRevId) + return AUDIO_ERROR_NODEVICE; + + /* + * Checks the installed hardware for all the feature bits, + * and determine which PAS hardware card is present. + */ + PAS.wProduct = MVSCSI; + if ((nRevId & IC_REVBITS) != 0x00) { + /* all second generation PAS cards use MV101 and have SB emulation */ + PAS.wProduct |= (MVSBEMUL | MV101); + + /* determine if the enhanced SCSI interface is present */ + PASPortB(PAS_ENHSCSI, 0x00); + if (!(PASPortRB(PAS_ENHSCSI) & 0x01)) + PAS.wProduct |= MVENHSCSI; + + /* determine AT/PS2, CDPC slave mode */ + mmrd = PASPortRB(PAS_MASTERMODRD); + if (!(mmrd & MMRD_ATPS2)) + PAS.wProduct |= MVPS2; + if (mmrd & MMRD_MSMD) + PAS.wProduct |= MVSLAVE; + + /* merge in the chip revision level */ + PAS.wProduct |= (WORD)(PASPortRB(PAS_MASTERCHIPR) & 0x0F) << 11; + + /* determine CDROM type, FM chip, 8/16 bit DAC, and mixer */ + smrd = PASPortRB(PAS_SLAVEMODRD); + if (smrd & SMRD_DACTYPE) + PAS.wProduct |= MVDAC16; + if (smrd & SMRD_FMTYPE) + PAS.wProduct |= MVOPL3; + if ((PAS.wProduct & (MVSLAVE | MVDAC16)) == MVDAC16) + PAS.wProduct |= MVA508; + if ((smrd & SMRD_DRVTYPE) == 2) { + PAS.wProduct &= ~(MVSCSI | MVENHSCSI); + PAS.wProduct |= MVSONY; + } + + /* determine if MPU-401 emulation is active */ + if (PASPortRB(PAS_COMPATREGE) & CP_MPUEMUL) + PAS.wProduct |= MVMPUEMUL; + } + /* + * Assume we have a PAS16 compatible card if the MV101 ASIC + * chip and the 16-bit DAC are both present. + */ + PAS.wId = (PAS.wProduct & (MV101 | MVDAC16)) == (MV101 | MVDAC16) ? + AUDIO_PRODUCT_PAS16 : AUDIO_PRODUCT_PAS; + + /* + * Check out playback encoding format and sampling + * frequencies for the specified PAS sound card. + */ + if (PAS.wId != AUDIO_PRODUCT_PAS16) + PAS.wFormat &= ~AUDIO_FORMAT_16BITS; + if (PAS.nSampleRate < 5000) + PAS.nSampleRate = 5000; + if (PAS.nSampleRate > 44100) + PAS.nSampleRate = 44100; + + /* get actual sampling frequency supported by hardware */ + dwSampleRate = PAS.nSampleRate; + if (PAS.wFormat & AUDIO_FORMAT_STEREO) + dwSampleRate <<= 1; + dwSampleRate = CLOCKFREQ / (CLOCKFREQ / dwSampleRate); + if (PAS.wFormat & AUDIO_FORMAT_STEREO) + dwSampleRate >>= 1; + PAS.nSampleRate = dwSampleRate; + + return AUDIO_ERROR_NONE; +} + +static VOID PASStartPlayback(VOID) +{ + DWORD nCount; + + /* + * Setup the DMA controller channel for playback in + * auto init mode and start the PCM state machine. + */ + DosSetupChannel(PAS.nDmaChannel, DMA_WRITE | DMA_AUTOINIT, 0); + + /* flush pending PCM interrupts writting interrupt status register */ + PASPortB(PAS_INTRSTAT, 0x00); + + /* + * Disable buffer counter and timer rate gates, and disable + * PAS16 output (these gates MUST be disabled before programming + * the timers). + */ + PASPortB(PAS_AUDIOFILT, AF_FILT1); + + /* + * Disable DMA and PCM state machine (the time rate must + * be initialized BEFORE enabling the PCM state machine). + */ + PASPortB(PAS_CROSSCHANNEL, CC_DAC | CC_L2L | CC_R2R); + + /* + * Set the PCM sample rate timer register (select rate timer, + * enable 16 bit timer, select rate generator, and set + * binary counting mode). + */ + nCount = PAS.nSampleRate; + if (PAS.wFormat & AUDIO_FORMAT_STEREO) + nCount <<= 1; + nCount = CLOCKFREQ / nCount; + PASPortB(PAS_TMRCTLR, TC_16BIT | TC_RATE | TC_SAMPRATE | TC_BIN); + PASPortB(PAS_SAMPLERATE, LOBYTE(nCount)); + PASPortB(PAS_SAMPLERATE, HIBYTE(nCount)); + + /* + * Set the PCM sample buffer counter register (select buffer + * counter, enable 16 bit timer, select square wave generator + * and set binary counting mode). + */ + nCount = PAS.nBufferSize; + if (PAS.wFormat & AUDIO_FORMAT_16BITS) { + if (PAS.nDmaChannel <= 3) + nCount <<= 1; + } + else { + if (PAS.nDmaChannel >= 4) + nCount >>= 1; + } + PASPortB(PAS_TMRCTLR, TC_16BIT | TC_SQUAREWAVE | TC_SAMPBUFF | TC_BIN); + PASPortB(PAS_SAMPLECNT, LOBYTE(nCount)); + PASPortB(PAS_SAMPLECNT, HIBYTE(nCount)); + + /* + * Setup 8/16-bit linear encoding format for playback + * (only possible for cards with the MV101 ASIC chip) + */ + if (PAS.wProduct & MV101) { + PASPortB(PAS_SYSCONFIG2, (PASPortRB(PAS_SYSCONFIG2) & ~SC2_16BIT) | + (PAS.wFormat & AUDIO_FORMAT_16BITS ? SC2_16BIT : 0x00)); + } + + /* + * Select mono/stereo mode and enable DMA and PCM state machine + * (DMA enable, disable PCM, DAC mode, L->L and R->R connections). + */ + PASPortB(PAS_CROSSCHANNEL, CC_DRQ | CC_DAC | CC_L2L | CC_R2R | + (PAS.wFormat & AUDIO_FORMAT_STEREO ? CC_STEREO : CC_MONO)); + + /* enable PCM state machine */ + PASPortB(PAS_CROSSCHANNEL, PASPortRB(PAS_CROSSCHANNEL) | CC_ENAPCM); + + /* + * Enable buffer counter and timer rate gates, and enable PAS output + * (enable gates and PAS16 output, select 17897 Hz filter). + */ + PASPortB(PAS_AUDIOFILT, AF_SAMPBUFF | AF_SAMPRATE | AF_UNMUTE | AF_FILT1); +} + +static VOID PASStopPlayback(VOID) +{ + /* disable buffer counter and timer rate gates and PAS16 output */ + PASPortB(PAS_AUDIOFILT, AF_FILT1); + + /* set back to 8 bit audio output */ + if (PAS.wProduct & MV101) { + PASPortB(PAS_SYSCONFIG2, PASPortRB(PAS_SYSCONFIG2) & ~SC2_16BIT); + } + + /* disable sample buffer interrupt */ + PASPortB(PAS_INTRCTLR, PASPortRB(PAS_INTRCTLR) & ~IC_SAMPBUFF); + + /* select mono mode, DAC mode, disable DMA and PCM state machine */ + PASPortB(PAS_CROSSCHANNEL, CC_DAC | CC_L2L | CC_R2R); + + /* reset DMA controller channel */ + DosDisableChannel(PAS.nDmaChannel); +} + +static UINT PASPing(WORD wPort) +{ + static DOSREGS r; + + /* + * Check if a PAS card is present making sure MVSOUND.SYS + * is loaded in memory, this is the way to know if the + * hardware is actually present. + */ + memset(&r, 0, sizeof(r)); + r.ax = 0xBC00; + r.bx = 0x3F3F; + r.cx = 0x0000; + r.dx = 0x0000; + DosIntVector(0x2F, &r); + if ((r.bx ^ r.cx ^ r.dx) == 0x4D56) { + /* get the MVSOUND.SYS specified DMA and IRQ channels */ + r.ax = 0xBC04; + DosIntVector(0x2F, &r); + PAS.wPort = wPort ^ PAS_DEFAULT_BASE; + PAS.nIrqLine = LOBYTE(r.cx); + PAS.nDmaChannel = LOBYTE(r.bx); + return PASProbe(); + } + return AUDIO_ERROR_NODEVICE; +} + + + + +/* + * Pro Audio Spectrum driver API interface + */ +static UINT AIAPI GetAudioCaps(LPAUDIOCAPS lpCaps) +{ + static AUDIOCAPS Caps = + { + AUDIO_PRODUCT_PAS, "Pro Audio Spectrum", + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 + }; + static AUDIOCAPS Caps16 = + { + AUDIO_PRODUCT_PAS16, "Pro Audio Spectrum 16", + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_1M16 | AUDIO_FORMAT_1S16 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_2M16 | AUDIO_FORMAT_2S16 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 | + AUDIO_FORMAT_4M16 | AUDIO_FORMAT_4S16 + }; + + memcpy(lpCaps, PAS.wId != AUDIO_PRODUCT_PAS16 ? + &Caps : &Caps16, sizeof(AUDIOCAPS)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI PingAudio(VOID) +{ + if (!PASPing(PAS_DEFAULT_BASE)) + return AUDIO_ERROR_NONE; + if (!PASPing(PAS_ALT_BASE_1)) + return AUDIO_ERROR_NONE; + if (!PASPing(PAS_ALT_BASE_2)) + return AUDIO_ERROR_NONE; + if (!PASPing(PAS_ALT_BASE_3)) + return AUDIO_ERROR_NONE; + return AUDIO_ERROR_NODEVICE; +} + +static UINT AIAPI OpenAudio(LPAUDIOINFO lpInfo) +{ + DWORD dwBytesPerSecond; + + memset(&PAS, 0, sizeof(PAS)); + + /* + * Initialize PAS16 configuration parameters + * and check whether we have such a card. + */ + PAS.wFormat = lpInfo->wFormat; + PAS.nSampleRate = lpInfo->nSampleRate; + if (PingAudio()) + return AUDIO_ERROR_NODEVICE; + + /* refresh configuration parameters */ + lpInfo->wFormat = PAS.wFormat; + lpInfo->nSampleRate = PAS.nSampleRate; + + /* + * Allocate and clean DMA channel buffer for playback + */ + dwBytesPerSecond = PAS.nSampleRate; + if (PAS.wFormat & AUDIO_FORMAT_16BITS) + dwBytesPerSecond <<= 1; + if (PAS.wFormat & AUDIO_FORMAT_STEREO) + dwBytesPerSecond <<= 1; + PAS.nBufferSize = dwBytesPerSecond / (1000 / BUFFERSIZE); + PAS.nBufferSize = (PAS.nBufferSize + BUFFRAGSIZE) & -BUFFRAGSIZE; + if (DosAllocChannel(PAS.nDmaChannel, PAS.nBufferSize)) + return AUDIO_ERROR_NOMEMORY; + if ((PAS.lpBuffer = DosLockChannel(PAS.nDmaChannel)) != NULL) { + memset(PAS.lpBuffer, PAS.wFormat & AUDIO_FORMAT_16BITS ? + 0x00 : 0x80, PAS.nBufferSize); + DosUnlockChannel(PAS.nDmaChannel); + } + + /* start playback with the PAS16 PCM state machine */ + PASStartPlayback(); + + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI CloseAudio(VOID) +{ + PASStopPlayback(); + DosFreeChannel(PAS.nDmaChannel); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudio(UINT nFrames) +{ + int nBlockSize, nSize; + + if (PAS.wFormat & AUDIO_FORMAT_16BITS) nFrames <<= 1; + if (PAS.wFormat & AUDIO_FORMAT_STEREO) nFrames <<= 1; + if (nFrames <= 0 || nFrames > PAS.nBufferSize) + nFrames = PAS.nBufferSize; + + if ((PAS.lpBuffer = DosLockChannel(PAS.nDmaChannel)) != NULL) { + nBlockSize = PAS.nBufferSize - PAS.nPosition - + DosGetChannelCount(PAS.nDmaChannel); + if (nBlockSize < 0) + nBlockSize += PAS.nBufferSize; + + if (nBlockSize > nFrames) + nBlockSize = nFrames; + + nBlockSize &= -BUFFRAGSIZE; + while (nBlockSize != 0) { + nSize = PAS.nBufferSize - PAS.nPosition; + if (nSize > nBlockSize) + nSize = nBlockSize; + if (PAS.lpfnAudioWave != NULL) { + PAS.lpfnAudioWave(&PAS.lpBuffer[PAS.nPosition], nSize); + } + else { + memset(&PAS.lpBuffer[PAS.nPosition], + PAS.wFormat & AUDIO_FORMAT_16BITS ? + 0x00 : 0x80, nSize); + } + if ((PAS.nPosition += nSize) >= PAS.nBufferSize) + PAS.nPosition -= PAS.nBufferSize; + nBlockSize -= nSize; + } + DosUnlockChannel(PAS.nDmaChannel); + } + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + PAS.lpfnAudioWave = lpfnAudioWave; + return AUDIO_ERROR_NONE; +} + + + +/* + * Pro Audio Spectrum driver public interface + */ +AUDIOWAVEDRIVER ProAudioSpectrumWaveDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudio, SetAudioCallback +}; + +AUDIODRIVER ProAudioSpectrumDriver = +{ + &ProAudioSpectrumWaveDriver, NULL +}; diff --git a/seal-hack/src/s3mfile.c b/seal-hack/src/s3mfile.c new file mode 100644 index 0000000..36cda9b --- /dev/null +++ b/seal-hack/src/s3mfile.c @@ -0,0 +1,764 @@ +/* + * $Id: s3mfile.c 1.7 1996/09/13 15:10:01 chasan released $ + * + * Scream Tracker 3.0 module file loader routines. + * + * Copyright (c) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include "audio.h" +#include "iofile.h" + + +/* + * ScreamTracker 3.0 module file structures + */ + +#define S3M_MAX_TRACKS 32 +#define S3M_MAX_SAMPLES 100 +#define S3M_MAX_PATTERNS 256 +#define S3M_MAX_ORDERS 256 +#define S3M_MAX_ROWS 64 +#define S3M_SCRM_MAGIC 0x4D524353L +#define S3M_SCRS_MAGIC 0x53524353L +#define S3M_SCRS_PCM 0x01 +#define S3M_SCRS_LOOPED 0x01 + +#pragma pack(1) +typedef struct { + CHAR aModuleName[28]; + BYTE bPadding; + BYTE nFileType; + WORD wReserved; + WORD nSongLength; + WORD nSamples; + WORD nPatterns; + WORD wFlags; + WORD wVersion; + WORD nSampleType; + DWORD dwSCRM; + BYTE nGlobalVolume; + BYTE nTempo; + BYTE nBPM; + BYTE nMasterVolume; + BYTE nUltraClick; + BYTE nDefaultPanning; + BYTE aReserved[8]; + WORD wSpecial; + BYTE aChannelTable[32]; +} S3MFILEHEADER; + +typedef struct { + BYTE nType; + CHAR aFileName[13]; + WORD wDataSegPtr; + DWORD dwLength; + DWORD dwLoopStart; + DWORD dwLoopEnd; + BYTE nVolume; + BYTE nReserved; + BYTE nPacking; + BYTE bFlags; + DWORD nSampleRate; + BYTE aReserved[12]; + CHAR aSampleName[28]; + DWORD dwSCRS; +} S3MSAMPLEHEADER; + +typedef struct { + WORD nSize; + LPBYTE lpData; +} S3MPATTERNHEADER; + +typedef struct { + BYTE nNote; + BYTE nSample; + BYTE nVolume; + BYTE nCommand; + BYTE nParams; +} S3MTRACKDATA; +#pragma pack() + +#define ACC 11 +#define MUL(a,b) (((a)*(b)+(1<<(ACC-1)))>>ACC) +#define A (LONG)(12.0 * -2.4991805816500 * (1 << ACC)) +#define B (LONG)(12.0 * +4.0305172865900 * (1 << ACC)) +#define C (LONG)(12.0 * -2.0791605988100 * (1 << ACC)) +#define D (LONG)(12.0 * +0.6262992372690 * (1 << ACC)) +#define E (LONG)(12.0 * -0.0784753434027 * (1 << ACC)) + +static LONG S3MGetRelativeNote(LONG dwSampleRate) +{ + LONG dwRelativeNote; + + /* + * Compute the relative note value given a sampling frequency: + * RelativeNote = 12.0 * log2(SampleRate / 8363.0) + * + * The following algorithm uses 21.11 fixed-point arithmetic + * with an accuracy of about 1/128 for sampling frequencies + * between 522 and 65535 Hertz. (Thanks Zed!) + */ + dwSampleRate = (dwSampleRate << (ACC + 4)) / 8363; + dwRelativeNote = -48L << ACC; + while (dwSampleRate > (2L << ACC)) { + dwSampleRate = (dwSampleRate + 1) >> 1; + dwRelativeNote += (12L << ACC); + } + dwRelativeNote += A + MUL(B + MUL(C + MUL(D + MUL(E, dwSampleRate), + dwSampleRate), dwSampleRate), dwSampleRate); + return dwRelativeNote >> (ACC - 7); +} + +static UINT S3MDecodePattern(UINT nTracks, LPBYTE lpData, UINT nSize, + BYTE aMappingTable[], LPAUDIOPATTERN lpPattern) +{ + static S3MTRACKDATA aTrackTable[S3M_MAX_TRACKS]; + static BYTE aParamTable[S3M_MAX_TRACKS]; + UINT nRow, nTrack, nFlags, nNote, nSample, nVolume, nCommand, nParams; + LPBYTE lpFTData, lpEndData; + + /* initialize the pattern structure */ + lpPattern->nPacking = 0; + lpPattern->nTracks = nTracks; + lpPattern->nRows = S3M_MAX_ROWS; + lpPattern->nSize = 0; + if ((lpPattern->lpData = malloc(nTracks * 6 * S3M_MAX_ROWS)) == NULL) { + return AUDIO_ERROR_NOMEMORY; + } + + lpFTData = lpPattern->lpData; + lpEndData = lpData + nSize; + memset(aParamTable, 0, sizeof(aParamTable)); + for (nRow = 0; nRow < S3M_MAX_ROWS; nRow++) { + /* grab the next row of notes from the S3M pattern */ + memset(aTrackTable, 0, sizeof(aTrackTable)); + while (lpData < lpEndData && (nFlags = *lpData++) != 0x00) { + /* get the note event */ + nNote = 0xFF; + nSample = 0x00; + nVolume = 0xFF; + nCommand = 0x00; + nParams = 0x00; + nTrack = nFlags & 0x1F; + if (nFlags & 0x20) { + nNote = *lpData++; + nSample = *lpData++; + } + if (nFlags & 0x40) { + nVolume = *lpData++; + } + if (nFlags & 0x80) { + nCommand = *lpData++; + nParams = *lpData++; + } + + /* skip notes for non-PCM tracks */ + if ((nTrack = aMappingTable[nTrack]) >= nTracks) + continue; + + /* decode note index */ + if (nNote == 0xFE) { + nNote = AUDIO_MAX_NOTES + 1; + } + else if (nNote == 0xFF) { + nNote = 0x00; + } + else { + nNote = 12 * (nNote >> 4) + (nNote & 0x0F) + 1; + if (nNote > AUDIO_MAX_NOTES) + nNote = 0; + } + + /* decode S3M command effect default parameter stuff */ + nCommand += 0x40; + if (nParams != 0x00) { + aParamTable[nTrack] = nParams; + } + else if (strchr("DEFGKLQ", nCommand)) { + nParams = aParamTable[nTrack]; + } + + /* decode S3M command effect */ + switch (nCommand) { + case '@': + /* null command */ + nCommand = nParams = 0x00; + break; + + case 'A': + /* set tempo speed */ + if (nParams < 0x20) { + nCommand = 0x0F; + } + else { + /* WARNING: tempo greater than 31 are not supported! */ + nCommand = nParams = 0x00; + } + break; + + case 'B': + /* jump position */ + nCommand = 0x0B; + break; + + case 'C': + /* break pattern */ + nCommand = 0x0D; + break; + + case 'D': + if ((nParams & 0xF0) == 0x00) { + /* volume slide down */ + nCommand = 0x0A; + nParams &= 0x0F; + } + else if ((nParams & 0x0F) == 0x00) { + /* volume slide up */ + nCommand = 0x0A; + nParams &= 0xF0; + } + else if ((nParams & 0xF0) == 0xF0) { + /* fine volume slide down */ + nCommand = 0x0E; + nParams = 0xB0 | (nParams & 0x0F); + } + else if ((nParams & 0x0F) == 0x0F) { + /* fine volume slide up */ + nCommand = 0x0E; + nParams = 0xA0 | (nParams >> 4); + } + else { + nCommand = nParams = 0x00; + } + break; + + case 'E': + if ((nParams & 0xF0) == 0xF0) { + /* fine porta down */ + nCommand = 0x0E; + nParams = 0x20 | (nParams & 0x0F); + } + else if ((nParams & 0xF0) == 0xE0) { + /* extra fine porta down */ + nCommand = 0x21; + nParams = 0x20 | (nParams & 0x0F); + } + else { + /* portamento down */ + nCommand = 0x02; + } + break; + + case 'F': + if ((nParams & 0xF0) == 0xF0) { + /* fine portamento up */ + nCommand = 0x0E; + nParams = 0x10 | (nParams & 0x0F); + } + else if ((nParams & 0xF0) == 0xe0) { + /* extra fine portamento up */ + nCommand = 0x21; + nParams = 0x10 | (nParams & 0x0F); + } + else { + /* portamento up */ + nCommand = 0x01; + } + break; + + case 'G': + /* tone portamento */ + nCommand = 0x03; + break; + + case 'H': + /* vibrato */ + nCommand = 0x04; + break; + + case 'I': + /* tremor */ + nCommand = 0x1d; + break; + + case 'J': + /* arpeggio */ + nCommand = 0x00; + break; + + case 'K': + /* vibrato & volume slide */ + nCommand = 0x06; + break; + + case 'L': + /* tone portamento & volume slide */ + nCommand = 0x05; + break; + + case 'O': + /* set sample offset */ + nCommand = 0x09; + break; + + case 'Q': + /* multi-retrig */ + nCommand = 0x1b; + break; + + case 'R': + /* tremolo */ + nCommand = 0x07; + break; + + case 'S': + /* misc settings */ + switch (nParams & 0xF0) { + case 0x00: + /* set filter on/off */ + nCommand = 0x0E; + nParams = 0x00 | (nParams & 0x0F); + break; + + case 0x10: + /* set glissando control */ + nCommand = 0x0E; + nParams = 0x30 | (nParams & 0x0F); + break; + + case 0x20: + /* set fine-tune */ + nCommand = 0x0E; + nParams = 0x50 | (nParams & 0x0F); + break; + + case 0x30: + /* set tremolo waveform */ + nCommand = 0x0E; + nParams = 0x70 | (nParams & 0x0F); + break; + + case 0x40: + /* set vibrato waveform */ + nCommand = 0x0E; + nParams = 0x40 | (nParams & 0x0F); + break; + + case 0x80: + /* set coarse panning */ + nCommand = 0x0E; + nParams = 0x80 | (nParams & 0x0F); + break; + + case 0xA0: + /* set stereo control */ + nCommand = 0x08; + switch (nParams & 0x0F) { + case 0x00: + case 0x02: + /* hard left panning */ + nParams = 0x00; + break; + + case 0x01: + case 0x03: + /* hard right panning */ + nParams = 0xFF; + break; + + case 0x04: + /* left panning */ + nParams = 0x40; + break; + + case 0x05: + /* right panning */ + nParams = 0xC0; + break; + + case 0x06: + case 0x07: + /* middle panning */ + nParams = 0x80; + break; + + default: + nCommand = nParams = 0x00; + break; + } + break; + + case 0xB0: + /* set/start pattern loop */ + nCommand = 0x0E; + nParams = 0x60 | (nParams & 0x0F); + break; + + case 0xC0: + /* note cut */ + nCommand = 0x0E; + nParams = 0xC0 | (nParams & 0x0F); + break; + + case 0xD0: + /* note delay */ + nCommand = 0x0E; + nParams = 0xD0 | (nParams & 0x0F); + break; + + case 0xE0: + /* pattern delay */ + nCommand = 0x0E; + nParams = 0xE0 | (nParams & 0x0F); + break; + + default: + nCommand = nParams = 0x00; + break; + } + break; + + case 'T': + /* set BPM speed */ + if (nParams >= 0x20) + nCommand = 0x0F; + else + nCommand = nParams = 0x00; + break; + + case 'U': + /* fine vibrato */ + /* WARNING: this is not an standard FT2 command! */ + nCommand = 0x1E; + break; + + case 'V': + /* set global volume */ + nCommand = 0x10; + break; + + case 'X': + /* set DMP-style panning */ + nCommand = 0x08; + if (nParams > 0x80) + nParams = 0x80; + else if (nParams < 0x80) + nParams <<= 1; + else + nParams = 0xFF; + break; + + case 'Z': + /* set sync mark */ + /* WARNING: this is not an standard FT2 command! */ + nCommand = 0x23; + break; + + default: + /* unknown S3M command value */ + nCommand = nParams = 0x00; + break; + } + + /* save note message */ + if (nNote) { + aTrackTable[nTrack].nNote = nNote; + } + if (nSample) { + aTrackTable[nTrack].nSample = nSample; + } + if (nVolume <= 64) { + aTrackTable[nTrack].nVolume = 0x10 + nVolume; + } + if (nCommand | nParams) { + aTrackTable[nTrack].nCommand = nCommand; + aTrackTable[nTrack].nParams = nParams; + } + } + + /* encode row of notes in our pattern structure */ + for (nTrack = 0; nTrack < nTracks; nTrack++) { + /* get saved note message */ + nNote = aTrackTable[nTrack].nNote; + nSample = aTrackTable[nTrack].nSample; + nVolume = aTrackTable[nTrack].nVolume; + nCommand = aTrackTable[nTrack].nCommand; + nParams = aTrackTable[nTrack].nParams; + + /* insert new note message */ + nFlags = AUDIO_PATTERN_PACKED; + if (nNote) + nFlags |= AUDIO_PATTERN_NOTE; + if (nSample) + nFlags |= AUDIO_PATTERN_SAMPLE; + if (nVolume) + nFlags |= AUDIO_PATTERN_VOLUME; + if (nCommand) + nFlags |= AUDIO_PATTERN_COMMAND; + if (nParams) + nFlags |= AUDIO_PATTERN_PARAMS; + *lpFTData++ = nFlags; + if (nNote) + *lpFTData++ = nNote; + if (nSample) + *lpFTData++ = nSample; + if (nVolume) + *lpFTData++ = nVolume; + if (nCommand) + *lpFTData++ = nCommand; + if (nParams) + *lpFTData++ = nParams; + } + } + lpPattern->nSize = (lpFTData - lpPattern->lpData); + if ((lpPattern->lpData = realloc(lpPattern->lpData, + lpPattern->nSize)) == NULL) { + return AUDIO_ERROR_NOMEMORY; + } + return AUDIO_ERROR_NONE; +} + +static VOID S3MDecodeSample(LPBYTE lpData, UINT nSize) +{ + /* convert from 8-bit unsigned to 8-bit signed linear */ + while (nSize--) { + *lpData++ ^= 0x80; + } +} + +UINT AIAPI ALoadModuleS3M(LPSTR lpszFileName, + LPAUDIOMODULE *lplpModule, DWORD dwFileOffset) +{ + static S3MFILEHEADER Header; + static S3MSAMPLEHEADER Sample; + static S3MPATTERNHEADER Pattern; + static WORD aSampleSegPtr[S3M_MAX_SAMPLES]; + static WORD aPatternSegPtr[S3M_MAX_PATTERNS]; + static BYTE aPanningTable[S3M_MAX_TRACKS]; + static BYTE aMappingTable[S3M_MAX_TRACKS]; + LPAUDIOMODULE lpModule; + LPAUDIOPATTERN lpPattern; + LPAUDIOPATCH lpPatch; + LPAUDIOSAMPLE lpSample; + LONG dwRelativeNote; + UINT n, nErrorCode; + + if (AIOOpenFile(lpszFileName)) { + printf("File not found\n"); + return AUDIO_ERROR_FILENOTFOUND; + } + AIOSeekFile(dwFileOffset, SEEK_SET); + + if ((lpModule = (LPAUDIOMODULE) calloc(1, sizeof(AUDIOMODULE))) == NULL) { + AIOCloseFile(); + printf("Memory error...\n"); + return AUDIO_ERROR_NOMEMORY; + } + + /* load S3M module file header */ + AIOReadFile(Header.aModuleName, sizeof(Header.aModuleName)); + AIOReadChar(&Header.bPadding); + AIOReadChar(&Header.nFileType); + AIOReadShort(&Header.wReserved); + AIOReadShort(&Header.nSongLength); + AIOReadShort(&Header.nSamples); + AIOReadShort(&Header.nPatterns); + AIOReadShort(&Header.wFlags); + AIOReadShort(&Header.wVersion); + AIOReadShort(&Header.nSampleType); + AIOReadLong(&Header.dwSCRM); + AIOReadChar(&Header.nGlobalVolume); + AIOReadChar(&Header.nTempo); + AIOReadChar(&Header.nBPM); + AIOReadChar(&Header.nMasterVolume); + AIOReadChar(&Header.nUltraClick); + AIOReadChar(&Header.nDefaultPanning); + AIOReadFile(Header.aReserved, sizeof(Header.aReserved)); + AIOReadShort(&Header.wSpecial); + AIOReadFile(Header.aChannelTable, sizeof(Header.aChannelTable)); + printf("[%lX] vs [%lX]\n", Header.dwSCRM, S3M_SCRM_MAGIC); + if (Header.dwSCRM != S3M_SCRM_MAGIC || + Header.nSongLength > S3M_MAX_ORDERS || + Header.nPatterns > S3M_MAX_PATTERNS || + Header.nSamples > S3M_MAX_SAMPLES) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_BADFILEFORMAT; + } + + /* load S3M order table and sample/pattern para-pointers */ + AIOReadFile(lpModule->aOrderTable, Header.nSongLength); + for (n = 0; n < Header.nSamples; n++) { + AIOReadShort(&aSampleSegPtr[n]); + } + for (n = 0; n < Header.nPatterns; n++) { + AIOReadShort(&aPatternSegPtr[n]); + } + + /* load S3M panning table if present */ + memset(aPanningTable, 0x00, sizeof(aPanningTable)); + if (Header.nDefaultPanning == 0xFC) { + AIOReadFile(aPanningTable, sizeof(aPanningTable)); + } + + /* fixup the S3M panning table */ + for (n = 0; n < S3M_MAX_TRACKS; n++) { + if (aPanningTable[n] & 0x20) { + aPanningTable[n] = (aPanningTable[n] & 0x0F) << 4; + } + else { + if (Header.aChannelTable[n] <= 7) { + aPanningTable[n] = 0x00; + } + else if (Header.aChannelTable[n] <= 15) { + aPanningTable[n] = 0xFF; + } + } + } + + /* initialize the module structure */ + strncpy(lpModule->szModuleName, Header.aModuleName, + sizeof(lpModule->szModuleName) - 1); + lpModule->wFlags = AUDIO_MODULE_AMIGA | AUDIO_MODULE_PANNING; + lpModule->nPatterns = Header.nPatterns; + lpModule->nPatches = Header.nSamples; + lpModule->nTempo = Header.nTempo; + lpModule->nBPM = Header.nBPM; + for (n = 0; n < Header.nSongLength; n++) { + if (lpModule->aOrderTable[n] < Header.nPatterns) { + lpModule->aOrderTable[lpModule->nOrders++] = + lpModule->aOrderTable[n]; + } + else { + lpModule->aOrderTable[n] = 0x00; + } + } + /* lpModule->nRestart = lpModule->nOrders; */ + for (n = 0; n < S3M_MAX_TRACKS; n++) { + aMappingTable[n] = 0xFF; + if ((Header.aChannelTable[n] &= 0x7F) <= 15) { + aMappingTable[n] = (BYTE) lpModule->nTracks; + lpModule->aPanningTable[lpModule->nTracks++] = + aPanningTable[n]; + } + } + if ((lpModule->aPatternTable = (LPAUDIOPATTERN) + calloc(lpModule->nPatterns, sizeof(AUDIOPATTERN))) == NULL) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_NOMEMORY; + } + if ((lpModule->aPatchTable = (LPAUDIOPATCH) + calloc(lpModule->nPatches, sizeof(AUDIOPATCH))) == NULL) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_NOMEMORY; + } + + /* load S3M pattern sheets */ + lpPattern = lpModule->aPatternTable; + for (n = 0; n < lpModule->nPatterns; n++, lpPattern++) { + AIOSeekFile(((LONG) aPatternSegPtr[n] << 4) + dwFileOffset, SEEK_SET); + AIOReadShort(&Pattern.nSize); + Pattern.nSize -= sizeof(Pattern.nSize); + if ((Pattern.lpData = malloc(Pattern.nSize)) == NULL) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_NOMEMORY; + } + AIOReadFile(Pattern.lpData, Pattern.nSize); + nErrorCode = S3MDecodePattern(lpModule->nTracks, Pattern.lpData, + Pattern.nSize, aMappingTable, lpPattern); + free(Pattern.lpData); + if (nErrorCode != AUDIO_ERROR_NONE) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return nErrorCode; + } + } + + /* load S3M sample waveforms */ + lpPatch = lpModule->aPatchTable; + for (n = 0; n < lpModule->nPatches; n++, lpPatch++) { + /* load S3M sample header structure */ + AIOSeekFile(((LONG) aSampleSegPtr[n] << 4) + dwFileOffset, SEEK_SET); + AIOReadChar(&Sample.nType); + AIOReadFile(&Sample.aFileName, sizeof(Sample.aFileName)); + AIOReadShort(&Sample.wDataSegPtr); + AIOReadLong(&Sample.dwLength); + AIOReadLong(&Sample.dwLoopStart); + AIOReadLong(&Sample.dwLoopEnd); + AIOReadChar(&Sample.nVolume); + AIOReadChar(&Sample.nReserved); + AIOReadChar(&Sample.nPacking); + AIOReadChar(&Sample.bFlags); + AIOReadLong(&Sample.nSampleRate); + AIOReadFile(Sample.aReserved, sizeof(Sample.aReserved)); + AIOReadFile(Sample.aSampleName, sizeof(Sample.aSampleName)); + AIOReadLong(&Sample.dwSCRS); + if (Sample.nType == S3M_SCRS_PCM && Sample.dwSCRS != S3M_SCRS_MAGIC) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_BADFILEFORMAT; + } + + /* initialize patch structure */ + strncpy(lpPatch->szPatchName, Sample.aSampleName, + sizeof(lpPatch->szPatchName) - 1); + if (Sample.nType == S3M_SCRS_PCM && Sample.dwLength != 0) { + if ((lpSample = (LPAUDIOSAMPLE) + calloc(1, sizeof(AUDIOSAMPLE))) == NULL) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_NOMEMORY; + } + lpPatch->nSamples = 1; + lpPatch->aSampleTable = lpSample; + + /* initialize sample structure */ + lpSample->Wave.wFormat = AUDIO_FORMAT_8BITS; + if (Sample.bFlags & S3M_SCRS_LOOPED) + lpSample->Wave.wFormat |= AUDIO_FORMAT_LOOP; + lpSample->Wave.dwLength = Sample.dwLength; + lpSample->Wave.dwLoopStart = Sample.dwLoopStart; + lpSample->Wave.dwLoopEnd = Sample.dwLoopEnd; + lpSample->Wave.nSampleRate = (WORD) Sample.nSampleRate; + lpSample->nVolume = Sample.nVolume; + lpSample->nPanning = (AUDIO_MIN_PANNING + AUDIO_MAX_PANNING) / 2; + + /* compute fine tuning for this sample */ + if (Sample.nSampleRate != 0) { + dwRelativeNote = S3MGetRelativeNote(Sample.nSampleRate); + lpSample->nRelativeNote = (BYTE) (dwRelativeNote >> 7); + lpSample->nFinetune = (dwRelativeNote & 0x7F); + } + + /* allocate sample waveform data */ + nErrorCode = ACreateAudioData(&lpSample->Wave); + if (nErrorCode != AUDIO_ERROR_NONE) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return nErrorCode; + } + + /* load sample wavefrom data */ + AIOSeekFile(((LONG) Sample.wDataSegPtr << 4) + dwFileOffset, SEEK_SET); + AIOReadFile(lpSample->Wave.lpData, lpSample->Wave.dwLength); + S3MDecodeSample(lpSample->Wave.lpData, lpSample->Wave.dwLength); + AWriteAudioData(&lpSample->Wave, 0, lpSample->Wave.dwLength); + } + } + + AIOCloseFile(); + *lplpModule = lpModule; + return AUDIO_ERROR_NONE; +} diff --git a/seal-hack/src/sbdrv.c b/seal-hack/src/sbdrv.c new file mode 100644 index 0000000..cf331f3 --- /dev/null +++ b/seal-hack/src/sbdrv.c @@ -0,0 +1,762 @@ +/* + * $Id: sbdrv.c 1.7 1996/08/05 18:51:19 chasan released $ + * 1.8 1998/12/24 00:16:00 chasan + * + * Sound Blaster series DSP audio drivers. + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include "audio.h" +#include "drivers.h" +#include "msdos.h" + +#define DEBUG(code) + +/* + * Sound Blaster DSP and Mixer register offsets + */ +#define MIXER_ADDR 0x04 /* mixer index address register */ +#define MIXER_DATA 0x05 /* mixer indexed data register */ +#define DSP_RESET 0x06 /* master reset register */ +#define DSP_READ_DATA 0x0A /* read data register */ +#define DSP_READ_READY 0x0E /* data available register */ +#define DSP_WRITE_DATA 0x0C /* write data register */ +#define DSP_WRITE_BUSY 0x0C /* write status register */ +#define DSP_DMA_ACK_8BIT 0x0E /* 8 bit DMA acknowledge */ +#define DSP_DMA_ACK_16BIT 0x0F /* 16 bit DMA acknowledge */ + +/* + * Sound Blaster 1.0 (DSP 1.x, 2.0, 2.01, 3.xx, 4.xx) command defines + */ +#define DSP_PIO_DAC_8BIT 0x10 /* direct 8 bit output */ +#define DSP_PIO_ADC_8BIT 0x20 /* direct 8 bit input */ +#define DSP_DMA_TIME_CONST 0x40 /* transfer time constant */ +#define DSP_DMA_DAC_8BIT 0x14 /* 8 bit DMA output transfer */ +#define DSP_DMA_ADC_8BIT 0x24 /* 8 bit DMA input transfer */ +#define DSP_DMA_PAUSE_8BIT 0xD0 /* pause 8 bit DMA transfer */ +#define DSP_DMA_CONTINUE_8BIT 0xD4 /* continue 8 bit DMA transfer */ +#define DSP_SPEAKER_ON 0xD1 /* turn speaker on */ +#define DSP_SPEAKER_OFF 0xD3 /* turn speaker off */ +#define DSP_GET_VERSION 0xE1 /* get DSP version */ + +/* + * Sound Blaster 1.5 (DSP 2.0, 2.01, 3.xx, 4.xx) command defines + */ +#define DSP_DMA_BLOCK_SIZE 0x48 /* transfer block size */ +#define DSP_DMA_DAC_AI_8BIT 0x1C /* 8 bit low-speed A/I output */ +#define DSP_DMA_ADC_AI_8BIT 0x2C /* 8 bit low-speed A/I input */ + +/* + * Sound Blaster 2.0 (DSP 2.01, 3.xx) command defines + */ +#define DSP_DMA_DAC_HS_8BIT 0x91 /* 8 bit high-speed output */ +#define DSP_DMA_ADC_HS_8BIT 0x99 /* 8 bit high-speed input */ +#define DSP_DMA_DAC_AI_HS_8BIT 0x90 /* 8 bit high-speed A/I output */ +#define DSP_DMA_ADC_AI_HS_8BIT 0x98 /* 8 bit high-speed A/I input */ + +/* + * Sound Blaster Pro (DSP 3.xx) command defines + */ +#define DSP_DMA_ADC_MONO 0xA0 /* 8 bit mono input mode */ +#define DSP_DMA_ADC_STEREO 0xA8 /* 8 bit stereo input mode */ + +/* + * Sound Blaster 16 (DSP 4.xx) command defines + */ +#define DSP_DMA_DAC_RATE 0x41 /* set output sample rate */ +#define DSP_DMA_ADC_RATE 0x42 /* set input sample rate */ +#define DSP_DMA_START_16BIT 0xB0 /* start 16 bit DMA transfer */ +#define DSP_DMA_START_8BIT 0xC0 /* start 8 bit DMA transfer */ +#define B_DSP_DMA_DAC_MODE 0x06 /* start DAC output mode */ +#define B_DSP_DMA_ADC_MODE 0x0E /* start ADC input mode */ +#define DSP_DMA_STOP_16BIT 0xD9 /* stop 16 bit DMA transfer */ +#define DSP_DMA_STOP_8BIT 0xDA /* stop 8 bit DMA transfer */ +#define DSP_DMA_PAUSE_16BIT 0xD5 /* pause 16 bit DMA transfer */ +#define DSP_DMA_CONTINUE_16BIT 0xD6 /* continue 16 bit DMA transfer */ + +/* + * Sound Blaster Pro mixer indirect registers + */ +#define MIXER_RESET 0x00 /* mixer reset register */ +#define MIXER_INPUT_CONTROL 0x0C /* input control register */ +#define MIXER_OUTPUT_CONTROL 0x0E /* output control register */ +#define MIXER_MASTER_VOLUME 0x22 /* master volume register */ +#define MIXER_VOICE_VOLUME 0x04 /* voice volume register */ +#define MIXER_MIDI_VOLUME 0x26 /* MIDI volume register */ +#define MIXER_CD_VOLUME 0x28 /* CD volume register */ +#define MIXER_LINE_VOLUME 0x2E /* line volume register */ +#define MIXER_MIC_MIXING 0x0A /* mic volume register */ +#define MIXER_IRQ_LINE 0x80 /* IRQ line register */ +#define MIXER_DMA_CHANNEL 0x81 /* DMA channel register */ +#define MIXER_IRQ_STATUS 0x82 /* IRQ status register */ + +/* + * Sound Blaster 16 mixer indirect registers + */ +#define MIXER_MASTER_LEFT 0x30 /* master left volume register */ +#define MIXER_MASTER_RIGHT 0x31 /* master right volume register */ +#define MIXER_VOICE_LEFT 0x32 /* voice left volume register */ +#define MIXER_VOICE_RIGHT 0x33 /* voice right volume register */ +#define MIXER_MIDI_LEFT 0x34 /* MIDI left volume register */ +#define MIXER_MIDI_RIGHT 0x35 /* MIDI right volume register */ +#define MIXER_CD_LEFT 0x36 /* CD left volume register */ +#define MIXER_CD_RIGHT 0x37 /* CD right volume register */ +#define MIXER_LINE_LEFT 0x38 /* line left volume register */ +#define MIXER_LINE_RIGHT 0x39 /* line right volume register */ +#define MIXER_MIC_VOLUME 0x3A /* mic input volume register */ +#define MIXER_SPKR_VOLUME 0x3B /* speaker volume register */ +#define MIXER_OUT_CONTROL 0x3C /* Output Line/CD/MIC control */ +#define MIXER_INPUT_LEFT 0x3D /* input left control bits */ +#define MIXER_INPUT_RIGHT 0x3E /* input right control bits */ +#define MIXER_INPUT_GAIN 0x3F /* input gain level */ +#define MIXER_OUT_GAIN_LEFT 0x41 /* Output gain left level */ +#define MIXER_OUT_GAIN_RIGHT 0x42 /* Output gain right level */ +#define MIXER_INPUT_AUTO_GAIN 0x43 /* input auto gain control */ +#define MIXER_TREBLE_LEFT 0x44 /* Treble left level */ +#define MIXER_TREBLE_RIGHT 0x45 /* Treble right level */ +#define MIXER_BASS_LEFT 0x46 /* Bass left level */ +#define MIXER_BASS_RIGHT 0x47 /* Bass right level */ + +/* + * Input source and filter select register bit fields (MIXER_INPUT_CONTROL) + */ +#define INPUT_SOURCE_MIC 0x00 /* select mic input */ +#define INPUT_SOURCE_CD 0x02 /* select CD input */ +#define INPUT_SOURCE_LINE 0x06 /* select line input */ +#define INPUT_LOW_FILTER 0x00 /* select low-pass filter */ +#define INPUT_HIGH_FILTER 0x08 /* select high-pass filter */ +#define INPUT_NO_FILTER 0x20 /* disable filters */ + +/* + * Output voice feature settings register bit fields (MIXER_OUTPUT_CONTROL) + */ +#define OUTPUT_DISABLE_DNFI 0x20 /* disable output filter */ +#define OUTPUT_ENABLE_VSTC 0x02 /* enable stereo mode */ + +/* + * Mixer output control register bit fields (MIXER_OUT_CONTROL) + */ +#define MUTE_LINE_LEFT 0x10 /* disable left line-out */ +#define MUTE_LINE_RIGHT 0x08 /* disable right line-out */ +#define MUTE_CD_LEFT 0x04 /* disable left CD output */ +#define MUTE_CD_RIGHT 0x02 /* disable right CD output */ +#define MUTE_MICROPHONE 0x01 /* disable MIC output */ + +/* + * Start DMA DAC transfer format bit fields (DSP_DMA_START_8/16BIT) + */ +#define B_DSP_DMA_UNSIGNED 0x00 /* select unsigned samples */ +#define B_DSP_DMA_SIGNED 0x10 /* select signed samples */ +#define B_DSP_DMA_MONO 0x00 /* select mono output */ +#define B_DSP_DMA_STEREO 0x20 /* select stereo output */ + +/* + * Timeout and DMA buffer size defines + */ +#define TIMEOUT 200000 /* number of times to wait for */ +#define BUFFERSIZE 50 /* buffer length in milliseconds */ +#define BUFFRAGSIZE 32 /* buffer fragment size in BYTEs */ + + +/* + * Sound Blaster configuration structure + */ +static struct { + WORD wId; /* audio device indentifier */ + WORD wFormat; /* playback encoding format */ + WORD nSampleRate; /* sampling frequency */ + WORD wPort; /* DSP base port address */ + BYTE nIrqLine; /* interrupt line */ + BYTE nDmaChannel; /* output DMA channel */ + BYTE nLowDmaChannel; /* 8-bit DMA channel */ + BYTE nHighDmaChannel; /* 16-bit DMA channel */ + LPBYTE lpBuffer; /* DMA buffer address */ + UINT nBufferSize; /* DMA buffer length */ + UINT nPosition; /* DMA buffer playing position */ + LPFNAUDIOWAVE lpfnAudioWave; /* user callback routine */ +} SB; + + +/* + * Sound Blaster DSP & Mixer programming routines + */ +static VOID DSPPortB(BYTE bData) +{ + UINT n; + + for (n = 0; n < TIMEOUT; n++) + if (!(INB(SB.wPort + DSP_WRITE_BUSY) & 0x80)) + break; + OUTB(SB.wPort + DSP_WRITE_DATA, bData); +} + +static BYTE DSPPortRB(VOID) +{ + UINT n; + + for (n = 0; n < TIMEOUT; n++) + if (INB(SB.wPort + DSP_READ_READY) & 0x80) + break; + return INB(SB.wPort + DSP_READ_DATA); +} + +static VOID DSPMixerB(BYTE nIndex, BYTE bData) +{ + OUTB(SB.wPort + MIXER_ADDR, nIndex); + OUTB(SB.wPort + MIXER_DATA, bData); +} + +static BYTE DSPMixerRB(BYTE nIndex) +{ + OUTB(SB.wPort + MIXER_ADDR, nIndex); + return INB(SB.wPort + MIXER_DATA); +} + +static WORD DSPGetVersion(VOID) +{ + WORD nMinor, nMajor; + + DSPPortB(DSP_GET_VERSION); + nMajor = DSPPortRB(); + nMinor = DSPPortRB(); + return MAKEWORD(nMinor, nMajor); +} + +static VOID DSPReset(VOID) +{ + UINT n; + + OUTB(SB.wPort + DSP_RESET, 1); + + /* wait 3 microseconds */ + for (n = 0; n < 32; n++) + INB(SB.wPort + DSP_RESET); + + OUTB(SB.wPort + DSP_RESET, 0); +} + +static BOOL DSPProbe(VOID) +{ + WORD nVersion; + UINT n; + + DEBUG(printf("DSPProbe: reset DSP processor\n")); + + /* reset the DSP device */ + for (n = 0; n < 8; n++) { + DSPReset(); + if (DSPPortRB() == 0xAA) + break; + } + if (n >= 8) + return AUDIO_ERROR_NODEVICE; + + DEBUG(printf("DSPProbe: read DSP version\n")); + + /* get the DSP version */ + nVersion = DSPGetVersion(); + + DEBUG(printf("DSPProbe: DSP version 0x%03x\n", nVersion)); + + /* [1998/12/24] don't use anything higher than specified by the user */ + if (nVersion >= 0x400) { + if (SB.wId >= AUDIO_PRODUCT_SB16) + SB.wId = AUDIO_PRODUCT_SB16; + } + else if (nVersion >= 0x300) { + if (SB.wId >= AUDIO_PRODUCT_SBPRO) + SB.wId = AUDIO_PRODUCT_SBPRO; + } + else if (nVersion >= 0x201) { + if (SB.wId >= AUDIO_PRODUCT_SB20) + SB.wId = AUDIO_PRODUCT_SB20; + } + else if (nVersion >= 0x200) { + if (SB.wId >= AUDIO_PRODUCT_SB15) + SB.wId = AUDIO_PRODUCT_SB15; + } + else { + SB.wId = AUDIO_PRODUCT_SB; + } + return AUDIO_ERROR_NONE; +} + +static VOID AIAPI DSPInterruptHandler(VOID) +{ + if (SB.wId == AUDIO_PRODUCT_SB16) { + /* + * Acknowledge 8/16 bit mono/stereo high speed + * autoinit DMA transfer for SB16 (DSP 4.x) cards. + */ + INB(SB.wPort + (SB.wFormat & AUDIO_FORMAT_16BITS ? + DSP_DMA_ACK_16BIT : DSP_DMA_ACK_8BIT)); + } + else if (SB.wId != AUDIO_PRODUCT_SB) { + /* + * Acknowledge 8 bit mono/stereo low/high speed autoinit + * DMA transfer for SB Pro (DSP 3.x), SB 2.0 (DSP 2.01) + * and SB 1.5 (DSP 2.0) cards. + */ + INB(SB.wPort + DSP_DMA_ACK_8BIT); + } + else { + /* + * Acknowledge and restart 8 bit mono low speed + * oneshot DMA transfer for SB 1.0 (DSP 1.x) cards. + */ + INB(SB.wPort + DSP_DMA_ACK_8BIT); + DSPPortB(DSP_DMA_DAC_8BIT); + DSPPortB(0xF0); + DSPPortB(0xFF); + } +} + +static VOID DSPStartPlayback(VOID) +{ + DWORD dwBytesPerSecond; + + DEBUG(printf("DSPStartPlayback: set DMA %d and IRQ %d resources\n", SB.nDmaChannel, SB.nIrqLine)); + + /* setup the DMA channel parameters */ + DosSetupChannel(SB.nDmaChannel, DMA_WRITE | DMA_AUTOINIT, 0); + + /* setup our IRQ interrupt handler */ + DosSetVectorHandler(SB.nIrqLine, DSPInterruptHandler); + + DEBUG(printf("DSPStartPlayback: reset DSP processor\n")); + + /* reset the DSP processor */ + DSPReset(); + + DEBUG(printf("DSPStartPlayback: turn on speaker\n")); + + /* turn on the DSP speaker */ + DSPPortB(DSP_SPEAKER_ON); + + /* [1998/12/04] turn off filter and enable/disable SBPro stereo mode */ + if (SB.wId == AUDIO_PRODUCT_SBPRO) { + DEBUG(printf("DSPStartPlayback: setup SBPro output control\n")); + DSPMixerB(MIXER_OUTPUT_CONTROL, DSPMixerRB(MIXER_OUTPUT_CONTROL) | + OUTPUT_DISABLE_DNFI | + (SB.wFormat & AUDIO_FORMAT_STEREO ? OUTPUT_ENABLE_VSTC : 0)); + } + + DEBUG(printf("DSPStartPlayback: set sample rate\n")); + + /* set DSP output playback rate */ + if (SB.wId == AUDIO_PRODUCT_SB16) { + /* set output sample rate for SB16 cards */ + DSPPortB(DSP_DMA_DAC_RATE); + DSPPortB(HIBYTE(SB.nSampleRate)); + DSPPortB(LOBYTE(SB.nSampleRate)); + } + else { + /* set input/output sample rate for SB/SB20/SBPro cards */ + dwBytesPerSecond = SB.nSampleRate; + if (SB.wFormat & AUDIO_FORMAT_STEREO) + dwBytesPerSecond <<= 1; + DSPPortB(DSP_DMA_TIME_CONST); + DSPPortB((65536 - (256000000L / dwBytesPerSecond)) >> 8); + } + + DEBUG(printf("DSPStartPlayback: start playback transfer\n")); + + /* start DMA playback transfer */ + if (SB.wId == AUDIO_PRODUCT_SB) { + /* + * Start 8 bit mono low speed oneshot DMA output + * transfer for SB 1.0 (DSP 1.x) cards. + */ + DSPPortB(DSP_DMA_DAC_8BIT); + DSPPortB(0xF0); + DSPPortB(0xFF); + } + else if (SB.wId == AUDIO_PRODUCT_SB15) { + /* + * Start 8 bit mono low speed autoinit DMA output + * transfer for SB 1.5 (DSP 2.0) cards. + */ + DSPPortB(DSP_DMA_BLOCK_SIZE); + DSPPortB(0xF0); + DSPPortB(0xFF); + DSPPortB(DSP_DMA_DAC_AI_8BIT); + } + else if (SB.wId == AUDIO_PRODUCT_SB20) { + /* + * Start 8 bit mono high speed autoinit DMA transfer + * output transfer for SB 2.0 (DSP 2.01) cards. + */ + DSPPortB(DSP_DMA_BLOCK_SIZE); + DSPPortB(0xF0); + DSPPortB(0xFF); + DSPPortB(DSP_DMA_DAC_AI_HS_8BIT); + } + else if (SB.wId == AUDIO_PRODUCT_SBPRO) { + /* + * Start 8 bit mono/stereo high speed autoinit + * DMA transfer for SB Pro (DSP 3.x) cards. + */ + DSPPortB(DSP_DMA_BLOCK_SIZE); + DSPPortB(0xF0); + DSPPortB(0xFF); + DSPPortB(DSP_DMA_DAC_AI_HS_8BIT); + } + else { + /* + * Start 8/16 bit mono/stereo high speed autoinit + * DMA transfer for SB16 (DSP 4.x) cards. + */ + if (SB.wFormat & AUDIO_FORMAT_16BITS) { + DSPPortB(DSP_DMA_START_16BIT | B_DSP_DMA_DAC_MODE); + DSPPortB(B_DSP_DMA_SIGNED | (SB.wFormat & AUDIO_FORMAT_STEREO ? + B_DSP_DMA_STEREO : B_DSP_DMA_MONO)); + DSPPortB(0xF0); + DSPPortB(0xFF); + } + else { + DSPPortB(DSP_DMA_START_8BIT | B_DSP_DMA_DAC_MODE); + DSPPortB(B_DSP_DMA_UNSIGNED | (SB.wFormat & AUDIO_FORMAT_STEREO ? + B_DSP_DMA_STEREO : B_DSP_DMA_MONO)); + DSPPortB(0xF0); + DSPPortB(0xFF); + } + } +} + +static VOID DSPStopPlayback(VOID) +{ + DEBUG(printf("DSPStopPlayback: reset DSP processor\n")); + + /* reset the DSP processor */ + DSPReset(); + + DEBUG(printf("DSPStopPlayback: turn off speaker\n")); + + /* turn off DSP speaker */ + DSPPortB(DSP_SPEAKER_OFF); + + /* turn off the stereo flag for SBPro cards */ + if (SB.wId == AUDIO_PRODUCT_SBPRO) { + DSPMixerB(MIXER_OUTPUT_CONTROL, + DSPMixerRB(MIXER_OUTPUT_CONTROL) & ~OUTPUT_ENABLE_VSTC); + } + + DEBUG(printf("DSPStopPlayback: restore DMA %d and IRQ %d resources\n", SB.nDmaChannel, SB.nIrqLine)); + + /* restore the interrupt handler */ + DosSetVectorHandler(SB.nIrqLine, NULL); + + /* reset the DMA channel parameters */ + DosDisableChannel(SB.nDmaChannel); +} + +static UINT DSPInitAudio(VOID) +{ + +#define CLIP(nRate, nMinRate, nMaxRate) \ + (nRate < nMinRate ? nMinRate : \ + (nRate > nMaxRate ? nMaxRate : nRate)) \ + + DEBUG(printf("DSPInitAudio: probe SB hardware at port 0x%03x\n", SB.wPort)); + + /* + * Probe if there is a SB present and detect the DSP version. + */ + if (DSPProbe()) + return AUDIO_ERROR_NODEVICE; + + DEBUG(printf("DSPInitAudio: check format and sample rate\n")); + + /* + * Check playback encoding format and sampling frequency + */ + if (SB.wId == AUDIO_PRODUCT_SB) { + SB.nSampleRate = CLIP(SB.nSampleRate, 4000, 22050); + SB.wFormat &= ~(AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO); + } + else if (SB.wId == AUDIO_PRODUCT_SB15) { + SB.nSampleRate = CLIP(SB.nSampleRate, 5000, 22050); + SB.wFormat &= ~(AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO); + } + else if (SB.wId == AUDIO_PRODUCT_SB20) { + SB.nSampleRate = CLIP(SB.nSampleRate, 5000, 44100); + SB.wFormat &= ~(AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO); + } + else if (SB.wId == AUDIO_PRODUCT_SBPRO) { + if (SB.wFormat & AUDIO_FORMAT_STEREO) { + SB.nSampleRate = CLIP(SB.nSampleRate, 5000, 22050); + } + else { + SB.nSampleRate = CLIP(SB.nSampleRate, 5000, 44100); + } + SB.wFormat &= ~AUDIO_FORMAT_16BITS; + } + else { + SB.nSampleRate = CLIP(SB.nSampleRate, 5000, 44100); + } + if (SB.wId != AUDIO_PRODUCT_SB16) { + SB.nSampleRate = (65536 - (256000000L / SB.nSampleRate)) >> 8; + SB.nSampleRate = 1000000L / (256 - SB.nSampleRate); + } + SB.nDmaChannel = (SB.wFormat & AUDIO_FORMAT_16BITS ? + SB.nHighDmaChannel : SB.nLowDmaChannel); + + DEBUG(printf("DSPInitAudio: DMA channel %d selected\n", SB.nDmaChannel)); + + return AUDIO_ERROR_NONE; +} + +static VOID DSPDoneAudio(VOID) +{ + DEBUG(printf("DSPDoneAudio: reset DSP processor\n")); + + DSPReset(); +} + + +/* + * Sound Blaster audio driver API interface + */ +static UINT AIAPI GetAudioCaps(LPAUDIOCAPS lpCaps) +{ + static AUDIOCAPS Caps = + { + AUDIO_PRODUCT_SB, "Sound Blaster", + AUDIO_FORMAT_1M08 | + AUDIO_FORMAT_2M08 + }; + static AUDIOCAPS Caps15 = + { + AUDIO_PRODUCT_SB15, "Sound Blaster 1.5", + AUDIO_FORMAT_1M08 | + AUDIO_FORMAT_2M08 + }; + static AUDIOCAPS Caps20 = + { + AUDIO_PRODUCT_SB20, "Sound Blaster 2.0", + AUDIO_FORMAT_1M08 | + AUDIO_FORMAT_2M08 | + AUDIO_FORMAT_4M08 + }; + static AUDIOCAPS CapsPro = + { + AUDIO_PRODUCT_SBPRO, "Sound Blaster Pro", + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_4M08 + }; + static AUDIOCAPS Caps16 = + { + AUDIO_PRODUCT_SB16, "Sound Blaster 16", + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_1M16 | AUDIO_FORMAT_1S16 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_2M16 | AUDIO_FORMAT_2S16 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 | + AUDIO_FORMAT_4M16 | AUDIO_FORMAT_4S16 + }; + + switch (SB.wId) { + case AUDIO_PRODUCT_SB16: + memcpy(lpCaps, &Caps16, sizeof(AUDIOCAPS)); + break; + case AUDIO_PRODUCT_SBPRO: + memcpy(lpCaps, &CapsPro, sizeof(AUDIOCAPS)); + break; + case AUDIO_PRODUCT_SB20: + memcpy(lpCaps, &Caps20, sizeof(AUDIOCAPS)); + break; + case AUDIO_PRODUCT_SB15: + memcpy(lpCaps, &Caps15, sizeof(AUDIOCAPS)); + break; + default: + memcpy(lpCaps, &Caps, sizeof(AUDIOCAPS)); + break; + } + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI PingAudio(VOID) +{ + LPSTR lpszBlaster; + UINT nChar; + + DEBUG(printf("SBPingAudio: fetch BLASTER variable\n")); + + SB.wId = AUDIO_PRODUCT_SB16; + SB.wPort = 0x220; + SB.nIrqLine = 5; + SB.nLowDmaChannel = 1; + SB.nHighDmaChannel = 5; + if ((lpszBlaster = DosGetEnvironment("BLASTER")) != NULL) { + nChar = DosParseString(lpszBlaster, TOKEN_CHAR); + while (nChar != 0) { + switch (nChar) { + case 'A': + case 'a': + SB.wPort = DosParseString(NULL, TOKEN_HEX); + break; + case 'I': + case 'i': + SB.nIrqLine = DosParseString(NULL, TOKEN_DEC); + break; + case 'D': + case 'd': + SB.nLowDmaChannel = DosParseString(NULL, TOKEN_DEC); + break; + case 'H': + case 'h': + SB.nHighDmaChannel = DosParseString(NULL, TOKEN_DEC); + break; + case 'T': + case 't': + switch (DosParseString(NULL, TOKEN_DEC)) { + case 1: SB.wId = AUDIO_PRODUCT_SB; break; + case 2: SB.wId = AUDIO_PRODUCT_SB15; break; /*[1998/12/24]*/ + case 3: SB.wId = AUDIO_PRODUCT_SB20; break; + case 4: SB.wId = AUDIO_PRODUCT_SBPRO; break; + case 5: SB.wId = AUDIO_PRODUCT_SBPRO; break; + case 6: SB.wId = AUDIO_PRODUCT_SB16; break; + } + break; + } + nChar = DosParseString(NULL, TOKEN_CHAR); + } + + DEBUG(printf("SBPingAudio: probe SB hardware at Port 0x%03x, IRQ %d, DMA %d/%d\n", SB.wPort, SB.nIrqLine, SB.nLowDmaChannel, SB.nHighDmaChannel)); + + return DSPProbe(); + } + return AUDIO_ERROR_NODEVICE; +} + +static UINT AIAPI OpenAudio(LPAUDIOINFO lpInfo) +{ + DWORD dwBytesPerSecond; + + DEBUG(printf("SBOpenAudio: initialize SB driver\n")); + + /* + * Initialize the SB audio driver for playback + */ + memset(&SB, 0, sizeof(SB)); + SB.wFormat = lpInfo->wFormat; + SB.nSampleRate = lpInfo->nSampleRate; + if (PingAudio()) + return AUDIO_ERROR_NODEVICE; + if (DSPInitAudio()) + return AUDIO_ERROR_NODEVICE; + + DEBUG(printf("SBOpenAudio: allocate DMA buffer\n")); + + /* + * Allocate DMA channel buffer and start playback transfers + */ + dwBytesPerSecond = SB.nSampleRate; + if (SB.wFormat & AUDIO_FORMAT_16BITS) + dwBytesPerSecond <<= 1; + if (SB.wFormat & AUDIO_FORMAT_STEREO) + dwBytesPerSecond <<= 1; + SB.nBufferSize = dwBytesPerSecond / (1000 / BUFFERSIZE); + SB.nBufferSize = (SB.nBufferSize + BUFFRAGSIZE) & -BUFFRAGSIZE; + if (DosAllocChannel(SB.nDmaChannel, SB.nBufferSize)) { + DSPDoneAudio(); + return AUDIO_ERROR_NOMEMORY; + } + if ((SB.lpBuffer = DosLockChannel(SB.nDmaChannel)) != NULL) { + memset(SB.lpBuffer, SB.wFormat & AUDIO_FORMAT_16BITS ? + 0x00 : 0x80, SB.nBufferSize); + DosUnlockChannel(SB.nDmaChannel); + } + + DEBUG(printf("SBOpenAudio: start playback\n")); + + DSPStartPlayback(); + + /* refresh caller's encoding format and sampling frequency */ + lpInfo->wFormat = SB.wFormat; + lpInfo->nSampleRate = SB.nSampleRate; + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI CloseAudio(VOID) +{ + DEBUG(printf("SBCloseAudio: shutdown playback and release resources\n")); + + /* + * Stop DMA playback transfers and reset the DSP processor + */ + DSPStopPlayback(); + DosFreeChannel(SB.nDmaChannel); + DSPDoneAudio(); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudio(UINT nFrames) +{ + int nBlockSize, nSize; + + if (SB.wFormat & AUDIO_FORMAT_16BITS) nFrames <<= 1; + if (SB.wFormat & AUDIO_FORMAT_STEREO) nFrames <<= 1; + if (nFrames <= 0 || nFrames > SB.nBufferSize) + nFrames = SB.nBufferSize; + + if ((SB.lpBuffer = DosLockChannel(SB.nDmaChannel)) != NULL) { + nBlockSize = SB.nBufferSize - SB.nPosition - + DosGetChannelCount(SB.nDmaChannel); + if (nBlockSize < 0) + nBlockSize += SB.nBufferSize; + + if (nBlockSize > nFrames) + nBlockSize = nFrames; + + nBlockSize &= -BUFFRAGSIZE; + while (nBlockSize != 0) { + nSize = SB.nBufferSize - SB.nPosition; + if (nSize > nBlockSize) + nSize = nBlockSize; + if (SB.lpfnAudioWave != NULL) { + SB.lpfnAudioWave(&SB.lpBuffer[SB.nPosition], nSize); + } + else { + memset(&SB.lpBuffer[SB.nPosition], + SB.wFormat & AUDIO_FORMAT_16BITS ? + 0x00 : 0x80, nSize); + } + if ((SB.nPosition += nSize) >= SB.nBufferSize) + SB.nPosition -= SB.nBufferSize; + nBlockSize -= nSize; + } + DosUnlockChannel(SB.nDmaChannel); + } + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + SB.lpfnAudioWave = lpfnAudioWave; + return AUDIO_ERROR_NONE; +} + + +/* + * Sound Blaster drivers public interface + */ +AUDIOWAVEDRIVER SoundBlasterWaveDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudio, SetAudioCallback +}; + +AUDIODRIVER SoundBlasterDriver = +{ + &SoundBlasterWaveDriver, NULL +}; diff --git a/seal-hack/src/sdldrv.c b/seal-hack/src/sdldrv.c new file mode 100644 index 0000000..e1887f6 --- /dev/null +++ b/seal-hack/src/sdldrv.c @@ -0,0 +1,183 @@ +/* + * $Id: lnxdrv.c 1.5 1996/08/05 18:51:19 chasan released $ + * + * SDL audio driver. Turns SEAL into a mixer on top of SDL. + * + * Copyright 2002 Greg Velichansky (hmaon@bumba.net) + * + * Based in part on the Linux Voxware driver, + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include + +#include "SDL.h" + +#include "audio.h" +#include "drivers.h" + + +/* + * fragments defines + */ +#define NUMFRAGS 16 +#define FRAGSIZE 11 +#define BUFFERSIZE (1 << FRAGSIZE) + +/* + * configuration structure + */ +static struct AudioStruct { + SDL_AudioSpec desired, spec; + BYTE aBuffer[BUFFERSIZE*4]; + LPFNAUDIOWAVE lpfnAudioWave; + WORD wFormat; +} Audio; + + +/* + * Linux driver API interface + */ +static UINT AIAPI GetAudioCaps(LPAUDIOCAPS lpCaps) +{ + static AUDIOCAPS Caps = + { + AUDIO_PRODUCT_LINUX, "SDL", + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_1M16 | AUDIO_FORMAT_1S16 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_2M16 | AUDIO_FORMAT_2S16 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 | + AUDIO_FORMAT_4M16 | AUDIO_FORMAT_4S16 + }; + + memcpy(lpCaps, &Caps, sizeof(AUDIOCAPS)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI PingAudio(VOID) +{ + return 0; +/* return (SDL_INIT_AUDIO == SDL_WasInit(SDL_INIT_AUDIO)); */ +} + +static void updatecallback(void *userdata, Uint8 *stream, int len); + +static UINT AIAPI OpenAudio(LPAUDIOINFO lpInfo) +{ + int nBitsPerSample, nStereoOn, nSampleRate, nFrags; + + memset(&Audio, 0, sizeof(Audio)); + + if (!SDL_WasInit(SDL_INIT_EVERYTHING)) + { + SDL_Init(SDL_INIT_AUDIO); + } else + { + if (!SDL_WasInit(SDL_INIT_AUDIO) && SDL_InitSubSystem(SDL_INIT_AUDIO)) + return AUDIO_ERROR_NODEVICE; + } + if (SDL_INIT_AUDIO != SDL_WasInit(SDL_INIT_AUDIO)) + return AUDIO_ERROR_NODEVICE; + + + nBitsPerSample = lpInfo->wFormat & AUDIO_FORMAT_16BITS ? 16 : 8; + nStereoOn = lpInfo->wFormat & AUDIO_FORMAT_STEREO ? 1 : 0; + /*nSampleRate = lpInfo->nSampleRate;*/ + + Audio.desired.freq = lpInfo->nSampleRate; + Audio.desired.samples = 512; + Audio.desired.channels = nStereoOn ? 2 : 1; + + Audio.desired.format = (lpInfo->wFormat & AUDIO_FORMAT_16BITS) ? AUDIO_U16SYS : AUDIO_U8; + + Audio.desired.userdata = (void*)&Audio; + + Audio.desired.callback = updatecallback; + + SDL_OpenAudio(&(Audio.desired), &(Audio.spec)); + + /* we should probably do something here... blah... whatever :/ */ + + /* setup number and size of buffer fragments */ + /*nFrags = (NUMFRAGS << 16) + (FRAGSIZE); + ioctl(Audio.nHandle, SNDCTL_DSP_SETFRAGMENT, &nFrags);*/ + + /* setup audio playback encoding format and sampling frequency */ + /*if (ioctl(Audio.nHandle, SNDCTL_DSP_SAMPLESIZE, &nBitsPerSample) < 0 || + ioctl(Audio.nHandle, SNDCTL_DSP_STEREO, &nStereoOn) < 0 || + ioctl(Audio.nHandle, SNDCTL_DSP_SPEED, &nSampleRate) < 0) { + close(Audio.nHandle); + return AUDIO_ERROR_BADFORMAT; + }*/ + + /*Audio.wFormat = lpInfo->wFormat;*/ + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI CloseAudio(VOID) +{ + SDL_CloseAudio(); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudio(UINT nFrames) +{ + /* compute frame size */ + /*if (Audio.wFormat & AUDIO_FORMAT_16BITS) nFrames <<= 1; + if (Audio.wFormat & AUDIO_FORMAT_STEREO) nFrames <<= 1; + if (nFrames <= 0 || nFrames > sizeof(Audio.aBuffer)) + nFrames = sizeof(Audio.aBuffer);*/ + + /* send PCM samples to the DSP audio device */ + /*if (Audio.lpfnAudioWave != NULL) { + Audio.lpfnAudioWave(Audio.aBuffer, nFrames); + write(Audio.nHandle, Audio.aBuffer, nFrames); + }*/ + + SDL_PauseAudio(0); /* the only use I can think of for UpdateAudio() ...*/ + + return AUDIO_ERROR_NONE; +} + + + +static void updatecallback(void *userdata, Uint8 *stream, int len) +{ + struct AudioStruct *aud = userdata; + /* maybe this isn't necessary, we know where Audio is, after all... */ + aud->lpfnAudioWave(stream, len); /* God speed... */ +} + + + +static UINT AIAPI SetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + /* set up DSP audio device user's callback function */ + Audio.lpfnAudioWave = lpfnAudioWave; + return AUDIO_ERROR_NONE; +} + + +/* + * Linux driver public interface + */ +AUDIOWAVEDRIVER SDLWaveDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudio, SetAudioCallback +}; + +AUDIODRIVER SDLDriver = +{ + &SDLWaveDriver, NULL +}; diff --git a/seal-hack/src/sgidrv.c b/seal-hack/src/sgidrv.c new file mode 100644 index 0000000..d4165ca --- /dev/null +++ b/seal-hack/src/sgidrv.c @@ -0,0 +1,135 @@ +/* + * $Id: sgidrv.c 1.5 1996/08/05 18:51:19 chasan released $ + * + * Silicon Graphics Indigo audio driver. + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include "audio.h" +#include "drivers.h" + +/* + * SGI audio driver buffer size + */ +#define BUFFERSIZE 2048 + +/* + * SGI audio driver configuration structure + */ +static struct { + ALport Port; + ALconfig Config; + WORD wFormat; + BYTE aBuffer[BUFFERSIZE]; + LPFNAUDIOWAVE lpfnAudioWave; +} Audio; + + +/* + * SGI audio driver API interface + */ +static UINT AIAPI GetAudioCaps(LPAUDIOCAPS lpCaps) +{ + static AUDIOCAPS Caps = + { + AUDIO_PRODUCT_SGI, "Silicon Graphics", + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_1M16 | AUDIO_FORMAT_1S16 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_2M16 | AUDIO_FORMAT_2S16 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 | + AUDIO_FORMAT_4M16 | AUDIO_FORMAT_4S16 + }; + + memcpy(lpCaps, &Caps, sizeof(AUDIOCAPS)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI PingAudio(VOID) +{ + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI OpenAudio(LPAUDIOINFO lpInfo) +{ + long op[2]; + + memset(&Audio, 0, sizeof(Audio)); + + if ((Audio.Config = ALnewconfig()) != NULL) { + /* setup encoding format for playback */ + ALsetwidth(Audio.Config, lpInfo->wFormat & AUDIO_FORMAT_16BITS ? + AL_SAMPLE_16 : AL_SAMPLE_8); + ALsetchannels(Audio.Config, lpInfo->wFormat & AUDIO_FORMAT_STEREO ? + AL_STEREO : AL_MONO); + + /* open audio port and configure it */ + Audio.Port = ALopenport("Audio Port", "w", Audio.Config); + Audio.wFormat = lpInfo->wFormat; + + /* setup playback sampling frequency */ + if (Audio.Port != NULL) { + op[0] = AL_OUTPUT_RATE; + op[1] = lpInfo->nSampleRate; + ALsetparms(AL_DEFAULT_DEVICE, op, 2); + return AUDIO_ERROR_NONE; + } + } + return AUDIO_ERROR_DEVICEBUSY; +} + +static UINT AIAPI CloseAudio(VOID) +{ + while (ALgetfilled(Audio.Port) > 0) + sleep(1); + ALcloseport(Audio.Port); + ALfreeconfig(Audio.Config); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudio(UINT nFrames) +{ + if (Audio.wFormat & AUDIO_FORMAT_16BITS) nFrames <<= 1; + if (Audio.wFormat & AUDIO_FORMAT_STEREO) nFrames <<= 1; + if (nFrames <= 0 || nFrames >= sizeof(Audio.aBuffer)) + nFrames = sizeof(Audio.aBuffer); + + if (Audio.lpfnAudioWave != NULL) { + Audio.lpfnAudioWave(Audio.aBuffer, nFrames); + ALwritesamps(Audio.Port, Audio.aBuffer, nFrames >> + ((Audio.wFormat & AUDIO_FORMAT_16BITS) != 0)); + } + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + Audio.lpfnAudioWave = lpfnAudioWave; + return AUDIO_ERROR_NONE; +} + + +/* + * SGI audio driver public interface + */ +AUDIOWAVEDRIVER SiliconWaveDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudio, SetAudioCallback +}; + +AUDIODRIVER SiliconDriver = +{ + &SiliconWaveDriver, NULL +}; diff --git a/seal-hack/src/sundrv.c b/seal-hack/src/sundrv.c new file mode 100644 index 0000000..f38386e --- /dev/null +++ b/seal-hack/src/sundrv.c @@ -0,0 +1,257 @@ +/* + * $Id: sundrv.c 1.5 1996/08/05 18:51:19 chasan released $ + * + * SPARCstation SunOS and Solaris audio drivers. + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __SOLARIS__ +#include +#else +#include +#endif +#include "audio.h" +#include "drivers.h" + + +/* + * SPARC driver audio buffer size + */ +#define BUFFERSIZE 2048 + +/* + * Table for 8 bit unsigned PCM linear to companded u-law conversion + * (Reference: CCITT Recommendation G.711) + */ +static BYTE auLawTable[256] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, + 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, + 0x03, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, + 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, + 0x07, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, + 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, + 0x0f, 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x13, + 0x13, 0x14, 0x14, 0x15, 0x15, 0x16, 0x16, 0x17, + 0x17, 0x18, 0x18, 0x19, 0x19, 0x1a, 0x1a, 0x1b, + 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, + 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, + 0x2f, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, + 0x3e, 0x41, 0x45, 0x49, 0x4d, 0x53, 0x5b, 0x67, + 0xff, 0xe7, 0xdb, 0xd3, 0xcd, 0xc9, 0xc5, 0xc1, + 0xbe, 0xbc, 0xba, 0xb8, 0xb6, 0xb4, 0xb2, 0xb0, + 0xaf, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, 0xa8, + 0xa7, 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1, 0xa0, + 0x9f, 0x9f, 0x9e, 0x9e, 0x9d, 0x9d, 0x9c, 0x9c, + 0x9b, 0x9b, 0x9a, 0x9a, 0x99, 0x99, 0x98, 0x98, + 0x97, 0x97, 0x96, 0x96, 0x95, 0x95, 0x94, 0x94, + 0x93, 0x93, 0x92, 0x92, 0x91, 0x91, 0x90, 0x90, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8a, 0x8a, 0x8a, 0x8a, + 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, + 0x87, 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, + 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84, + 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, + 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80 +}; + +/* + * Table of supported sampling frequencies of dbri devices + */ +static LONG aSampleRate[] = +{ + 8000, 9600, 11025, 16000, 18900, 22050, 32000, 37800, 44100, 48000 +}; + +/* + * SPARC driver configuration structure + */ +static struct { + int nHandle; + int nEncoding; + BYTE aBuffer[BUFFERSIZE]; + LPFNAUDIOWAVE lpfnAudioWave; + WORD wFormat; +} Audio; + + +static LONG GetSampleRate(LONG nSampleRate) +{ + int n; + + /* return the nearest supported sampling frequency */ + for (n = 0; n < sizeof(aSampleRate) / sizeof(LONG) - 1; n++) { + if (nSampleRate <= aSampleRate[n]) + break; + } + return aSampleRate[n]; +} + + +/* + * SPARC audio driver API interface + */ +static UINT AIAPI GetAudioCaps(LPAUDIOCAPS lpCaps) +{ + static AUDIOCAPS Caps = + { + AUDIO_PRODUCT_SPARC, "SPARC SunOS", +#ifdef __SOLARIS__ + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_1M16 | AUDIO_FORMAT_1S16 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_2M16 | AUDIO_FORMAT_2S16 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 | + AUDIO_FORMAT_4M16 | AUDIO_FORMAT_4S16 +#else + AUDIO_FORMAT_1M08 +#endif + }; + + memcpy(lpCaps, &Caps, sizeof(AUDIOCAPS)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI PingAudio(VOID) +{ + return access("/dev/audio", W_OK) ? AUDIO_ERROR_NODEVICE : AUDIO_ERROR_NONE; +} + +static UINT AIAPI OpenAudio(LPAUDIOINFO lpInfo) +{ + int dbri, type; + audio_info_t info; +#ifdef __SOLARIS__ + audio_device_t dev; +#endif + + memset(&Audio, 0, sizeof(Audio)); + + /* try to open the audio device for playback */ +#ifdef __SOLARIS__ + if ((Audio.nHandle = open("/dev/audio", O_WRONLY)) < 0) + return AUDIO_ERROR_DEVICEBUSY; +#else + if ((Audio.nHandle = open("/dev/audio", O_WRONLY | O_NDELAY)) < 0) + return AUDIO_ERROR_DEVICEBUSY; +#endif + + /* check whether we know about linear encoding */ +#ifdef __SOLARIS__ + dbri = (ioctl(Audio.nHandle, AUDIO_GETDEV, &dev) == 0 && + strcmp(dev.name, "SUNW,dbri") == 0); +#else +#ifdef AUDIO_GETDEV + dbri = (ioctl(Audio.nHandle, AUDIO_GETDEV, &type) == 0 && + type != AUDIO_DEV_AMD); +#else + /* + * There is no AUDIO_GETDEV under SunOS 4.1.1 so we have to + * assume that there is an AMD device attached to /dev/audio. + */ + dbri = 0; +#endif +#endif + + /* setup audio configuration structure */ + AUDIO_INITINFO(&info); + if (dbri) { + /* configure linear encoding for dbri devices */ + info.play.encoding = AUDIO_ENCODING_LINEAR; + info.play.channels = lpInfo->wFormat & AUDIO_FORMAT_STEREO ? 2 : 1; + info.play.precision = lpInfo->wFormat & AUDIO_FORMAT_16BITS ? 16 : 8; + info.play.sample_rate = GetSampleRate(lpInfo->nSampleRate); + } + else { + /* configure companded u-law encoding for AMD devices */ + info.play.encoding = AUDIO_ENCODING_ULAW; + info.play.channels = 1; + info.play.precision = 8; + info.play.sample_rate = 8000; + } + + /* commit playback encoding format */ + Audio.nEncoding = info.play.encoding; + if (ioctl(Audio.nHandle, AUDIO_SETINFO, &info) < 0) { + close(Audio.nHandle); + return AUDIO_ERROR_BADFORMAT; + } + + /* refresh configuration structure */ + lpInfo->wFormat &= ~(AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO); + lpInfo->wFormat |= info.play.precision != 16 ? + AUDIO_FORMAT_8BITS : AUDIO_FORMAT_16BITS; + lpInfo->wFormat |= info.play.channels != 2 ? + AUDIO_FORMAT_MONO : AUDIO_FORMAT_STEREO; + lpInfo->nSampleRate = info.play.sample_rate; + + Audio.wFormat = lpInfo->wFormat; + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI CloseAudio(VOID) +{ + ioctl(Audio.nHandle, AUDIO_DRAIN, NULL); + close(Audio.nHandle); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI UpdateAudio(UINT nFrames) +{ + int n; + + if (Audio.wFormat & AUDIO_FORMAT_16BITS) nFrames <<= 1; + if (Audio.wFormat & AUDIO_FORMAT_STEREO) nFrames <<= 1; + if (nFrames <= 0 || nFrames > sizeof(Audio.aBuffer)) + nFrames = sizeof(Audio.aBuffer); + + if (Audio.lpfnAudioWave != NULL) { + Audio.lpfnAudioWave(Audio.aBuffer, nFrames); + if (Audio.nEncoding == AUDIO_ENCODING_ULAW) { + for (n = 0; n < nFrames; n++) { + Audio.aBuffer[n] = auLawTable[Audio.aBuffer[n]]; + } + } + write(Audio.nHandle, Audio.aBuffer, nFrames); + } + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + Audio.lpfnAudioWave = lpfnAudioWave; + return AUDIO_ERROR_NONE; +} + + +/* + * SPARC audio driver public interface + */ +AUDIOWAVEDRIVER SparcWaveDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudio, SetAudioCallback +}; + +AUDIODRIVER SparcDriver = +{ + &SparcWaveDriver, NULL +}; diff --git a/seal-hack/src/tables.h b/seal-hack/src/tables.h new file mode 100644 index 0000000..f375221 --- /dev/null +++ b/seal-hack/src/tables.h @@ -0,0 +1,197 @@ +/* + * $Id: tables.h 1.4 1996/08/05 18:51:19 chasan released $ + * + * Extended module player private resources. + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __TABLES_H +#define __TABLES_H + +/* dwFrequency = 8363*2^((6*12*16*4 - wPeriod)/(12*16*4)) */ +static LONG aFrequencyTable[12 * 16 * 4] = +{ + 535232, 534749, 534267, 533785, 533303, 532822, 532341, 531861, + 531381, 530902, 530423, 529945, 529466, 528989, 528512, 528035, + 527558, 527083, 526607, 526132, 525657, 525183, 524709, 524236, + 523763, 523291, 522819, 522347, 521876, 521405, 520934, 520465, + 519995, 519526, 519057, 518589, 518121, 517654, 517187, 516720, + 516254, 515788, 515323, 514858, 514394, 513930, 513466, 513003, + 512540, 512078, 511616, 511154, 510693, 510232, 509772, 509312, + 508853, 508394, 507935, 507477, 507019, 506561, 506104, 505648, + 505192, 504736, 504281, 503826, 503371, 502917, 502463, 502010, + 501557, 501105, 500653, 500201, 499750, 499299, 498849, 498399, + 497949, 497500, 497051, 496602, 496154, 495707, 495260, 494813, + 494367, 493921, 493475, 493030, 492585, 492141, 491697, 491253, + 490810, 490367, 489925, 489483, 489041, 488600, 488159, 487719, + 487279, 486839, 486400, 485961, 485523, 485085, 484647, 484210, + 483773, 483337, 482901, 482465, 482030, 481595, 481161, 480727, + 480293, 479860, 479427, 478994, 478562, 478130, 477699, 477268, + 476838, 476407, 475978, 475548, 475119, 474691, 474262, 473834, + 473407, 472980, 472553, 472127, 471701, 471275, 470850, 470426, + 470001, 469577, 469154, 468730, 468307, 467885, 467463, 467041, + 466620, 466199, 465778, 465358, 464938, 464519, 464100, 463681, + 463263, 462845, 462427, 462010, 461593, 461177, 460761, 460345, + 459930, 459515, 459101, 458686, 458273, 457859, 457446, 457033, + 456621, 456209, 455798, 455386, 454976, 454565, 454155, 453745, + 453336, 452927, 452519, 452110, 451702, 451295, 450888, 450481, + 450075, 449669, 449263, 448858, 448453, 448048, 447644, 447240, + 446837, 446434, 446031, 445628, 445226, 444825, 444424, 444023, + 443622, 443222, 442822, 442423, 442023, 441625, 441226, 440828, + 440430, 440033, 439636, 439240, 438843, 438447, 438052, 437657, + 437262, 436867, 436473, 436080, 435686, 435293, 434900, 434508, + 434116, 433725, 433333, 432942, 432552, 432162, 431772, 431382, + 430993, 430604, 430216, 429828, 429440, 429052, 428665, 428279, + 427892, 427506, 427121, 426735, 426350, 425966, 425581, 425198, + 424814, 424431, 424048, 423665, 423283, 422901, 422520, 422139, + 421758, 421377, 420997, 420617, 420238, 419859, 419480, 419102, + 418723, 418346, 417968, 417591, 417215, 416838, 416462, 416086, + 415711, 415336, 414961, 414587, 414213, 413839, 413466, 413093, + 412720, 412348, 411976, 411604, 411233, 410862, 410491, 410121, + 409751, 409381, 409012, 408643, 408274, 407906, 407538, 407171, + 406803, 406436, 406070, 405703, 405337, 404972, 404606, 404241, + 403877, 403512, 403148, 402784, 402421, 402058, 401695, 401333, + 400971, 400609, 400248, 399887, 399526, 399166, 398805, 398446, + 398086, 397727, 397368, 397010, 396652, 396294, 395936, 395579, + 395222, 394866, 394510, 394154, 393798, 393443, 393088, 392733, + 392379, 392025, 391671, 391318, 390965, 390612, 390260, 389908, + 389556, 389205, 388854, 388503, 388152, 387802, 387452, 387103, + 386754, 386405, 386056, 385708, 385360, 385012, 384665, 384318, + 383971, 383625, 383279, 382933, 382587, 382242, 381897, 381553, + 381209, 380865, 380521, 380178, 379835, 379492, 379150, 378808, + 378466, 378125, 377784, 377443, 377102, 376762, 376422, 376083, + 375743, 375404, 375066, 374727, 374389, 374052, 373714, 373377, + 373040, 372704, 372367, 372032, 371696, 371361, 371026, 370691, + 370356, 370022, 369689, 369355, 369022, 368689, 368356, 368024, + 367692, 367360, 367029, 366698, 366367, 366036, 365706, 365376, + 365047, 364717, 364388, 364060, 363731, 363403, 363075, 362748, + 362420, 362094, 361767, 361440, 361114, 360789, 360463, 360138, + 359813, 359489, 359164, 358840, 358516, 358193, 357870, 357547, + 357225, 356902, 356580, 356259, 355937, 355616, 355295, 354975, + 354655, 354335, 354015, 353696, 353376, 353058, 352739, 352421, + 352103, 351785, 351468, 351151, 350834, 350518, 350201, 349886, + 349570, 349255, 348939, 348625, 348310, 347996, 347682, 347368, + 347055, 346742, 346429, 346117, 345804, 345492, 345181, 344869, + 344558, 344247, 343937, 343627, 343317, 343007, 342697, 342388, + 342079, 341771, 341462, 341154, 340847, 340539, 340232, 339925, + 339618, 339312, 339006, 338700, 338394, 338089, 337784, 337479, + 337175, 336871, 336567, 336263, 335960, 335657, 335354, 335052, + 334749, 334447, 334146, 333844, 333543, 333242, 332941, 332641, + 332341, 332041, 331742, 331442, 331143, 330845, 330546, 330248, + 329950, 329652, 329355, 329058, 328761, 328464, 328168, 327872, + 327576, 327281, 326986, 326691, 326396, 326101, 325807, 325513, + 325220, 324926, 324633, 324340, 324048, 323755, 323463, 323171, + 322880, 322589, 322298, 322007, 321716, 321426, 321136, 320846, + 320557, 320268, 319979, 319690, 319402, 319114, 318826, 318538, + 318251, 317964, 317677, 317390, 317104, 316818, 316532, 316247, + 315961, 315676, 315391, 315107, 314823, 314539, 314255, 313971, + 313688, 313405, 313122, 312840, 312558, 312276, 311994, 311713, + 311431, 311150, 310870, 310589, 310309, 310029, 309749, 309470, + 309191, 308912, 308633, 308355, 308077, 307799, 307521, 307244, + 306966, 306690, 306413, 306136, 305860, 305584, 305309, 305033, + 304758, 304483, 304208, 303934, 303660, 303386, 303112, 302839, + 302566, 302293, 302020, 301747, 301475, 301203, 300932, 300660, + 300389, 300118, 299847, 299577, 299306, 299036, 298767, 298497, + 298228, 297959, 297690, 297421, 297153, 296885, 296617, 296350, + 296082, 295815, 295548, 295282, 295015, 294749, 294483, 294218, + 293952, 293687, 293422, 293157, 292893, 292629, 292365, 292101, + 291837, 291574, 291311, 291048, 290786, 290523, 290261, 289999, + 289738, 289476, 289215, 288954, 288694, 288433, 288173, 287913, + 287653, 287394, 287135, 286876, 286617, 286358, 286100, 285842, + 285584, 285326, 285069, 284812, 284555, 284298, 284042, 283785, + 283529, 283273, 283018, 282763, 282508, 282253, 281998, 281744, + 281489, 281236, 280982, 280728, 280475, 280222, 279969, 279717, + 279464, 279212, 278960, 278709, 278457, 278206, 277955, 277704, + 277454, 277204, 276953, 276704, 276454, 276205, 275955, 275706, + 275458, 275209, 274961, 274713, 274465, 274217, 273970, 273723, + 273476, 273229, 272983, 272737, 272491, 272245, 271999, 271754, + 271509, 271264, 271019, 270774, 270530, 270286, 270042, 269799, + 269555, 269312, 269069, 268826, 268584, 268342, 268100, 267858 +}; + +/* wPeriod = 4*16*428*2^(-nNote/(12*16)) */ +static WORD aPeriodTable[12 * 16] = +{ + 27392, 27293, 27195, 27097, 26999, 26902, 26805, 26708, + 26612, 26516, 26421, 26326, 26231, 26136, 26042, 25948, + 25855, 25761, 25669, 25576, 25484, 25392, 25301, 25209, + 25119, 25028, 24938, 24848, 24758, 24669, 24580, 24492, + 24403, 24316, 24228, 24141, 24054, 23967, 23881, 23795, + 23709, 23623, 23538, 23453, 23369, 23285, 23201, 23117, + 23034, 22951, 22868, 22786, 22704, 22622, 22540, 22459, + 22378, 22297, 22217, 22137, 22057, 21978, 21899, 21820, + 21741, 21663, 21585, 21507, 21429, 21352, 21275, 21199, + 21122, 21046, 20970, 20895, 20819, 20744, 20670, 20595, + 20521, 20447, 20373, 20300, 20227, 20154, 20081, 20009, + 19937, 19865, 19793, 19722, 19651, 19580, 19509, 19439, + 19369, 19299, 19230, 19160, 19091, 19023, 18954, 18886, + 18818, 18750, 18682, 18615, 18548, 18481, 18414, 18348, + 18282, 18216, 18150, 18085, 18020, 17955, 17890, 17826, + 17762, 17698, 17634, 17570, 17507, 17444, 17381, 17318, + 17256, 17194, 17132, 17070, 17008, 16947, 16886, 16825, + 16765, 16704, 16644, 16584, 16524, 16465, 16405, 16346, + 16287, 16229, 16170, 16112, 16054, 15996, 15938, 15881, + 15824, 15767, 15710, 15653, 15597, 15541, 15485, 15429, + 15373, 15318, 15263, 15208, 15153, 15098, 15044, 14990, + 14936, 14882, 14828, 14775, 14721, 14668, 14616, 14563, + 14510, 14458, 14406, 14354, 14302, 14251, 14199, 14148, + 14097, 14047, 13996, 13945, 13895, 13845, 13795, 13746 +}; + +static BYTE aSineTable[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 +}; + +static signed char aRetrigTable[32] = +{ + 0, -1, -2, -4, -8, -16, 0, 0, 0, 1, 2, 4, 8, 16, 0, 0, + 16, 16, 16, 16, 16, 16, 11, 8, 16, 16, 16, 16, 16, 16, 24, 32 +}; + +static signed char aAutoVibratoTable[256] = +{ + 0, -1, -2, -4, -5, -7, -8,-10, + -11,-13,-15,-16,-18,-19,-21,-22, + -23,-25,-26,-28,-29,-31,-32,-33, + -35,-36,-37,-38,-40,-41,-42,-43, + -44,-45,-46,-47,-48,-49,-50,-51, + -52,-53,-54,-55,-55,-56,-57,-58, + -58,-59,-59,-60,-60,-61,-61,-61, + -62,-62,-62,-63,-63,-63,-63,-63, + -63,-63,-63,-63,-63,-63,-62,-62, + -62,-61,-61,-61,-60,-60,-59,-59, + -58,-58,-57,-56,-55,-55,-54,-53, + -52,-51,-50,-49,-48,-47,-46,-45, + -44,-43,-42,-41,-40,-38,-37,-36, + -35,-33,-32,-31,-29,-28,-26,-25, + -23,-22,-21,-19,-18,-16,-15,-13, + -11,-10, -8, -7, -5, -4, -2, -1, + 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 +}; + +#endif diff --git a/seal-hack/src/wavfile.c b/seal-hack/src/wavfile.c new file mode 100644 index 0000000..7b9939a --- /dev/null +++ b/seal-hack/src/wavfile.c @@ -0,0 +1,152 @@ +/* + * $Id: wavfile.c 1.7 1996/09/13 15:10:22 chasan released $ + * + * Windows RIFF/WAVE PCM file loader routines. + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include "audio.h" +#include "iofile.h" + + +/* + * Windows RIFF/WAVE PCM file structures + */ + +#define FOURCC_RIFF 0x46464952L +#define FOURCC_WAVE 0x45564157L +#define FOURCC_FMT 0x20746D66L +#define FOURCC_DATA 0x61746164L + +#define WAVE_FORMAT_PCM 1 + +typedef struct { + WORD wFormatTag; + WORD nChannels; + DWORD nSamplesPerSec; + DWORD nAvgBytesPerSec; + WORD nBlockAlign; + WORD wBitsPerSample; +} PCMWAVEFORMAT; + +typedef struct { + DWORD fccId; + DWORD dwSize; +} CHUNKHEADER; + +typedef struct { + DWORD fccId; + DWORD dwSize; + DWORD fccType; +} RIFFHEADER; + + +UINT AIAPI ALoadWaveFile(LPSTR lpszFileName, + LPAUDIOWAVE* lplpWave, DWORD dwFileOffset) +{ + static RIFFHEADER Header; + static CHUNKHEADER Chunk; + static PCMWAVEFORMAT Fmt; + LPAUDIOWAVE lpWave; + UINT n, nErrorCode; + + if (lplpWave == NULL) { + return AUDIO_ERROR_INVALPARAM; + } + *lplpWave = NULL; + + if (AIOOpenFile(lpszFileName)) { + return AUDIO_ERROR_FILENOTFOUND; + } + AIOSeekFile(dwFileOffset, SEEK_SET); + + if ((lpWave = (LPAUDIOWAVE) calloc(1, sizeof(AUDIOWAVE))) == NULL) { + AIOCloseFile(); + return AUDIO_ERROR_NOMEMORY; + } + + /* read RIFF/WAVE header structure */ + AIOReadLong(&Header.fccId); + AIOReadLong(&Header.dwSize); + AIOReadLong(&Header.fccType); + Header.dwSize += (Header.dwSize & 1); + if (Header.fccId != FOURCC_RIFF || Header.fccType != FOURCC_WAVE) { + AIOCloseFile(); + AFreeWaveFile(lpWave); + return AUDIO_ERROR_BADFILEFORMAT; + } + + memset(&Fmt, 0, sizeof(Fmt)); + Header.dwSize -= sizeof(Header.fccType); + while (Header.dwSize != 0) { + /* read RIFF chunk header structure */ + AIOReadLong(&Chunk.fccId); + AIOReadLong(&Chunk.dwSize); + Chunk.dwSize += (Chunk.dwSize & 1); + Header.dwSize -= sizeof(Chunk) + Chunk.dwSize; + if (Chunk.fccId == FOURCC_FMT) { + /* read RIFF/WAVE format chunk */ + AIOReadShort(&Fmt.wFormatTag); + AIOReadShort(&Fmt.nChannels); + AIOReadLong(&Fmt.nSamplesPerSec); + AIOReadLong(&Fmt.nAvgBytesPerSec); + AIOReadShort(&Fmt.nBlockAlign); + AIOReadShort(&Fmt.wBitsPerSample); + AIOSeekFile(Chunk.dwSize - sizeof(Fmt), SEEK_CUR); + } + else if (Chunk.fccId == FOURCC_DATA) { + /* read RIFF/WAVE data chunk */ + if (Fmt.wFormatTag != WAVE_FORMAT_PCM) { + AIOCloseFile(); + AFreeWaveFile(lpWave); + return AUDIO_ERROR_BADFILEFORMAT; + } + lpWave->dwLength = Chunk.dwSize; + lpWave->nSampleRate = (WORD) Fmt.nSamplesPerSec; + lpWave->wFormat = AUDIO_FORMAT_8BITS | AUDIO_FORMAT_MONO; + if (Fmt.wBitsPerSample != 8) + lpWave->wFormat |= AUDIO_FORMAT_16BITS; + if (Fmt.nChannels != 1) + lpWave->wFormat |= AUDIO_FORMAT_STEREO; + if ((nErrorCode = ACreateAudioData(lpWave)) != AUDIO_ERROR_NONE) { + AIOCloseFile(); + AFreeWaveFile(lpWave); + return nErrorCode; + } + AIOReadFile(lpWave->lpData, lpWave->dwLength); + if (!(lpWave->wFormat & AUDIO_FORMAT_16BITS)) { + for (n = 0; n < lpWave->dwLength; n++) + lpWave->lpData[n] ^= 0x80; + } + AWriteAudioData(lpWave, 0, lpWave->dwLength); + AIOCloseFile(); + *lplpWave = lpWave; + return AUDIO_ERROR_NONE; + } + else { + /* skip unknown RIFF/WAVE chunks */ + AIOSeekFile(Chunk.dwSize, SEEK_CUR); + } + } + + AIOCloseFile(); + return AUDIO_ERROR_BADFILEFORMAT; +} + + +UINT AIAPI AFreeWaveFile(LPAUDIOWAVE lpWave) +{ + UINT rc; + rc = ADestroyAudioData(lpWave); /*** FIX: 04/12/98 ***/ + free(lpWave); + return rc; +} diff --git a/seal-hack/src/windrv.c b/seal-hack/src/windrv.c new file mode 100644 index 0000000..2259b00 --- /dev/null +++ b/seal-hack/src/windrv.c @@ -0,0 +1,208 @@ +/* + * $Id: windrv.c 1.10 1997/01/05 16:22:59 chasan Exp $ + * + * Windows Wave audio driver. + * + * Copyright (c) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include "audio.h" +#include "drivers.h" + +/* + * Windows waveform block defines + */ +#define BUFFERSIZE 50 /* buffer size in milliseconds */ +#define BUFFRAGSIZE 16 /* buffer fragment size in bytes */ +#define NUMBLOCKS 3 /* total number of buffers [1998/12/24] */ + +/* + * Windows Wave output configuration structure + */ +static struct { + HWAVEOUT nHandle; + HGLOBAL aBlockHandle[NUMBLOCKS]; + WAVEHDR aWaveHeader[NUMBLOCKS]; + UINT nBlockIndex; + LPFNAUDIOWAVE lpfnAudioWave; +} WaveOut; + + +/* + * Windows Wave driver API routines + */ +static UINT AIAPI GetAudioCaps(LPAUDIOCAPS lpCaps) +{ + WAVEOUTCAPS Caps; + + if (waveOutGetDevCaps(WAVE_MAPPER, &Caps, sizeof(WAVEOUTCAPS)) != 0) { + strncpy(Caps.szPname, "Windows Wave", sizeof(Caps.szPname)); + Caps.dwFormats = 0x00000000L; + } + strncpy(lpCaps->szProductName, Caps.szPname, sizeof(lpCaps->szProductName)); + lpCaps->wProductId = AUDIO_PRODUCT_WINDOWS; + lpCaps->dwFormats = Caps.dwFormats; + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI PingAudio(VOID) +{ + return waveOutGetNumDevs() ? AUDIO_ERROR_NONE : AUDIO_ERROR_NODEVICE; +} + +static UINT AIAPI OpenAudio(LPAUDIOINFO lpInfo) +{ + WAVEOUTCAPS caps; + PCMWAVEFORMAT format; + LONG nBufferSize; + UINT n; + + memset(&WaveOut, 0, sizeof(WaveOut)); + + /* get wave output device capabilities */ + if (waveOutGetDevCaps(WAVE_MAPPER, &caps, sizeof(WAVEOUTCAPS)) != 0) { + if (!(caps.dwFormats & (WAVE_FORMAT_1S08 | WAVE_FORMAT_1S16 | + WAVE_FORMAT_2S08 | WAVE_FORMAT_2S16 | + WAVE_FORMAT_4S08 | WAVE_FORMAT_4S16))) + lpInfo->wFormat &= ~AUDIO_FORMAT_STEREO; + if (!(caps.dwFormats & (WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16 | + WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 | + WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16))) + lpInfo->wFormat &= ~AUDIO_FORMAT_16BITS; + if (!(caps.dwFormats & (WAVE_FORMAT_4M08 | WAVE_FORMAT_4M16 | + WAVE_FORMAT_4S08 | WAVE_FORMAT_4S16))) + if (lpInfo->nSampleRate > 22050) + lpInfo->nSampleRate = 22050; + } + + /* setup PCM wave format structure */ + format.wf.wFormatTag = WAVE_FORMAT_PCM; + format.wf.nChannels = lpInfo->wFormat & AUDIO_FORMAT_STEREO ? 2 : 1; + format.wBitsPerSample = lpInfo->wFormat & AUDIO_FORMAT_16BITS ? 16 : 8; + format.wf.nSamplesPerSec = lpInfo->nSampleRate; + format.wf.nAvgBytesPerSec = lpInfo->nSampleRate; + format.wf.nBlockAlign = sizeof(char); + + if (lpInfo->wFormat & AUDIO_FORMAT_STEREO) { + format.wf.nAvgBytesPerSec <<= 1; + format.wf.nBlockAlign <<= 1; + } + if (lpInfo->wFormat & AUDIO_FORMAT_16BITS) { + format.wf.nAvgBytesPerSec <<= 1; + format.wf.nBlockAlign <<= 1; + } + + /* open wave output device using the PCM format structure */ + if (waveOutOpen(&WaveOut.nHandle, WAVE_MAPPER, + (LPWAVEFORMATEX) &format, 0, 0, 0) != 0) { + return AUDIO_ERROR_NODEVICE; + } + + /* compute wave output block buffer size in bytes */ + nBufferSize = lpInfo->nSampleRate / (1000 / BUFFERSIZE); + if (lpInfo->wFormat & AUDIO_FORMAT_16BITS) + nBufferSize <<= 1; + if (lpInfo->wFormat & AUDIO_FORMAT_STEREO) + nBufferSize <<= 1; + nBufferSize = (nBufferSize + BUFFRAGSIZE - 1) & -BUFFRAGSIZE; + + /* allocate and lock memory for wave output block buffers */ + for (n = 0; n < NUMBLOCKS; n++) { + WaveOut.aBlockHandle[n] = + GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, nBufferSize); + WaveOut.aWaveHeader[n].lpData = + GlobalLock(WaveOut.aBlockHandle[n]); + WaveOut.aWaveHeader[n].dwBufferLength = nBufferSize; + WaveOut.aWaveHeader[n].dwFlags = WHDR_DONE; + WaveOut.aWaveHeader[n].dwLoops = 0; + WaveOut.aWaveHeader[n].dwUser = 0; + } + + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI CloseAudio(VOID) +{ + UINT n, nErrorCode; + + /* reset wave output device and stop all playing blocks */ + waveOutReset(WaveOut.nHandle); + + /* make sure all wave output block buffers are done */ + nErrorCode = AUDIO_ERROR_NONE; + for (n = 0; n < NUMBLOCKS; n++) { + if (!(WaveOut.aWaveHeader[n].dwFlags & WHDR_DONE)) + nErrorCode = AUDIO_ERROR_DEVICEBUSY; + } + + /* unprepare, unlock and free wave output block buffers */ + for (n = 0; n < NUMBLOCKS; n++) { + if (WaveOut.aWaveHeader[n].dwUser != 0) { + waveOutUnprepareHeader(WaveOut.nHandle, + &WaveOut.aWaveHeader[n], sizeof(WAVEHDR)); + } + GlobalUnlock(WaveOut.aBlockHandle[n]); + GlobalFree(WaveOut.aBlockHandle[n]); + } + + /* close wave output device */ + waveOutClose(WaveOut.nHandle); + + return nErrorCode; +} + +static UINT AIAPI UpdateAudio(UINT nFrames) +{ + LPWAVEHDR lpWaveHeader; + + lpWaveHeader = &WaveOut.aWaveHeader[WaveOut.nBlockIndex]; + if ((lpWaveHeader->dwFlags & WHDR_DONE) && WaveOut.lpfnAudioWave) { + if (lpWaveHeader->dwUser != 0) { + waveOutUnprepareHeader(WaveOut.nHandle, + lpWaveHeader, sizeof(WAVEHDR)); + lpWaveHeader->dwUser = 0; + } + if (lpWaveHeader->lpData != NULL) { + lpWaveHeader->dwFlags = 0; + lpWaveHeader->dwUser = 1; + WaveOut.lpfnAudioWave((PUCHAR) lpWaveHeader->lpData, + lpWaveHeader->dwBufferLength); + waveOutPrepareHeader(WaveOut.nHandle, + lpWaveHeader, sizeof(WAVEHDR)); + waveOutWrite(WaveOut.nHandle, + lpWaveHeader, sizeof(WAVEHDR)); + } + if (++WaveOut.nBlockIndex >= NUMBLOCKS) + WaveOut.nBlockIndex = 0; + } + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI SetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + WaveOut.lpfnAudioWave = lpfnAudioWave; + return AUDIO_ERROR_NONE; +} + + +/* + * Windows Wave driver public interface + */ +AUDIOWAVEDRIVER WindowsWaveDriver = +{ + GetAudioCaps, PingAudio, OpenAudio, CloseAudio, + UpdateAudio, SetAudioCallback +}; + +AUDIODRIVER WindowsDriver = +{ + &WindowsWaveDriver, NULL +}; diff --git a/seal-hack/src/wssdrv.c b/seal-hack/src/wssdrv.c new file mode 100644 index 0000000..4297537 --- /dev/null +++ b/seal-hack/src/wssdrv.c @@ -0,0 +1,1214 @@ +/* + * $Id: wssdrv.c 1.8 1996/09/08 00:25:13 chasan released $ + * 1.9 1998/10/13 21:45:40 chasan (ENSONIQ AudioPCI fix) + * + * Analog Devices AD1848 SoundPort Stereo Codec low level driver. + * Windows Sound System, Ultrasound Max and Ensoniq Soundscape audio drivers. + * + * Copyright (C) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include "audio.h" +#include "drivers.h" +#include "msdos.h" + +#define DEBUG(code) + +/*----------------- Analog Devices AD1848 Codec routines -----------------*/ + +/* + * The AD1848 direct control register offsets + */ +#define CODEC_ADDR 0x00 /* index address register */ +#define CODEC_DATA 0x01 /* indexed data register */ +#define CODEC_STAT 0x02 /* status register */ +#define CODEC_PIO 0x03 /* PIO data registers */ + +/* + * The AD1848 indirect register indexes + */ +#define CODEC_LIC 0x00 /* left input control */ +#define CODEC_RIC 0x01 /* right input control */ +#define CODEC_LX1C 0x02 /* left aux #1 input control */ +#define CODEC_RX1C 0x03 /* right aux #1 input control */ +#define CODEC_LX2C 0x04 /* left aux #2 input control */ +#define CODEC_RX2C 0x05 /* right aux #2 input control */ +#define CODEC_LDC 0x06 /* left output control */ +#define CODEC_RDC 0x07 /* right output control */ +#define CODEC_CDF 0x08 /* clock and data format */ +#define CODEC_INTF 0x09 /* interface configuration */ +#define CODEC_PIN 0x0A /* PIN control */ +#define CODEC_TEST 0x0B /* test and initialization */ +#define CODEC_MISC 0x0C /* miscellaneous information */ +#define CODEC_DIGMIX 0x0D /* digital mix */ +#define CODEC_UPR_COUNT 0x0E /* upper base count */ +#define CODEC_LWR_COUNT 0x0F /* lower base count */ + +/* + * Index register bit fields (CODEC_ADDR) + */ +#define CODEC_ADDR_TRD 0x20 /* transfer request disable */ +#define CODEC_ADDR_MCE 0x40 /* mode change enable */ +#define CODEC_ADDR_INIT 0x80 /* AD1848 initialization */ + +/* + * Status register bit fields (CODEC_STAT) + */ +#define CODEC_STAT_INT 0x01 /* interrupt status */ +#define CODEC_STAT_PRDY 0x02 /* playback data register ready */ +#define CODEC_STAT_PLR 0x04 /* playback left/right sample */ +#define CODEC_STAT_PUL 0x08 /* playback upper/lower byte */ +#define CODEC_STAT_SOUR 0x10 /* sample over/underrun */ +#define CODEC_STAT_CRDY 0x20 /* capture data register ready */ +#define CODEC_STAT_CLR 0x40 /* capture left/right sample */ +#define CODEC_STAT_CUL 0x80 /* capture upper/lower byte */ + +/* + * Left input control register (CODEC_LIC) + */ +#define CODEC_LIG 0x0F /* left input gain select mask */ +#define CODEC_LMGE 0x20 /* left input microphone gain enable */ +#define CODEC_LSS 0xC0 /* left source select mask */ +#define CODEC_LSS_LINE 0x00 /* left line source selected */ +#define CODEC_LSS_AUX1 0x40 /* left aux #1 source selected */ +#define CODEC_LSS_MIC 0x80 /* left microphone source selected */ +#define CODEC_LSS_DAC 0xC0 /* left line post-mixed DAC source */ + +/* + * Right input control register (CODEC_RIC) + */ +#define CODEC_RIG 0x0F /* right input gain select */ +#define CODEC_RMGE 0x20 /* right microphone gain enable */ +#define CODEC_RSS 0xC0 /* right source select mask */ +#define CODEC_RSS_LINE 0x00 /* right line source selected */ +#define CODEC_RSS_AUX1 0x40 /* right aux #1 source selected */ +#define CODEC_RSS_MIC 0x80 /* right microphone source selected */ +#define CODEC_RSS_DAC 0xC0 /* right line post-mixed DAC source */ + +/* + * Left auxiliary #1 input control register (CODEC_LX1C) + */ +#define CODEC_LX1A 0x1F /* left aux #1 attenuate select */ +#define CODEC_LMX1 0x80 /* left aux #1 mute */ + +/* + * Right auxiliary #1 input control register (CODEC_RX1C) + */ +#define CODEC_RX1A 0x1F /* right aux #1 attenuate select */ +#define CODEC_RMX1 0x80 /* right aux #1 mute */ + +/* + * Left auxiliary #2 input control register (CODEC_LX2C) + */ +#define CODEC_LX2A 0x1F /* left aux #2 attenuate select */ +#define CODEC_LMX2 0x80 /* left aux #2 mute */ + +/* + * Right auxiliary #2 input control register (CODEC_RX2C) + */ +#define CODEC_RX2A 0x1F /* right aux #2 attenuate select */ +#define CODEC_RMX2 0x80 /* right aux #2 mute */ + +/* + * Left DAC control register (CODEC_LDC) + */ +#define CODEC_LDA 0x3F /* left DAC attenuate select */ +#define CODEC_LDM 0x80 /* left DAC mute */ + +/* + * Right DAC control register (CODEC_RDC) + */ +#define CODEC_RDA 0x3F /* right DAC attenuate select */ +#define CODEC_RDM 0x80 /* right DAC mute */ + +/* + * Clock and data format register (CODEC_CDF) + */ +#define CODEC_CSS 0x01 /* clock source select */ +#define CODEC_CFS 0x0E /* clock frequency divide select */ +#define CODEC_SM 0x10 /* stereo/mono select */ +#define CODEC_LC 0x20 /* linear/companded select */ +#define CODEC_FMT 0x40 /* format select */ +#define CODEC_CSS_XTAL1 0x00 /* XTAL1 24.576 MHz */ +#define CODEC_CSS_XTAL2 0x01 /* XTAL2 16.9344 MHz */ +#define CODEC_LC_FMT_8BIT 0x00 /* 8-bit unsigned PCM linear */ +#define CODEC_LC_FMT_16BIT 0x40 /* 16-bit signed PCM linear */ +#define CODEC_LC_FMT_ULAW 0x20 /* 8-bit u-law companded */ +#define CODEC_LC_FMT_ALAW 0x60 /* 8-bit A-law companded */ + +/* + * Interface configuration register (CODEC_INTF) + */ +#define CODEC_PEN 0x01 /* playback enable */ +#define CODEC_CEN 0x02 /* capture enable */ +#define CODEC_SDC 0x04 /* single DMA channel */ +#define CODEC_ACAL 0x08 /* autocalibration enable */ +#define CODEC_PPIO 0x40 /* playback PIO enable */ +#define CODEC_CPIO 0x80 /* capture PIO enable */ + +/* + * Pin control register (CODEC_PIN) + */ +#define CODEC_IEN 0x02 /* interrupt enable */ +#define CODEC_XCTL0 0x40 /* external control #1 */ +#define CODEC_XCTL1 0x80 /* external control #2 */ + +/* + * Test and initialization register (CODEC_TEST) + */ +#define CODEC_ORL 0x03 /* overrange left detect */ +#define CODEC_ORR 0x0C /* overrange right detect */ +#define CODEC_DRS 0x10 /* data request status */ +#define CODEC_ACI 0x20 /* autocalibrate in progress */ +#define CODEC_PUR 0x40 /* playback underrun */ +#define CODEC_COR 0x80 /* capture overrun */ + +/* + * Miscellaneous control register (CODEC_MISC) + */ +#define CODEC_REVID 0x0F /* AD1848 revision ID code */ + +/* + * Digital mix control register (CODEC_DIGMIX) + */ +#define CODEC_DME 0x01 /* digital mix enable */ +#define CODEC_DMA 0xFC /* digital mix attenuation mask */ + +/* + * Timeout for autocalibrate and DMA buffer length defines + */ +#define TIMEOUT 100000 /* delay for sync and autocalib. */ +#define BUFFERSIZE 50 /* buffer length in milliseconds */ +#define BUFFRAGSIZE 32 /* buffer fragment size in bytes */ + + +/* + * AD1848 supported sampling frequencies table + */ +static WORD aFreqFmtTable[] = +{ + 5512, (0 << 1) | 0x01, /* CFS=0 XTAL2 */ + 6615, (7 << 1) | 0x01, /* CFS=7 XTAL2 */ + 8000, (0 << 1) | 0x00, /* CFS=0 XTAL1 */ + 9600, (7 << 1) | 0x00, /* CFS=7 XTAL1 */ + 11025, (1 << 1) | 0x01, /* CFS=1 XTAL2 */ + 16000, (1 << 1) | 0x00, /* CFS=1 XTAL1 */ + 18900, (2 << 1) | 0x01, /* CFS=2 XTAL2 */ + 22050, (3 << 1) | 0x01, /* CFS=3 XTAL2 */ + 27428, (2 << 1) | 0x00, /* CFS=2 XTAL1 */ + 32000, (3 << 1) | 0x00, /* CFS=3 XTAL1 */ + 33075, (6 << 1) | 0x01, /* CFS=6 XTAL2 */ + 37800, (4 << 1) | 0x01, /* CFS=4 XTAL2 */ + 44100, (5 << 1) | 0x01, /* CFS=5 XTAL2 */ + 48000, (6 << 1) | 0x00 /* CFS=6 XTAL1 */ +}; + + +/* + * AD1848 configuration structure + */ +static struct { + WORD wId; /* audio device identifier */ + WORD wFormat; /* encoding data format */ + WORD nSampleRate; /* sampling frequency */ + WORD wBasePort; /* audio device base port */ + WORD wPort; /* codec base port */ + BYTE nIrqLine; /* IRQ interrupt line */ + BYTE nDmaChannel; /* playback DMA channel */ + BYTE nAdcDmaChannel; /* capture DMA channel */ + BYTE nClockFormat; /* clock and data format */ + LPBYTE lpBuffer; /* DMA buffer address */ + UINT nBufferSize; /* DMA buffer length */ + UINT nPosition; /* playing DMA position */ + LPFNAUDIOWAVE lpfnAudioWave; /* user callback function */ +} Codec; + + +static VOID ADPortB(BYTE nIndex, BYTE bData) +{ + OUTB(Codec.wPort + CODEC_ADDR, nIndex); + OUTB(Codec.wPort + CODEC_DATA, bData); +} + +static BYTE ADPortRB(BYTE nIndex) +{ + OUTB(Codec.wPort + CODEC_ADDR, nIndex); + return INB(Codec.wPort + CODEC_DATA); +} + +static BOOL ADWaitSync(VOID) +{ + UINT n; + + /* wait until resynchronization finishes */ + for (n = 0; n < TIMEOUT; n++) { + if (!(INB(Codec.wPort + CODEC_ADDR) & CODEC_ADDR_INIT)) + break; + } + return (n >= TIMEOUT); +} + +static BOOL ADWaitACI(VOID) +{ + UINT n; + + /* wait until autocalibration finishes */ + for (n = 0; n < TIMEOUT; n++) { + if (ADPortRB(CODEC_TEST) & CODEC_ACI) + break; + } + if (n < TIMEOUT) { + for (n = 0; n < TIMEOUT; n++) { + if (!(ADPortRB(CODEC_TEST) & CODEC_ACI)) + break; + } + } + return (n >= TIMEOUT); +} + +static UINT ADProbe(VOID) +{ + BYTE nVersion /**, nLIC, nRIC**/; + + DEBUG(printf("ADProbe: clear interrupts and wait sync\n")); + + /* + * Clear pending interrupts and wait until synchronization ends + */ + INB(Codec.wPort + CODEC_STAT); + OUTB(Codec.wPort + CODEC_STAT, 0x00); + if (ADWaitSync()) + return AUDIO_ERROR_NODEVICE; + + DEBUG(printf("ADProbe: check AD1848 read-only revision code\n")); + + /* + * Check out AD1848's read-only revision ID code + */ + nVersion = ADPortRB(CODEC_MISC); + ADPortB(CODEC_MISC, nVersion ^ CODEC_REVID); + if (ADPortRB(CODEC_MISC) != nVersion) + return AUDIO_ERROR_NODEVICE; + + /**[1998/10/12]***************************************** + * This check does not work with ENSONIQ AudioPCI cards + * in Legacy emulation mode. Thanks to Bomb! + *******************************************************/ +#if 0 + /* + * Check out if the left and right input control + * registers are there. + */ + nLIC = ADPortRB(CODEC_LIC); + nRIC = ADPortRB(CODEC_RIC); + ADPortB(CODEC_LIC, nLIC ^ CODEC_LIG); + ADPortB(CODEC_RIC, nRIC ^ CODEC_RIG); + if (ADPortRB(CODEC_LIC) != (nLIC ^ CODEC_LIG) || + ADPortRB(CODEC_RIC) != (nRIC ^ CODEC_RIG)) { + ADPortB(CODEC_LIC, nLIC); + ADPortB(CODEC_RIC, nRIC); + return AUDIO_ERROR_NODEVICE; + } + ADPortB(CODEC_LIC, nLIC); + ADPortB(CODEC_RIC, nRIC); +#endif + + DEBUG(printf("ADProbe: set interface configuration\n")); + + /* + * Set interface configuration register (enable autocalibration + * and DMA transfers for playback and capture, and use single + * DMA channel if required) + */ + ADPortB(CODEC_ADDR_MCE | CODEC_INTF, CODEC_ACAL | + (Codec.nDmaChannel != Codec.nAdcDmaChannel ? 0x00 : CODEC_SDC)); + ADPortB(CODEC_INTF, CODEC_ACAL | CODEC_SDC); + + DEBUG(printf("ADProbe: wait autocalibration\n")); + + /**[1998/10/12]***************************************** + * This check timeouts with ENSONIQ AudioPCI cards, but + * should not be removed for actual AD1848 codecs. + */ +#if 0 + if (ADWaitACI()) + return AUDIO_ERROR_NODEVICE; +#else + ADWaitACI(); +#endif + + return AUDIO_ERROR_NONE; +} + +static VOID AIAPI ADInterruptHandler(VOID) +{ + /* Acknowledge AD1848's interrupt signals */ + if (INB(Codec.wPort + CODEC_STAT) & CODEC_STAT_INT) + OUTB(Codec.wPort + CODEC_STAT, 0x00); +} + +static VOID ADSetClockFormat(VOID) +{ + UINT n; + + /* + * Determine playback format bit fields and select + * clock source and frequency divisor values. + */ + for (n = 0; n < sizeof(aFreqFmtTable) / sizeof(WORD) - 2; n += 2) { + if (Codec.nSampleRate <= aFreqFmtTable[n]) + break; + } + Codec.nSampleRate = aFreqFmtTable[n]; + Codec.nClockFormat = aFreqFmtTable[n + 1]; + if (Codec.wFormat & AUDIO_FORMAT_16BITS) { + Codec.nClockFormat |= CODEC_FMT; + } + if (Codec.wFormat & AUDIO_FORMAT_STEREO) { + Codec.nClockFormat |= CODEC_SM; + } + + DEBUG(printf("ADSetClockFormat: change clock and data format\n")); + + /* + * Set AD1848 clock and data format register and waits + * until the internal resynchronization and autocalibration + * progress finishes. + */ + ADPortB(CODEC_ADDR_MCE | CODEC_CDF, Codec.nClockFormat); + ADWaitSync(); + ADPortB(CODEC_CDF, Codec.nClockFormat); + ADWaitACI(); +} + +static VOID ADStartPlayback(VOID) +{ + WORD nCount; + + DEBUG(printf("ADStartPlayback: setup DMA channel\n")); + + /* + * First setup the DMA controller parameters for + * autoinit playback transfers. + */ + DosSetupChannel(Codec.nDmaChannel, DMA_WRITE | DMA_AUTOINIT, 0); + + /* + * Setup base count register, enable playback + * and set DAC output control registers. + */ + nCount = Codec.nBufferSize; + if (Codec.wFormat & AUDIO_FORMAT_16BITS) + nCount >>= 1; + if (Codec.wFormat & AUDIO_FORMAT_STEREO) + nCount >>= 1; + nCount--; + + DEBUG(printf("ADStartPlayback: set frames and enable playback\n")); + + /* set sample frames per interrupt and enable playback */ + ADPortB(CODEC_LWR_COUNT, LOBYTE(nCount - 1)); + ADPortB(CODEC_UPR_COUNT, HIBYTE(nCount - 1)); + ADPortB(CODEC_INTF, ADPortRB(CODEC_INTF) | CODEC_PEN); + + DEBUG(printf("ADStartPlayback: unmute left and right DAC\n")); + + ADPortB(CODEC_LDC, ADPortRB(CODEC_LDC) & ~CODEC_LDM); + ADPortB(CODEC_RDC, ADPortRB(CODEC_RDC) & ~CODEC_RDM); +} + +static VOID ADStopPlayback(VOID) +{ + DEBUG(printf("ADStopPlayback: disable playback\n")); + + /* + * Disable playback using the interface configuration + * register and then disable the DMA controller channel. + */ + ADPortB(CODEC_INTF, ADPortRB(CODEC_INTF) & ~CODEC_PEN); + + DEBUG(printf("ADStopPlayback: disable DMA channel\n")); + + DosDisableChannel(Codec.nDmaChannel); +} + + +static UINT ADOpenAudio(LPAUDIOINFO lpInfo) +{ + DWORD dwBytesPerSecond; + + DEBUG(printf("ADOpenAudio: probe AD1848 codec\n")); + + /* + * Check if we actually have an AD1848 audio codec device + */ + if (ADProbe()) + return AUDIO_ERROR_NODEVICE; + + DEBUG(printf("ADOpenAudio: allocate DMA buffer area\n")); + + /* + * Allocate and clean DMA channel buffer for playback + */ + dwBytesPerSecond = Codec.nSampleRate; + if (Codec.wFormat & AUDIO_FORMAT_16BITS) + dwBytesPerSecond <<= 1; + if (Codec.wFormat & AUDIO_FORMAT_STEREO) + dwBytesPerSecond <<= 1; + Codec.nBufferSize = dwBytesPerSecond / (1000 / BUFFERSIZE); + Codec.nBufferSize = (Codec.nBufferSize + BUFFRAGSIZE) & -BUFFRAGSIZE; + if (DosAllocChannel(Codec.nDmaChannel, Codec.nBufferSize)) + return AUDIO_ERROR_NOMEMORY; + if ((Codec.lpBuffer = DosLockChannel(Codec.nDmaChannel)) != NULL) { + memset(Codec.lpBuffer, Codec.wFormat & AUDIO_FORMAT_16BITS ? + 0x00 : 0x80, Codec.nBufferSize); + DosUnlockChannel(Codec.nDmaChannel); + } + + DEBUG(printf("ADOpenAudio: install interrupt handler\n")); + + /* + * Install AD1848 interrupt handler and enable interrupts + */ + DosSetVectorHandler(Codec.nIrqLine, ADInterruptHandler); + + DEBUG(printf("ADOpenAudio: enable interrupts\n")); + + ADPortB(CODEC_PIN, CODEC_IEN); + + DEBUG(printf("ADOpenAudio: set frequency and start playback\n")); + + /* + * Set frequency and encoding format, and enable playback + */ + ADSetClockFormat(); + ADStartPlayback(); + + DEBUG(printf("ADOpenAudio: done\n\n")); + + lpInfo->wFormat = Codec.wFormat; + lpInfo->nSampleRate = Codec.nSampleRate; + return AUDIO_ERROR_NONE; +} + +static UINT ADCloseAudio(VOID) +{ + DEBUG(printf("ADCloseAudio: stop playback and DMA channel\n")); + + /* + * Stop DMA playback transfer and releases the DMA channel buffer + */ + ADStopPlayback(); + DosFreeChannel(Codec.nDmaChannel); + + DEBUG(printf("ADCloseAudio: restore interrupt handler\n")); + + /* + * Restore the interrupt handler and disable/clear pending interrupts + */ + DosSetVectorHandler(Codec.nIrqLine, NULL); + + DEBUG(printf("ADCloseAudio: disable and clear interrupts\n")); + + INB(Codec.wPort + CODEC_STAT); + OUTB(Codec.wPort + CODEC_STAT, 0x00); + ADPortB(CODEC_PIN, 0x00); + + DEBUG(printf("ADCloseAudio: done\n\n")); + + return AUDIO_ERROR_NONE; +} + +static UINT ADUpdateAudio(UINT nFrames) +{ + int nBlockSize, nSize; + + if (Codec.wFormat & AUDIO_FORMAT_16BITS) nFrames <<= 1; + if (Codec.wFormat & AUDIO_FORMAT_STEREO) nFrames <<= 1; + if (nFrames <= 0 || nFrames > Codec.nBufferSize) + nFrames = Codec.nBufferSize; + + if ((Codec.lpBuffer = DosLockChannel(Codec.nDmaChannel)) != NULL) { + nBlockSize = Codec.nBufferSize - Codec.nPosition - + DosGetChannelCount(Codec.nDmaChannel); + if (nBlockSize < 0) + nBlockSize += Codec.nBufferSize; + + if (nBlockSize > nFrames) + nBlockSize = nFrames; + + nBlockSize &= -BUFFRAGSIZE; + while (nBlockSize != 0) { + nSize = Codec.nBufferSize - Codec.nPosition; + if (nSize > nBlockSize) + nSize = nBlockSize; + if (Codec.lpfnAudioWave != NULL) { + Codec.lpfnAudioWave(&Codec.lpBuffer[Codec.nPosition], nSize); + } + else { + memset(&Codec.lpBuffer[Codec.nPosition], + Codec.wFormat & AUDIO_FORMAT_16BITS ? + 0x00 : 0x80, nSize); + } + if ((Codec.nPosition += nSize) >= Codec.nBufferSize) + Codec.nPosition -= Codec.nBufferSize; + nBlockSize -= nSize; + } + DosUnlockChannel(Codec.nDmaChannel); + } + return AUDIO_ERROR_NONE; +} + +static UINT ADSetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + Codec.lpfnAudioWave = lpfnAudioWave; + return AUDIO_ERROR_NONE; +} + +/*--------------------- Windows Sound System driver ---------------------*/ + +/* + * Windows Sound System (AD1848) direct register offsets + */ +#define WSS_CODEC_INTF 0x000 /* interface register */ +#define WSS_CODEC_CHIPID 0x003 /* ID test code register */ +#define WSS_CODEC_BASE 0x004 /* AD1848 codec base register */ + +static UINT AIAPI WSSProbe(VOID) +{ + /* + * Windows Sound System IRQ and DMA interface latches + */ + static BYTE aIrqTable[16] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x10, 0x18, 0x20, 0x00, 0x00, 0x00, 0x00 + }; + static BYTE aDmaTable[8] = + { + 0x01, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00 + }; + +#if 0 + BYTE nChipID; + + /* + * Check out for a WSS card, then probe the AD1848 audio + * codec to make sure the hardware is present. + * Check out if the I/O port returns a valid signature, + * the original WSS card returns 0x04 while some other + * cards (eg. AudioTrix Pro) returns 0x00 or 0x0F. + */ + nChipID = INB(Codec.wBasePort + WSS_CODEC_CHIPID); + if ((nChipID & 0x3F) != 0x04 && (nChipID & 0x3F) != 0x00 && + (nChipID & 0x3F) != 0x0F) + return AUDIO_ERROR_NODEVICE; +#endif + if (!aIrqTable[Codec.nIrqLine] || !aDmaTable[Codec.nDmaChannel]) + return AUDIO_ERROR_NODEVICE; + OUTB(Codec.wBasePort + WSS_CODEC_INTF, + aIrqTable[Codec.nIrqLine] | aDmaTable[Codec.nDmaChannel]); + return ADProbe(); +} + +static UINT AIAPI WSSGetAudioCaps(LPAUDIOCAPS lpCaps) +{ + static AUDIOCAPS Caps = + { + AUDIO_PRODUCT_WSS, "Windows Sound System", + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_1M16 | AUDIO_FORMAT_1S16 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_2M16 | AUDIO_FORMAT_2S16 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 | + AUDIO_FORMAT_4M16 | AUDIO_FORMAT_4S16 + }; + + memcpy(lpCaps, &Caps, sizeof(AUDIOCAPS)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI WSSPingAudio(VOID) +{ + static WORD aPorts[4] = { 0x530, 0xE80, 0xF40, 0x604 }; + static BYTE aIrqs[8] = { 7, 7, 9, 10, 11, 7, 7, 7 }; + static BYTE aDmas[4] = { 1, 0, 1, 3 }; + WORD wIntf; + UINT n, nChar; + LPSTR lpszCfg; + + Codec.wId = AUDIO_PRODUCT_WSS; + Codec.wBasePort = 0x530; + Codec.wPort = 0x530 + WSS_CODEC_BASE; + Codec.nIrqLine = 7; + Codec.nDmaChannel = 1; + Codec.nAdcDmaChannel = 1; + if ((lpszCfg = DosGetEnvironment("WSSCFG")) != NULL) { + nChar = DosParseString(lpszCfg, TOKEN_CHAR); + while (nChar != 0) { + switch (nChar) { + case 'A': + case 'a': + Codec.wBasePort = DosParseString(NULL, TOKEN_HEX); + Codec.wPort = Codec.wBasePort + WSS_CODEC_BASE; + break; + case 'I': + case 'i': + Codec.nIrqLine = DosParseString(NULL, TOKEN_DEC); + break; + case 'D': + case 'd': + Codec.nDmaChannel = DosParseString(NULL, TOKEN_DEC); + Codec.nAdcDmaChannel = Codec.nDmaChannel; + break; + } + nChar = DosParseString(NULL, TOKEN_CHAR); + } + return WSSProbe(); + } + else { + for (n = 0; n < sizeof(aPorts) / sizeof(WORD); n++) { + Codec.wBasePort = aPorts[n]; + Codec.wPort = Codec.wBasePort + WSS_CODEC_BASE; + + /**[1998/12/02********************************** + * Experimental code to autodetect the IRQ and + * DMA resource allocated for the WSS card. + */ + wIntf = INB(Codec.wBasePort + WSS_CODEC_INTF); + Codec.nIrqLine = aIrqs[(wIntf >> 3) & 0x07]; + Codec.nDmaChannel = + Codec.nAdcDmaChannel = aDmas[wIntf & 0x03]; + if (!WSSProbe()) + return AUDIO_ERROR_NONE; + } + return AUDIO_ERROR_NODEVICE; + } +} + +static UINT AIAPI WSSOpenAudio(LPAUDIOINFO lpInfo) +{ + /* + * Initialize AD1848 configuration structure + * and setup the IRQ and DMA interface + */ + memset(&Codec, 0, sizeof(Codec)); + Codec.wFormat = lpInfo->wFormat; + Codec.nSampleRate = lpInfo->nSampleRate; + if (WSSPingAudio()) + return AUDIO_ERROR_NODEVICE; + + /* Initialize common AD1848 codec chip audio driver */ + return ADOpenAudio(lpInfo); +} + +static UINT AIAPI WSSCloseAudio(VOID) +{ + /* Shutdown common AD1848 codec chip audio driver */ + ADCloseAudio(); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI WSSUpdateAudio(UINT nFrames) +{ + return ADUpdateAudio(nFrames); +} + +static UINT AIAPI WSSSetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + return ADSetAudioCallback(lpfnAudioWave); +} + +/*--------------------- Gravis Ultrasound Max driver ---------------------*/ + +/* + * Ultrasound Max (CS4231) direct register offsets + */ +#define GUS_BOARD_MIX_CTRL 0x000 /* (2X0) mix control register */ +#define GUS_CODEC_CTRL 0x106 /* (3X6) codec control register */ +#define GUS_CODEC_BASE 0x10C /* (3XC) codec base address */ +#define GUS_BOARD_VERSION 0x506 /* (7X6) board version */ + + +static UINT GUSProbe(VOID) +{ + BYTE nRevId, nIntf; + + /* + * Check whether we have a GUS MAX board reading + * the board revision level register (7X6): + * + * Revision ID Board Revision + * 0xFF Pre 3.7 boards without ICS mixer. + * 0x05 Rev 3.7 with ICS mixer (L/R flip problems). + * 0x06-0x09 Rev 3.7 and above. ICS mixer present. + * 0x0A-0xNN UltraMax boards. CS4231 present, no ICS mixer. + */ + nRevId = INB(Codec.wBasePort + GUS_BOARD_VERSION); + if (Codec.wId == AUDIO_PRODUCT_GUSMAX) { + if (nRevId < 0x0A) + return AUDIO_ERROR_NODEVICE; + + /* Setup the GUS MAX DMA interface */ + nIntf = 0x40 | ((Codec.wPort >> 4) & 0x0F); + if (Codec.nAdcDmaChannel >= 4) + nIntf |= 0x10; + if (Codec.nDmaChannel >= 4) + nIntf |= 0x20; + OUTB(Codec.wBasePort + GUS_CODEC_CTRL, nIntf); + } + else { + if (nRevId >= 0x0A) + return AUDIO_ERROR_NODEVICE; + } + return ADProbe(); +} + +static UINT AIAPI GUSGetAudioCaps(LPAUDIOCAPS lpCaps) +{ + static AUDIOCAPS Caps = + { + AUDIO_PRODUCT_GUSMAX, "Ultrasound Max (CS4231 Codec)", + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_1M16 | AUDIO_FORMAT_1S16 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_2M16 | AUDIO_FORMAT_2S16 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 | + AUDIO_FORMAT_4M16 | AUDIO_FORMAT_4S16 + }; + static AUDIOCAPS CapsDB = + { + AUDIO_PRODUCT_GUSDB, "Ultrasound Daugherboard", + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_1M16 | AUDIO_FORMAT_1S16 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_2M16 | AUDIO_FORMAT_2S16 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 | + AUDIO_FORMAT_4M16 | AUDIO_FORMAT_4S16 + }; + + memcpy(lpCaps, Codec.wId != AUDIO_PRODUCT_GUSDB ? + &Caps : &CapsDB, sizeof(AUDIOCAPS)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI GUSPingAudio(VOID) +{ + LPSTR lpszUltrasnd, lpszUltra16; + UINT wPort, nDramDmaChannel, nAdcDmaChannel, nIrqLine; + UINT wCodecPort, nCodecDmaChannel, nCodecIrqLine, nCodecType; + + if ((lpszUltrasnd = DosGetEnvironment("ULTRASND")) != NULL && + (lpszUltra16 = DosGetEnvironment("ULTRA16")) != NULL) { + if ((wPort = DosParseString(lpszUltrasnd, TOKEN_HEX)) != BAD_TOKEN && + (DosParseString(NULL, TOKEN_CHAR) == ',') && + (nDramDmaChannel = DosParseString(NULL, TOKEN_DEC)) != BAD_TOKEN && + (DosParseString(NULL, TOKEN_CHAR) == ',') && + (nAdcDmaChannel = DosParseString(NULL, TOKEN_DEC)) != BAD_TOKEN && + (DosParseString(NULL, TOKEN_CHAR) == ',') && + (nIrqLine = DosParseString(NULL, TOKEN_DEC)) != BAD_TOKEN && + (DosParseString(NULL, TOKEN_CHAR) == ',') && + (/*nMidiIrqLine =*/ DosParseString(NULL, TOKEN_DEC)) != BAD_TOKEN && + (wCodecPort = DosParseString(lpszUltra16, TOKEN_HEX)) != BAD_TOKEN && + (DosParseString(NULL, TOKEN_CHAR) == ',') && + (nCodecDmaChannel = DosParseString(NULL, TOKEN_DEC)) != BAD_TOKEN && + (DosParseString(NULL, TOKEN_CHAR) == ',') && + (nCodecIrqLine = DosParseString(NULL, TOKEN_DEC)) != BAD_TOKEN && + (DosParseString(NULL, TOKEN_CHAR) == ',') && + (nCodecType = DosParseString(NULL, TOKEN_DEC)) != BAD_TOKEN && + (DosParseString(NULL, TOKEN_CHAR) == ',') && + (/*wCdromPort =*/ DosParseString(NULL, TOKEN_HEX)) != BAD_TOKEN) { + if (nCodecType == 1) { + Codec.wId = AUDIO_PRODUCT_GUSMAX; + Codec.wBasePort = wPort; + Codec.wPort = wCodecPort; + Codec.nIrqLine = nIrqLine; + Codec.nDmaChannel = nAdcDmaChannel; + Codec.nAdcDmaChannel = nDramDmaChannel; + return GUSProbe(); + } + else { + Codec.wId = AUDIO_PRODUCT_GUSDB; + Codec.wBasePort = wPort; + Codec.wPort = wCodecPort; + Codec.nIrqLine = nCodecIrqLine; + Codec.nDmaChannel = nCodecDmaChannel; + Codec.nAdcDmaChannel = nCodecDmaChannel; + return GUSProbe(); + } + } + } + return AUDIO_ERROR_NODEVICE; +} + +static UINT AIAPI GUSOpenAudio(LPAUDIOINFO lpInfo) +{ + /* + * Initialize AD1848 configuration structure + */ + memset(&Codec, 0, sizeof(Codec)); + Codec.wFormat = lpInfo->wFormat; + Codec.nSampleRate = lpInfo->nSampleRate; + if (GUSPingAudio()) + return AUDIO_ERROR_NODEVICE; + + /* + * Enable DAC output and interrupts, disable MIC and + * line input on the GUS MAX mixer control register. + */ + OUTB(Codec.wBasePort + GUS_BOARD_MIX_CTRL, 0x09); + + /* Initialize common AD1848/CS4231 codec chip audio driver */ + return ADOpenAudio(lpInfo); +} + +static UINT AIAPI GUSCloseAudio(VOID) +{ + BYTE nIntf; + + /* Shutdown common AD1848 codec audio driver */ + ADCloseAudio(); + + /* Clean up GUS MAX playback/capture DMA interface latches */ + if (Codec.wId == AUDIO_PRODUCT_GUSMAX) { + nIntf = 0x40 | ((Codec.wPort >> 4) & 0x0F); + if (Codec.nAdcDmaChannel >= 4) + nIntf |= 0x10; + if (Codec.nDmaChannel >= 4) + nIntf |= 0x20; + + OUTB(Codec.wBasePort + GUS_CODEC_CTRL, nIntf & ~0x10); + OUTB(Codec.wBasePort + GUS_CODEC_CTRL, nIntf); + + OUTB(Codec.wBasePort + GUS_CODEC_CTRL, nIntf & ~0x20); + OUTB(Codec.wBasePort + GUS_CODEC_CTRL, nIntf); + } + + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI GUSUpdateAudio(UINT nFrames) +{ + return ADUpdateAudio(nFrames); +} + +static UINT AIAPI GUSSetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + return ADSetAudioCallback(lpfnAudioWave); +} + +/*---------------------- Ensoniq Soundscape driver ----------------------*/ + +/* + * * Ensoniq Soundscape (AD1848) gate-array register offsets + */ +#define ESS_HOST 0x002 /* host control register */ +#define ESS_HOST_DATA 0x003 /* host data register */ +#define ESS_ADDR 0x004 /* index address register */ +#define ESS_DATA 0x005 /* indexed data register */ +#define ESS_CODEC_BASE 0x008 /* AD1848 codec base register */ + +/* + * Ensoniq Soundscape gate-array indirect registers + */ +#define ESS_DMAB 0x03 /* DMA channel B assign */ +#define ESS_INTCFG 0x04 /* interrupt config register */ +#define ESS_DMACFG 0x05 /* DMA config register */ +#define ESS_CDCFG 0x06 /* CDROM/Codec config register */ +#define ESS_HMCTRL 0x09 /* host master control register */ + +/* + * Ensoniq Soundscape gate-array chip ID defines + */ +#define ESS_CHIP_ODIE 0 /* ODIE gate array */ +#define ESS_CHIP_OPUS 1 /* OPUS gate array */ +#define ESS_CHIP_MMIC 2 /* MiMIC gate array */ + +/* + * Ensoniq Soundscape private structure + */ +static struct { + BYTE nChip; + BYTE nProduct; + BYTE nDmaB; + BYTE nIntCfg; + BYTE nDmaCfg; + BYTE nCdCfg; +} ESS; + +static VOID ESSPortB(BYTE nIndex, BYTE bData) +{ + OUTB(Codec.wBasePort + ESS_ADDR, nIndex); + OUTB(Codec.wBasePort + ESS_DATA, bData); +} + +static BYTE ESSPortRB(BYTE nIndex) +{ + OUTB(Codec.wBasePort + ESS_ADDR, nIndex); + return INB(Codec.wBasePort + ESS_DATA); +} + +static UINT AIAPI ESSGetAudioCaps(LPAUDIOCAPS lpCaps) +{ + static AUDIOCAPS Caps = + { + AUDIO_PRODUCT_ESS, "Ensoniq Soundscape", + AUDIO_FORMAT_1M08 | AUDIO_FORMAT_1S08 | + AUDIO_FORMAT_1M16 | AUDIO_FORMAT_1S16 | + AUDIO_FORMAT_2M08 | AUDIO_FORMAT_2S08 | + AUDIO_FORMAT_2M16 | AUDIO_FORMAT_2S16 | + AUDIO_FORMAT_4M08 | AUDIO_FORMAT_4S08 | + AUDIO_FORMAT_4M16 | AUDIO_FORMAT_4S16 + }; + + memcpy(lpCaps, &Caps, sizeof(AUDIOCAPS)); + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI ESSPingAudio(VOID) +{ + static CHAR szFileName[80], szLine[80]; + LPSTR lpszSndscape, lpszName, lpszValue; + UINT nProduct, wPort, wWavePort, nMidiIrqLine, nWaveIrqLine, nDmaChannel; + FILE *fpSndScape; + + DEBUG(printf("ESSPingAudio: read SNDSCAPE.INI hardware profile\n")); + + /* + * Check out if the SNDSCAPE environment variable is present, + * and read the hardware parameters from the SNDSCAPE.INI file. + */ + if ((lpszSndscape = DosGetEnvironment("SNDSCAPE")) == NULL) + return AUDIO_ERROR_NODEVICE; + strcpy(szFileName, lpszSndscape); + if (szFileName[strlen(szFileName) - 1] == '\\') + szFileName[strlen(szFileName) - 1] = 0; + strcat(szFileName, "\\SNDSCAPE.INI"); + if ((fpSndScape = fopen(szFileName, "r")) == NULL) + return AUDIO_ERROR_NODEVICE; + nProduct = 0; + wPort = 0xFFFF; + wWavePort = 0xFFFF; + nMidiIrqLine = 0xFFFF; + nWaveIrqLine = 0xFFFF; + nDmaChannel = 0xFFFF; + while (fgets(szLine, sizeof(szLine) - 1, fpSndScape) != NULL) { + /* + * Parse the next line from the SNDSCAPE.INI file + * which has the following syntax: + * + * Line ::= {Identifier} '=' {String} {Blank}* {EOL} + * + * There should not be blanks between the tokens + * and the identifiers are case-insensitive. + * + * Ref: ENSONIQ Soundscape Digital Audio Driver + * Created 09/08/95 by Andrew P. Weir + */ + strupr(szLine); + lpszName = szLine; + if ((lpszValue = strchr(szLine, '=')) == NULL) + continue; + *lpszValue++ = 0; + + if (!strcmp(lpszName, "PRODUCT")) { + if (strstr(lpszValue, "SOUNDFX") || strstr(lpszValue, "MEDIA_FX")) + nProduct = 1; + } + else if (!strcmp(lpszName, "PORT")) { + wPort = DosParseString(lpszValue, TOKEN_HEX); + } + else if (!strcmp(lpszName, "WAVEPORT")) { + wWavePort = DosParseString(lpszValue, TOKEN_HEX); + } + else if (!strcmp(lpszName, "IRQ")) { + nMidiIrqLine = DosParseString(lpszValue, TOKEN_DEC); + } + else if (!strcmp(lpszName, "SBIRQ")) { + nWaveIrqLine = DosParseString(lpszValue, TOKEN_DEC); + } + else if (!strcmp(lpszName, "DMA")) { + nDmaChannel = DosParseString(lpszValue, TOKEN_DEC); + } + } + fclose(fpSndScape); + if ((wPort|wWavePort|nMidiIrqLine|nWaveIrqLine|nDmaChannel) == 0xFFFF) + return AUDIO_ERROR_NODEVICE; + + DEBUG(printf("ESSPingAudio: Port=0x%03x, WavePort=0x%03x, MidiIrq=%d, WaveIrq=%d, Dma=%d\n", + wPort, wWavePort, nMidiIrqLine, nWaveIrqLine, nDmaChannel)); + + /* + * Initialize the AD1848 codec driver variables + */ + ESS.nProduct = nProduct; + Codec.wId = AUDIO_PRODUCT_ESS; + Codec.wBasePort = wPort; + Codec.wPort = wWavePort; + Codec.nIrqLine = nWaveIrqLine; + Codec.nDmaChannel = nDmaChannel; + Codec.nAdcDmaChannel = nDmaChannel; + + DEBUG(printf("ESSPingAudio: check Ensoniq Soundscape card\n")); + + /* + * Check if there is an Ensoniq Soundscape present + */ + if ((INB(Codec.wBasePort + ESS_HOST) & 0x78) != 0x00) + return AUDIO_ERROR_NODEVICE; + if ((INB(Codec.wBasePort + ESS_ADDR) & 0xF0) == 0xF0) + return AUDIO_ERROR_NODEVICE; + + DEBUG(printf("ESSPingAudio: check Ensoniq GA chip revision\n")); + + /* + * Check Ensoniq Soundscape gate-array chip version + */ + OUTB(Codec.wBasePort + ESS_ADDR, 0xF5); + ESS.nChip = INB(Codec.wBasePort + ESS_ADDR); + if ((ESS.nChip & 0xF0) == 0xF0 || (ESS.nChip & 0x0F) != 0x05) + return AUDIO_ERROR_NODEVICE; + if (ESS.nChip & 0x80) + ESS.nChip = ESS_CHIP_MMIC; + else if (ESS.nChip & 0x70) + ESS.nChip = ESS_CHIP_OPUS; + else + ESS.nChip = ESS_CHIP_ODIE; + + DEBUG(printf("ESSPingAudio: probe AD1848 codec\n")); + + return ADProbe(); +} + +static UINT AIAPI ESSOpenAudio(LPAUDIOINFO lpInfo) +{ + static BYTE aIrqTable[2][16] = + { + { + /* Ensoniq Soundscape IRQ interface latches */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0x02, + 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }, + { + /* SoundFX and MediaFX old Ensoniq IRQ interface latches */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0xFF, 0x01, + 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03 + } + }; + + DEBUG(printf("ESSOpenAudio: initialize ENSONIQ card\n")); + + /* + * Initialize AD1848 configuration structure + */ + memset(&Codec, 0, sizeof(Codec)); + Codec.wFormat = lpInfo->wFormat; + Codec.nSampleRate = lpInfo->nSampleRate; + if (ESSPingAudio()) + return AUDIO_ERROR_NODEVICE; + + /* do some resource rerouting if necessary */ + if (ESS.nChip != ESS_CHIP_MMIC) { + + DEBUG(printf("ESSOpenAudio: setup CODEC DMA polarity\n")); + + /* setup Codec DMA polarity */ + ESSPortB(ESS_DMACFG, 0x50); + + DEBUG(printf("ESSOpenAudio: lock DMA and IRQ resources\n")); + + /* give Codec control of DMA and wave IRQ resources */ + ESS.nCdCfg = ESSPortRB(ESS_CDCFG); + ESSPortB(ESS_CDCFG, 0x89 | (Codec.nDmaChannel << 4) | + (aIrqTable[ESS.nProduct][Codec.nIrqLine] << 1)); + + DEBUG(printf("ESSOpenAudio: pull resources from SB emulation\n")); + + /* pull off the SB emulation off of those resources */ + ESS.nDmaB = ESSPortRB(ESS_DMAB); + ESSPortB(ESS_DMAB, 0x20); + ESS.nIntCfg = ESSPortRB(ESS_INTCFG); + ESSPortB(ESS_INTCFG, 0xF0 | aIrqTable[ESS.nProduct][Codec.nIrqLine] | + (aIrqTable[ESS.nProduct][Codec.nIrqLine] << 2)); + } + + DEBUG(printf("ESSOpenAudio: open AD1848 audio driver\n")); + + return ADOpenAudio(lpInfo); +} + +static UINT AIAPI ESSCloseAudio(VOID) +{ + DEBUG(printf("ESSCloseAudio: shutdown AD1848 audio driver\n")); + + /* shutdown AD1848 codec playback transfers */ + ADCloseAudio(); + + /* if neccesary, restore gate array resource registers */ + if (ESS.nChip != ESS_CHIP_MMIC) { + + DEBUG(printf("ESSCloseAudio: restore Ensoniq GA resources\n")); + + ESSPortB(ESS_INTCFG, ESS.nIntCfg); + ESSPortB(ESS_DMAB, ESS.nDmaB); + ESSPortB(ESS_CDCFG, ESS.nCdCfg); + } + return AUDIO_ERROR_NONE; +} + +static UINT AIAPI ESSUpdateAudio(UINT nFrames) +{ + return ADUpdateAudio(nFrames); +} + +static UINT AIAPI ESSSetAudioCallback(LPFNAUDIOWAVE lpfnAudioWave) +{ + return ADSetAudioCallback(lpfnAudioWave); +} + + +/* + * Windows Sound System, Ultrasound Max & Ensoniq Soundscape public interfaces + */ +AUDIOWAVEDRIVER WinSndSystemWaveDriver = +{ + WSSGetAudioCaps, WSSPingAudio, + WSSOpenAudio, WSSCloseAudio, + WSSUpdateAudio, WSSSetAudioCallback +}; + +AUDIOWAVEDRIVER UltraSoundMaxWaveDriver = +{ + GUSGetAudioCaps, GUSPingAudio, + GUSOpenAudio, GUSCloseAudio, + GUSUpdateAudio, GUSSetAudioCallback +}; + +AUDIOWAVEDRIVER SoundscapeWaveDriver = +{ + ESSGetAudioCaps, ESSPingAudio, + ESSOpenAudio, ESSCloseAudio, + ESSUpdateAudio, ESSSetAudioCallback +}; + +AUDIODRIVER WinSndSystemDriver = +{ + &WinSndSystemWaveDriver, NULL +}; + +AUDIODRIVER UltraSoundMaxDriver = +{ + &UltraSoundMaxWaveDriver, NULL +}; + +AUDIODRIVER SoundscapeDriver = +{ + &SoundscapeWaveDriver, NULL +}; diff --git a/seal-hack/src/xmfile.c b/seal-hack/src/xmfile.c new file mode 100644 index 0000000..b25a0ee --- /dev/null +++ b/seal-hack/src/xmfile.c @@ -0,0 +1,407 @@ +/* + * $Id: xmfile.c 1.6 1996/12/12 16:28:54 chasan Exp $ + * + * Extended module file loader routines. + * + * Copyright (c) 1995-1999 Carlos Hasan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +//#include +#include +#include +#include "audio.h" +#include "iofile.h" + + +/* + * Extended module file structures + */ +#define XM_FILE_HEADER_SIZE 276 +#define XM_PATTERN_HEADER_SIZE 9 +#define XM_PATCH_HEADER_SIZE 29 +#define XM_PATCH_BODY_SIZE 214 +#define XM_SAMPLE_HEADER_SIZE 40 +#define XM_MODULE_LINEAR 0x0001 +#define XM_ENVELOPE_ON 0x0001 +#define XM_ENVELOPE_SUSTAIN 0x0002 +#define XM_ENVELOPE_LOOP 0x0004 +#define XM_SAMPLE_LOOP 0x0001 +#define XM_SAMPLE_PINGPONG 0x0002 +#define XM_SAMPLE_16BITS 0x0010 + +typedef struct { + CHAR aIdText[17]; + CHAR aModuleName[20]; + BYTE bPadding; + CHAR aTrackerName[20]; + WORD wVersion; + DWORD dwHeaderSize; + WORD nSongLength; + WORD nRestart; + WORD nTracks; + WORD nPatterns; + WORD nPatches; + WORD wFlags; + WORD nTempo; + WORD nBPM; + BYTE aOrderTable[256]; +} XMFILEHEADER; + +typedef struct { + DWORD dwHeaderSize; + BYTE nPacking; + WORD nRows; + WORD nSize; +} XMPATTERNHEADER; + +typedef struct { + DWORD dwHeaderSize; + CHAR aPatchName[22]; + BYTE nType; + WORD nSamples; + DWORD dwSampleHeaderSize; + BYTE aSampleNumber[96]; + DWORD aVolumeEnvelope[12]; + DWORD aPanningEnvelope[12]; + BYTE nVolumePoints; + BYTE nPanningPoints; + BYTE nVolumeSustain; + BYTE nVolumeLoopStart; + BYTE nVolumeLoopEnd; + BYTE nPanningSustain; + BYTE nPanningLoopStart; + BYTE nPanningLoopEnd; + BYTE bVolumeFlags; + BYTE bPanningFlags; + BYTE nVibratoType; + BYTE nVibratoSweep; + BYTE nVibratoDepth; + BYTE nVibratoRate; + WORD nVolumeFadeout; + WORD wReserved; +} XMPATCHHEADER; + +typedef struct { + DWORD dwLength; + DWORD dwLoopStart; + DWORD dwLoopLength; + BYTE nVolume; + BYTE nFinetune; + BYTE bFlags; + BYTE nPanning; + BYTE nRelativeNote; + BYTE bReserved; + CHAR aSampleName[22]; +} XMSAMPLEHEADER; + + +/* + * Extended module loader routines + */ +static VOID XMDecodeSamples(LPAUDIOWAVE lpWave) +{ + LPWORD lpwCode; + LPBYTE lpbCode; + UINT nDelta, nCount; + + nDelta = 0; + nCount = lpWave->dwLength; + if (lpWave->wFormat & AUDIO_FORMAT_16BITS) { + lpwCode = (LPWORD) lpWave->lpData; + nCount >>= 1; + while (nCount--) { +#ifdef __BIGENDIAN__ + *lpwCode = MAKEWORD(HIBYTE(*lpwCode), LOBYTE(*lpwCode)); +#endif + nDelta = *lpwCode++ += nDelta; + } + } + else { + lpbCode = (LPBYTE) lpWave->lpData; + while (nCount--) { + nDelta = (BYTE) (*lpbCode++ += (BYTE) nDelta); + } + } +} + +UINT AIAPI ALoadModuleXM(LPSTR lpszFileName, + LPAUDIOMODULE *lplpModule, DWORD dwFileOffset) +{ + static XMFILEHEADER Header; + static XMPATTERNHEADER Pattern; + static XMPATCHHEADER Patch; + static XMSAMPLEHEADER Sample; + LPAUDIOMODULE lpModule; + LPAUDIOPATTERN lpPattern; + LPAUDIOPATCH lpPatch; + LPAUDIOSAMPLE lpSample; + UINT n, m, nErrorCode; + + /* open XM module file */ + if (AIOOpenFile(lpszFileName)) { + return AUDIO_ERROR_FILENOTFOUND; + } + AIOSeekFile(dwFileOffset, SEEK_SET); + + if ((lpModule = (LPAUDIOMODULE) calloc(1, sizeof(AUDIOMODULE))) == NULL) { + AIOCloseFile(); + return AUDIO_ERROR_NOMEMORY; + } + + /* load XM module header structure */ + AIOReadFile(Header.aIdText, sizeof(Header.aIdText)); + AIOReadFile(Header.aModuleName, sizeof(Header.aModuleName)); + AIOReadChar(&Header.bPadding); + AIOReadFile(Header.aTrackerName, sizeof(Header.aTrackerName)); + AIOReadShort(&Header.wVersion); + AIOReadLong(&Header.dwHeaderSize); + AIOReadShort(&Header.nSongLength); + AIOReadShort(&Header.nRestart); + AIOReadShort(&Header.nTracks); + AIOReadShort(&Header.nPatterns); + AIOReadShort(&Header.nPatches); + AIOReadShort(&Header.wFlags); + AIOReadShort(&Header.nTempo); + AIOReadShort(&Header.nBPM); + AIOReadFile(&Header.aOrderTable, sizeof(Header.aOrderTable)); + AIOSeekFile(Header.dwHeaderSize - XM_FILE_HEADER_SIZE, SEEK_CUR); + if (memcmp(Header.aIdText, "Extended Module: ", sizeof(Header.aIdText)) || + Header.wVersion != 0x104 || + Header.nSongLength > AUDIO_MAX_ORDERS || + Header.nPatterns > AUDIO_MAX_PATTERNS || + Header.nPatches > AUDIO_MAX_PATCHES || + Header.nTracks > AUDIO_MAX_VOICES) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_BADFILEFORMAT; + } + + /* initialize module structure */ + strncpy(lpModule->szModuleName, Header.aModuleName, + sizeof(Header.aModuleName)); + if (Header.wFlags & XM_MODULE_LINEAR) + lpModule->wFlags |= AUDIO_MODULE_LINEAR; + lpModule->nOrders = Header.nSongLength; + lpModule->nRestart = Header.nRestart; + lpModule->nTracks = Header.nTracks; + lpModule->nPatterns = Header.nPatterns; + lpModule->nPatches = Header.nPatches; + lpModule->nTempo = Header.nTempo; + lpModule->nBPM = Header.nBPM; + for (n = 0; n < lpModule->nOrders; n++) { + lpModule->aOrderTable[n] = Header.aOrderTable[n]; + } + for (n = 0; n < lpModule->nTracks; n++) { + lpModule->aPanningTable[n] = (AUDIO_MIN_PANNING + AUDIO_MAX_PANNING)/2; + } + + if ((lpModule->aPatternTable = (LPAUDIOPATTERN) + calloc(lpModule->nPatterns, sizeof(AUDIOPATTERN))) == NULL) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_NOMEMORY; + } + if ((lpModule->aPatchTable = (LPAUDIOPATCH) + calloc(lpModule->nPatches, sizeof(AUDIOPATCH))) == NULL) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_NOMEMORY; + } + + lpPattern = lpModule->aPatternTable; + for (n = 0; n < lpModule->nPatterns; n++, lpPattern++) { + /* load XM pattern header structure */ + AIOReadLong(&Pattern.dwHeaderSize); + AIOReadChar(&Pattern.nPacking); + AIOReadShort(&Pattern.nRows); + AIOReadShort(&Pattern.nSize); + AIOSeekFile(Pattern.dwHeaderSize - XM_PATTERN_HEADER_SIZE, SEEK_CUR); + if (Pattern.nPacking != 0) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_BADFILEFORMAT; + } + + /* initialize pattern structure */ + lpPattern->nPacking = Pattern.nPacking; + lpPattern->nTracks = lpModule->nTracks; + lpPattern->nRows = Pattern.nRows; + lpPattern->nSize = Pattern.nSize; + if (lpPattern->nSize != 0) { + /* allocate and load pattern data */ + if ((lpPattern->lpData = malloc(lpPattern->nSize)) == NULL) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_NOMEMORY; + } + AIOReadFile(lpPattern->lpData, lpPattern->nSize); + } + } + + lpPatch = lpModule->aPatchTable; + for (n = 0; n < lpModule->nPatches; n++, lpPatch++) { + /* load XM patch header structure */ + AIOReadLong(&Patch.dwHeaderSize); + AIOReadFile(Patch.aPatchName, sizeof(Patch.aPatchName)); + AIOReadChar(&Patch.nType); + AIOReadShort(&Patch.nSamples); + if (Patch.nSamples != 0) { + AIOReadLong(&Patch.dwSampleHeaderSize); + AIOReadFile(Patch.aSampleNumber, sizeof(Patch.aSampleNumber)); + for (m = 0; m < AUDIO_MAX_POINTS; m++) { + AIOReadLong(&Patch.aVolumeEnvelope[m]); + } + for (m = 0; m < AUDIO_MAX_POINTS; m++) { + AIOReadLong(&Patch.aPanningEnvelope[m]); + } + AIOReadChar(&Patch.nVolumePoints); + AIOReadChar(&Patch.nPanningPoints); + AIOReadChar(&Patch.nVolumeSustain); + AIOReadChar(&Patch.nVolumeLoopStart); + AIOReadChar(&Patch.nVolumeLoopEnd); + AIOReadChar(&Patch.nPanningSustain); + AIOReadChar(&Patch.nPanningLoopStart); + AIOReadChar(&Patch.nPanningLoopEnd); + AIOReadChar(&Patch.bVolumeFlags); + AIOReadChar(&Patch.bPanningFlags); + AIOReadChar(&Patch.nVibratoType); + AIOReadChar(&Patch.nVibratoSweep); + AIOReadChar(&Patch.nVibratoDepth); + AIOReadChar(&Patch.nVibratoRate); + AIOReadShort(&Patch.nVolumeFadeout); + AIOReadShort(&Patch.wReserved); + Patch.dwHeaderSize -= XM_PATCH_BODY_SIZE; + } + AIOSeekFile(Patch.dwHeaderSize - XM_PATCH_HEADER_SIZE, SEEK_CUR); + + /* HACK: clamp envelope's number of points (12/12/96) */ + if (Patch.nVolumePoints > AUDIO_MAX_POINTS) + Patch.nVolumePoints = AUDIO_MAX_POINTS; + if (Patch.nPanningPoints > AUDIO_MAX_POINTS) + Patch.nPanningPoints = AUDIO_MAX_POINTS; + + if (Patch.nSamples > AUDIO_MAX_SAMPLES || + Patch.nVolumePoints > AUDIO_MAX_POINTS || + Patch.nPanningPoints > AUDIO_MAX_POINTS) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_BADFILEFORMAT; + } + + /* initialize patch structure */ + strncpy(lpPatch->szPatchName, Patch.aPatchName, + sizeof(Patch.aPatchName)); + for (m = 0; m < AUDIO_MAX_NOTES; m++) { + lpPatch->aSampleNumber[m] = Patch.aSampleNumber[m]; + if (lpPatch->aSampleNumber[m] >= Patch.nSamples) + lpPatch->aSampleNumber[m] = 0x00; + } + lpPatch->nSamples = Patch.nSamples; + lpPatch->nVibratoType = Patch.nVibratoType; + lpPatch->nVibratoSweep = Patch.nVibratoSweep; + lpPatch->nVibratoDepth = Patch.nVibratoDepth; + lpPatch->nVibratoRate = Patch.nVibratoRate; + lpPatch->nVolumeFadeout = Patch.nVolumeFadeout; + lpPatch->Volume.nPoints = Patch.nVolumePoints; + lpPatch->Volume.nSustain = Patch.nVolumeSustain; + lpPatch->Volume.nLoopStart = Patch.nVolumeLoopStart; + lpPatch->Volume.nLoopEnd = Patch.nVolumeLoopEnd; + if (Patch.bVolumeFlags & XM_ENVELOPE_ON) + lpPatch->Volume.wFlags |= AUDIO_ENVELOPE_ON; + if (Patch.bVolumeFlags & XM_ENVELOPE_SUSTAIN) + lpPatch->Volume.wFlags |= AUDIO_ENVELOPE_SUSTAIN; + if (Patch.bVolumeFlags & XM_ENVELOPE_LOOP) + lpPatch->Volume.wFlags |= AUDIO_ENVELOPE_LOOP; + for (m = 0; m < lpPatch->Volume.nPoints; m++) { + lpPatch->Volume.aEnvelope[m].nFrame = + LOWORD(Patch.aVolumeEnvelope[m]); + lpPatch->Volume.aEnvelope[m].nValue = + HIWORD(Patch.aVolumeEnvelope[m]); + } + lpPatch->Panning.nPoints = Patch.nPanningPoints; + lpPatch->Panning.nSustain = Patch.nPanningSustain; + lpPatch->Panning.nLoopStart = Patch.nPanningLoopStart; + lpPatch->Panning.nLoopEnd = Patch.nPanningLoopEnd; + if (Patch.bPanningFlags & XM_ENVELOPE_ON) + lpPatch->Panning.wFlags |= AUDIO_ENVELOPE_ON; + if (Patch.bPanningFlags & XM_ENVELOPE_SUSTAIN) + lpPatch->Panning.wFlags |= AUDIO_ENVELOPE_SUSTAIN; + if (Patch.bPanningFlags & XM_ENVELOPE_LOOP) + lpPatch->Panning.wFlags |= AUDIO_ENVELOPE_LOOP; + for (m = 0; m < lpPatch->Panning.nPoints; m++) { + lpPatch->Panning.aEnvelope[m].nFrame = + LOWORD(Patch.aPanningEnvelope[m]); + lpPatch->Panning.aEnvelope[m].nValue = + HIWORD(Patch.aPanningEnvelope[m]); + } + if (lpPatch->nSamples != 0) { + if ((lpPatch->aSampleTable = (LPAUDIOSAMPLE) + calloc(lpPatch->nSamples, sizeof(AUDIOSAMPLE))) == NULL) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return AUDIO_ERROR_NOMEMORY; + } + } + + /* load XM multi-sample header structures */ + lpSample = lpPatch->aSampleTable; + for (m = 0; m < Patch.nSamples; m++, lpSample++) { + AIOReadLong(&Sample.dwLength); + AIOReadLong(&Sample.dwLoopStart); + AIOReadLong(&Sample.dwLoopLength); + AIOReadChar(&Sample.nVolume); + AIOReadChar(&Sample.nFinetune); + AIOReadChar(&Sample.bFlags); + AIOReadChar(&Sample.nPanning); + AIOReadChar(&Sample.nRelativeNote); + AIOReadChar(&Sample.bReserved); + AIOReadFile(Sample.aSampleName, sizeof(Sample.aSampleName)); + AIOSeekFile(Patch.dwSampleHeaderSize - + XM_SAMPLE_HEADER_SIZE, SEEK_CUR); + strncpy(lpSample->szSampleName, Sample.aSampleName, + sizeof(Sample.aSampleName)); + lpSample->Wave.dwLength = Sample.dwLength; + lpSample->Wave.dwLoopStart = Sample.dwLoopStart; + lpSample->Wave.dwLoopEnd = Sample.dwLoopStart + Sample.dwLoopLength; + lpSample->Wave.nSampleRate = 8363; + lpSample->nVolume = Sample.nVolume; + lpSample->nPanning = Sample.nPanning; + lpSample->nRelativeNote = Sample.nRelativeNote; + lpSample->nFinetune = Sample.nFinetune; + if (Sample.bFlags & XM_SAMPLE_16BITS) { + lpSample->Wave.wFormat |= AUDIO_FORMAT_16BITS; + } + if (Sample.bFlags & XM_SAMPLE_LOOP) + lpSample->Wave.wFormat |= AUDIO_FORMAT_LOOP; + if (Sample.bFlags & XM_SAMPLE_PINGPONG) + lpSample->Wave.wFormat |= AUDIO_FORMAT_BIDILOOP; + } + + /* load XM multi-sample waveform data */ + lpSample = lpPatch->aSampleTable; + for (m = 0; m < Patch.nSamples; m++, lpSample++) { + if (lpSample->Wave.dwLength == 0) + continue; + nErrorCode = ACreateAudioData(&lpSample->Wave); + if (nErrorCode != AUDIO_ERROR_NONE) { + AFreeModuleFile(lpModule); + AIOCloseFile(); + return nErrorCode; + } + AIOReadFile(lpSample->Wave.lpData, lpSample->Wave.dwLength); + XMDecodeSamples(&lpSample->Wave); + AWriteAudioData(&lpSample->Wave, 0, lpSample->Wave.dwLength); + } + } + + AIOCloseFile(); + *lplpModule = lpModule; + return AUDIO_ERROR_NONE; +}