├── src ├── include │ ├── username.h │ ├── wavswitc.h │ ├── network.h │ ├── switch.h │ ├── it_obj.h │ └── it_struc.h ├── player.c ├── ui │ ├── it_obj1.c │ ├── it_m.c │ └── it.c ├── sdriver │ ├── drv_oss.c │ └── drv_sdl.c └── player │ ├── it_disk.c │ └── it_m_eff.c ├── .gitignore ├── Makefile ├── README.md ├── LICENCE.txt └── Makefile.common /src/include/username.h: -------------------------------------------------------------------------------- 1 | #define REGISTERNAME "Unregistered" 2 | 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Output 2 | itedit 3 | itplay 4 | 5 | # Source files 6 | *.it 7 | 8 | # VIM 9 | .sw? 10 | .*.sw? 11 | 12 | # Other crap 13 | *~ 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # I personally don't care if you steal this makefile. --GM 2 | 3 | CFLAGS = -g -O2 -Isrc/include/ `sdl2-config --cflags` 4 | LDFLAGS = -g 5 | LIBS = -lm `sdl2-config --libs` 6 | BINNAME_PLAYER = itplay 7 | BINNAME_EDITOR = itedit 8 | OBJDIR = build 9 | 10 | include Makefile.common 11 | 12 | -------------------------------------------------------------------------------- /src/include/wavswitc.h: -------------------------------------------------------------------------------- 1 | #define REGISTERED 1 2 | 3 | #define VOLUMERAMP 1 4 | #define DOUBLEVOLUME 0 5 | #define DITHEROUTPUT 1 6 | 7 | #define USECLICKFADETHRESHHOLD 0 8 | #define CLICKFADETHRESHHOLD 4096 9 | 10 | #define RAMPSPEED 8 11 | #define RAMPCOMPENSATE 255 12 | 13 | #define CUBICINTERPOLATION 1 14 | #define QUADRATICINTERPOLATION 0 15 | #define LINEARINTERPOLATION 0 16 | #define POINTSAMPLED 0 17 | 18 | #define INTELOPTIMISED 0 19 | 20 | static uint16_t FileID = 0; 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/player.c: -------------------------------------------------------------------------------- 1 | /* 2 | This part is public domain and is by GreaseMonkey. 3 | Of course, IT itself is BSD-licensed, 4 | and this code is kinda useless without it, 5 | but hey, here's a simple use case. 6 | */ 7 | 8 | #include 9 | #include "it_struc.h" 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | const char *fname = argv[1]; 14 | 15 | it_engine *ite = ITEngineNew(); 16 | 17 | Music_InitMusic(ite); 18 | const char *dname = Music_AutoDetectSoundCard(ite); 19 | printf("Driver detected: \"%s\"\n", dname); 20 | 21 | D_LoadIT(ite, argv[1]); 22 | Music_PlaySong(ite, 0); 23 | //Music_PlayPattern(ite, 0, 64, 0); 24 | 25 | for(;;) 26 | { 27 | Music_Poll(ite); 28 | } 29 | 30 | return 0; 31 | } 32 | 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | this is a port of this thing to C: http://bitbucket.org/jthlim/impulsetracker 2 | 3 | licence now exists, check LICENCE.TXT 4 | 5 | to build all the things: 6 | 7 | make 8 | 9 | to build player manually: 10 | 11 | cc -o itplay src/sdriver/*.c src/player/*.c src/player.c -I src/include/ -lm 12 | 13 | to build editor manually: 14 | 15 | cc -o itedit -DEDITOR src/sdriver/*.c src/player/*.c src/ui/*.c -I src/include/ -lm 16 | 17 | to play delicious music: 18 | 19 | ./itplay ~/path/to/music.it 20 | 21 | you will need OSS or some OSS-emulation layer for sound 22 | 23 | only has the IT loading routines ported and some cases are incomplete 24 | 25 | currently broken in many ways though sample-mode stuff might work 26 | 27 | have fun 28 | 29 | -------------------------------------------------------------------------------- /LICENCE.txt: -------------------------------------------------------------------------------- 1 | Modifications are by GreaseMonkey, 2014, 2015. 2 | This software is derived almost entirely from the Impulse Tracker source release: 3 | 4 | Copyright (C) 2014, Jeffrey Lim. All Rights Reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. The name of the author may not be used to endorse or promote products 17 | derived from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 20 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 22 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | POSSIBILITY OF SUCH DAMAGE. 29 | 30 | -------------------------------------------------------------------------------- /Makefile.common: -------------------------------------------------------------------------------- 1 | # I personally don't care if you steal this makefile. --GM 2 | 3 | SRCDIR = src 4 | INCDIR = src/include 5 | INCLUDES = \ 6 | $(INCDIR)/it_obj.h \ 7 | $(INCDIR)/network.h \ 8 | $(INCDIR)/switch.h \ 9 | $(INCDIR)/username.h \ 10 | $(INCDIR)/wavswitc.h \ 11 | \ 12 | $(INCDIR)/it_struc.h 13 | 14 | OBJDIR_PLAYER = $(OBJDIR)/itplay 15 | OBJDIR_EDITOR = $(OBJDIR)/itedit 16 | 17 | OBJS_PLAYER = \ 18 | $(OBJDIR_PLAYER)/player/it_disk.o \ 19 | $(OBJDIR_PLAYER)/player/it_music.o \ 20 | $(OBJDIR_PLAYER)/player/it_m_eff.o \ 21 | \ 22 | $(OBJDIR_PLAYER)/sdriver/drv_sdl.o \ 23 | $(OBJDIR_PLAYER)/sdriver/drv_oss.o \ 24 | \ 25 | $(OBJDIR_PLAYER)/player.o 26 | 27 | OBJS_EDITOR = \ 28 | $(OBJDIR_EDITOR)/player/it_disk.o \ 29 | $(OBJDIR_EDITOR)/player/it_music.o \ 30 | $(OBJDIR_EDITOR)/player/it_m_eff.o \ 31 | \ 32 | $(OBJDIR_PLAYER)/sdriver/drv_sdl.o \ 33 | $(OBJDIR_EDITOR)/sdriver/drv_oss.o \ 34 | \ 35 | $(OBJDIR_EDITOR)/ui/it_m.o \ 36 | $(OBJDIR_EDITOR)/ui/it_obj1.o \ 37 | \ 38 | $(OBJDIR_EDITOR)/ui/it.o 39 | 40 | all: $(BINNAME_PLAYER) $(BINNAME_EDITOR) $(TOOLS) 41 | 42 | clean: 43 | rm -f $(OBJS_PLAYER) 44 | rm -f $(OBJS_EDITOR) 45 | 46 | $(OBJDIR): 47 | mkdir $(OBJDIR) || true 48 | mkdir $(OBJDIR_PLAYER) || true 49 | mkdir $(OBJDIR_EDITOR) || true 50 | mkdir $(OBJDIR_PLAYER)/player || true 51 | mkdir $(OBJDIR_EDITOR)/player || true 52 | mkdir $(OBJDIR_PLAYER)/sdriver || true 53 | mkdir $(OBJDIR_EDITOR)/sdriver || true 54 | mkdir $(OBJDIR_EDITOR)/ui || true 55 | 56 | $(OBJDIR_PLAYER)/%.o: $(SRCDIR)/%.c $(OBJDIR) $(INCLUDES) 57 | $(CC) -c -o $@ $(CFLAGS) $< 58 | 59 | $(OBJDIR_EDITOR)/%.o: $(SRCDIR)/%.c $(OBJDIR) $(INCLUDES) 60 | $(CC) -c -o $@ $(CFLAGS) -DEDITOR $< 61 | 62 | $(BINNAME_PLAYER): $(OBJDIR) $(OBJS_PLAYER) 63 | $(CC) -o $(BINNAME_PLAYER) $(LDFLAGS) $(OBJS_PLAYER) $(LIBS) 64 | 65 | $(BINNAME_EDITOR): $(OBJDIR) $(OBJS_EDITOR) 66 | $(CC) -o $(BINNAME_EDITOR) $(LDFLAGS) $(OBJS_EDITOR) $(LIBS) 67 | 68 | .PHONY: all clean 69 | 70 | -------------------------------------------------------------------------------- /src/include/network.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014, Jeffrey Lim. All Rights Reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | 3. The name of the author may not be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 19 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 20 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #if NETWORKENABLED 30 | /* 31 | Extrn Network_GetSendQueue:Far 32 | Extrn Network_FinishedSendQueue:Far 33 | Extrn Network_AddWordToQueue:Far 34 | Extrn Network_EnsureNoNetwork:Far 35 | Extrn Network_SendSampleHeader:Far 36 | Extrn Network_SendInstrumentHeader:Far 37 | Extrn Network_QueueSampleData:Far 38 | Extrn Network_SendSongDataInformation:Far 39 | */ 40 | 41 | #define NETWORK_PARTIALPATTERNOBJECT 0 42 | #define NETWORK_ENTIREPATTERNOBJECT 1 43 | #define NETWORK_REQUESTPATTERNOBJECT 2 44 | #define NETWORK_SONGDATAOBJECT 3 45 | #define NETWORK_INSTRUMENTHEADEROBJECT 4 46 | #define NETWORK_SAMPLEHEADEROBJECT 5 47 | #define NETWORK_SETPATTERNLENGTH 6 48 | #define NETWORK_DELETESAMPLEOBJECT 7 49 | 50 | #define EnsureNoNetwork(ite) Network_EnsureNoNetwork(ite) 51 | #define NetworkSendSample(ite) Network_SendSampleHeader(ite) 52 | #define NetworkSendInstrument(ite) Network_SendInstrumentHeader(ite) 53 | 54 | #else 55 | 56 | #define EnsureNoNetwork(ite) 57 | #define NetworkSendSample(ite) 58 | #define NetworkSendInstrument(ite) 59 | 60 | #endif 61 | 62 | -------------------------------------------------------------------------------- /src/include/switch.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014, Jeffrey Lim. All Rights Reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | 3. The name of the author may not be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 19 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 20 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #define TRACEENABLED 0 30 | 31 | #define TUTORIAL 0 32 | 33 | #define EMSUSE41 0 34 | 35 | #define SHOWVERSION 0 36 | #define SHOWREGISTERNAME 1 37 | 38 | #define USE32BITSCREENCOPY 0 39 | 40 | #define SORTENABLED 1 41 | #define DDCOMPRESS 1 42 | #define ORDERSORT 1 43 | #define FILTERENVELOPES 1 44 | #define CHORDENTRY 1 45 | #define SPECTRUMANALYSER 1 46 | #define SAVESAMPLEWAV 1 47 | #define ENABLEPRESETENVELOPES 1 48 | #define ENABLESOLO 1 49 | 50 | #define DEFAULTFORMAT 3 /* 0 IT214, 1 S3M, 2 IT2xx, 3 IT215 */ 51 | 52 | // USEFPUCODE disabled for the time being --GM 53 | #define USEFPUCODE 0 /* For IT_MUSIC, this will change from LUT to FPU code */ 54 | 55 | #define OLDDRIVER 0 56 | 57 | #define MUSICDEBUG 0 58 | #define EMSDEBUG 0 59 | #define MEMORYDEBUG 0 60 | #define ENABLEINT3 0 /* For debugging. */ 61 | 62 | #define TIMERSCREEN 1 63 | 64 | //define NETWORKENABLED 1 65 | #define NETWORKENABLED 0 66 | #define SHOWPATTERNLENGTH 0 67 | 68 | #if TUTORIAL 69 | #define SORTENABLED 1 70 | #define DDCOMPRESS 1 71 | #endif 72 | 73 | #define TRACKERVERSION 0x217 /* Still have to change text in IT.ASM, IT_F.ASM */ 74 | 75 | -------------------------------------------------------------------------------- /src/include/it_obj.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014, Jeffrey Lim. All Rights Reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | 3. The name of the author may not be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 19 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 20 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | typedef union it_object_u it_object; 30 | union it_object_u 31 | { 32 | int typ; 33 | 34 | // 0: Box 35 | struct { 36 | int typ; 37 | int left, top, right, bottom; 38 | int style; 39 | } box; 40 | 41 | // 1: Text 42 | struct { 43 | int typ; 44 | int x, y; 45 | int color; 46 | const char *text; 47 | } text; 48 | 49 | // 2: Button 50 | struct { 51 | int typ; 52 | int a_up, a_down, a_left, a_right; 53 | int usage; 54 | int usage_radio_min, usage_radio_max; 55 | int button_effect; 56 | int eff_v1, eff_v2; 57 | void *eff_p1, *eff_p2; 58 | int left, top, right, bottom; 59 | int style; 60 | int flags; 61 | const char *text; 62 | } button; 63 | 64 | // 3: Empty 65 | // 4: Empty 66 | 67 | // 5: Select Direct Screen 68 | struct { 69 | int typ; 70 | int mode; 71 | } select_direct_screen; 72 | 73 | // 6: Redefine Characters 74 | struct { 75 | int typ; 76 | int first, num; 77 | const uint8_t *table; 78 | } redefine_characters; 79 | 80 | // 7: Empty 81 | 82 | // 8: Call Far Function 83 | struct { 84 | int typ; 85 | void *function; 86 | } call_far_function; 87 | 88 | // 9: Thumb bar 89 | struct { 90 | int typ; 91 | int x, y; 92 | int min_range, max_range; 93 | int wd1, wd2; 94 | int a_up, a_down, a_tab, a_shtab; 95 | int a_pgup, a_pgdn; 96 | } thumb_bar; 97 | 98 | // 10: Infoline 99 | struct { 100 | int typ; 101 | const char *text; 102 | } infoline; 103 | 104 | // 11: Set help context 105 | struct { 106 | int typ; 107 | int number; 108 | } set_help_context; 109 | 110 | // TODO: The rest 111 | }; 112 | 113 | typedef struct it_objlist_2_s 114 | { 115 | int typ; 116 | int unk1; 117 | void *ptrs[]; 118 | } it_objlist_2; 119 | 120 | typedef struct it_objlist_6_s 121 | { 122 | int typ; 123 | int unk1; 124 | void *ptrs[]; 125 | } it_objlist_6; 126 | 127 | -------------------------------------------------------------------------------- /src/ui/it_obj1.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014, Jeffrey Lim. All Rights Reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | 3. The name of the author may not be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 19 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 20 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #include "it_struc.h" 30 | 31 | /* 32 | ESCContinueList DB 0 ; ESC 33 | DW 101h 34 | DD Glbl_F2 35 | 36 | DB 0FFh 37 | */ 38 | it_object AboutBox = { 39 | .box = { 40 | 0, // Object type 0 41 | 11, 16, 68, 34, // Coordinates 42 | 0, // Box style 43 | } 44 | }; 45 | 46 | it_object AutoMiniBox = { 47 | .box = { 48 | 0, 49 | 25, 25, 55, 30, 50 | 0, 51 | } 52 | }; 53 | 54 | const char AboutTextData[] = { 55 | 0xFF, 1, 0, 4, 8, 0xFF, 8, 55, 37, 41, 0xFF, 5, 55, 56, 58, 62, 66, 0xFF, 6, 55, 88, 92, 13, 56 | 1, 5, 9, 12, 15, 18, 22, 25, 28, 31, 34, 38, 42, 45, 48, 51, 55, 55, 57, 59, 63, 67, 70, 73, 76, 79, 82, 85, 89, 93, 96, 99, 102, 105, 13, 57 | 2, 6, 0xFF, 1, 10, 0xFF, 1, 13, 16, 19, 23, 26, 29, 32, 35, 39, 43, 46, 49, 52, 54, 55, 55, 60, 64, 68, 71, 74, 77, 80, 83, 86, 90, 94, 97, 100, 103, 106, 13, 58 | 3, 7, 11, 14, 17, 20, 24, 27, 30, 33, 36, 40, 44, 47, 50, 53, 55, 55, 55, 61, 65, 69, 72, 75, 78, 81, 84, 87, 91, 95, 98, 101, 104, 107, 13, 59 | 0xFF, 5, 55, 21, 0 60 | }; 61 | 62 | it_object AboutText = { 63 | .text = { 64 | 1, // Object type 1 65 | 24, 19, 66 | 0x2B, 67 | AboutTextData, 68 | } 69 | }; 70 | 71 | const uint8_t ImpulseLogoChars[] = { 72 | 0, 0, 0, 0, 1, 7, 15, 31, // 0 73 | 63, 127, 127, 254, 252, 255, 255, 126, // 1 74 | 24, 0, 0, 0, 0, 0, 0, 0, // 2 75 | 0, 1, 3, 3, 3, 1, 0, 0, // 3 76 | 7, 31, 63, 255, 255, 254, 248, 240, // 4 77 | 192, 128, 0, 1, 1, 131, 3, 7, // 5 78 | 7, 15, 14, 30, 60, 60, 120, 240, // 6 79 | 240, 224, 224, 224, 224, 192, 0, 0, // 7 80 | 240, 240, 248, 248, 248, 120, 56, 120, // 8 81 | 112, 240, 240, 224, 224, 192, 192, 131, // 9 82 | 7, 15, 31, 31, 62, 60, 61, 63, // 10 83 | 63, 63, 62, 28, 8, 0, 0, 0, // 11 84 | 0, 0, 0, 0, 0, 0, 193, 227, // 12 85 | 199, 223, 191, 127, 247, 239, 207, 159, // 13 86 | 31, 31, 63, 60, 24, 0, 0, 0, // 14 87 | 0, 0, 0, 0, 0, 240, 240, 240, // 15 88 | 241, 227, 239, 223, 191, 251, 247, 231, // 16 89 | 159, 159, 31, 31, 14, 0, 0, 0, // 17 90 | 0, 0, 0, 0, 0, 48, 112, 248, // 18 91 | 248, 240, 224, 192, 193, 131, 7, 30, // 19 92 | 252, 240, 225, 131, 3, 7, 7, 15, // 20 93 | 15, 30, 30, 28, 8, 0, 0, 0, // 21 94 | 0, 0, 0, 1, 3, 3, 7, 15, // 22 95 | 31, 63, 127, 255, 191, 190, 124, 126, // 23 96 | 255, 255, 255, 255, 199, 128, 128, 0, // 24 97 | 60, 124, 248, 240, 224, 192, 135, 159, // 25 98 | 127, 255, 223, 143, 30, 60, 56, 113, // 26 99 | 255, 255, 252, 240, 192, 0, 0, 0, // 27 100 | 0, 0, 0, 0, 0, 0, 128, 129, // 28 101 | 131, 135, 15, 15, 30, 60, 124, 253, // 29 102 | 191, 31, 31, 14, 0, 0, 0, 0, // 30 103 | 0, 0, 0, 0, 0, 112, 248, 240, // 31 104 | 225, 195, 135, 15, 31, 63, 127, 255, // 32 105 | 239, 223, 159, 15, 14, 0, 0, 0, // 33 106 | 0, 0, 0, 0, 24, 56, 124, 248, // 34 107 | 248, 241, 225, 193, 129, 131, 15, 31, // 35 108 | 249, 241, 225, 192, 0, 0, 0, 0, // 36 109 | 0, 0, 0, 0, 0, 0, 1, 3, // 37 110 | 7, 15, 30, 61, 57, 123, 119, 254, // 38 111 | 252, 248, 240, 224, 192, 192, 192, 225, // 39 112 | 247, 255, 254, 252, 0, 0, 0, 0, // 40 113 | 0, 0, 24, 56, 120, 248, 248, 240, // 41 114 | 112, 96, 224, 192, 192, 128, 0, 1, // 42 115 | 3, 7, 14, 28, 56, 112, 248, 252, // 43 116 | 255, 127, 63, 31, 7, 0, 0, 0, // 44 117 | 0, 0, 0, 48, 120, 120, 248, 248, // 45 118 | 252, 124, 124, 120, 120, 112, 241, 231, // 46 119 | 142, 252, 248, 224, 128, 0, 0, 0, // 47 120 | 0, 0, 0, 0, 0, 0, 3, 7, // 48 121 | 15, 30, 60, 63, 127, 254, 252, 60, // 49 122 | 126, 63, 63, 31, 6, 0, 0, 0, // 50 123 | 0, 0, 0, 0, 60, 254, 254, 222, // 51 124 | 30, 60, 248, 224, 128, 1, 7, 14, // 52 125 | 124, 248, 224, 192, 0, 0, 0, 0, // 53 126 | 0, 0, 0, 0, 128, 128, 0, 0, // 54 127 | 0, 0, 0, 0, 0, 0, 0, 0, // 55 128 | 0, 0, 7, 31, 63, 127, 127, 255, // 56 129 | 255, 252, 127, 0, 0, 0, 0, 0, // 57 130 | 3, 255, 255, 255, 255, 255, 255, 252, // 58 131 | 128, 0, 0, 0, 0, 0, 0, 0, // 59 132 | 0, 0, 0, 1, 1, 3, 3, 7, // 60 133 | 7, 15, 31, 31, 31, 30, 0, 0, // 61 134 | 255, 255, 255, 255, 255, 255, 255, 0, // 62 135 | 0, 1, 3, 7, 7, 15, 31, 62, // 63 136 | 60, 124, 248, 248, 240, 240, 224, 224, // 64 137 | 192, 192, 128, 128, 0, 0, 0, 0, // 65 138 | 128, 224, 240, 240, 248, 248, 248, 112, // 66 139 | 240, 224, 192, 192, 128, 6, 15, 31, // 67 140 | 63, 127, 127, 112, 33, 97, 195, 131, // 68 141 | 7, 7, 7, 3, 1, 0, 0, 0, // 69 142 | 0, 0, 0, 0, 0, 0, 252, 254, // 70 143 | 254, 252, 248, 240, 224, 193, 195, 199, // 71 144 | 223, 253, 240, 224, 128, 0, 0, 0, // 72 145 | 0, 0, 0, 0, 0, 0, 0, 3, // 73 146 | 15, 31, 63, 124, 248, 240, 225, 195, // 74 147 | 199, 254, 252, 120, 48, 0, 0, 0, // 75 148 | 0, 0, 0, 0, 0, 31, 255, 255, // 76 149 | 255, 255, 191, 63, 126, 252, 248, 184, // 77 150 | 63, 127, 127, 126, 124, 48, 0, 0, // 78 151 | 0, 0, 0, 0, 0, 0, 128, 128, // 79 152 | 129, 3, 7, 15, 15, 31, 62, 126, // 80 153 | 239, 207, 143, 7, 3, 0, 0, 0, // 81 154 | 0, 0, 0, 0, 0, 15, 63, 255, // 82 155 | 255, 255, 238, 204, 0, 0, 0, 3, // 83 156 | 15, 255, 254, 248, 224, 0, 0, 0, // 84 157 | 0, 0, 0, 0, 0, 193, 195, 131, // 85 158 | 135, 15, 15, 31, 63, 127, 255, 255, // 86 159 | 190, 60, 28, 24, 0, 0, 0, 0, // 87 160 | 0, 0, 0, 0, 0, 1, 3, 7, // 88 161 | 15, 31, 63, 126, 252, 248, 240, 227, // 89 162 | 199, 223, 188, 112, 225, 199, 254, 252, // 90 163 | 252, 126, 127, 63, 31, 0, 0, 0, // 91 164 | 0, 12, 60, 124, 248, 248, 240, 224, // 92 165 | 192, 128, 0, 0, 0, 48, 248, 248, // 93 166 | 248, 120, 241, 225, 195, 3, 15, 31, // 94 167 | 59, 243, 227, 129, 0, 0, 0, 0, // 95 168 | 0, 0, 0, 0, 1, 15, 31, 62, // 96 169 | 120, 241, 231, 239, 252, 240, 192, 192, // 97 170 | 227, 255, 255, 252, 112, 0, 0, 0, // 98 171 | 0, 0, 0, 0, 192, 240, 241, 243, // 99 172 | 231, 207, 143, 14, 12, 28, 56, 112, // 100 173 | 225, 193, 1, 0, 0, 0, 0, 0, // 101 174 | 0, 0, 0, 0, 0, 192, 255, 255, // 102 175 | 255, 255, 254, 60, 120, 112, 240, 241, // 103 176 | 247, 255, 252, 248, 96, 0, 0, 0, // 104 177 | 0, 0, 0, 0, 0, 0, 0, 128, // 105 178 | 128, 0, 0, 0, 0, 0, 0, 192, // 106 179 | 192, 0, 0, 0, 0, 0, 0, 0, // 107 180 | }; 181 | 182 | it_object ImpulseLogo = { 183 | .redefine_characters = { 184 | 6, // Object type 6 185 | 256, // First char to define - label: LogoCharacter 186 | 108, 187 | ImpulseLogoChars, 188 | } 189 | }; 190 | 191 | it_object AutoDetectText = { 192 | .text = { 193 | 1, 194 | 32, 26, 195 | 0x20, 196 | "Sound Card Setup", 197 | } 198 | }; 199 | 200 | it_object CallAutoDetect = { 201 | .call_far_function = { 202 | 8, 203 | Music_ShowAutoDetectSoundCard, 204 | } 205 | }; 206 | 207 | it_object AutoContinueButton = { 208 | .button = { 209 | 2, // Object type 2 210 | -1, -1, -1, -1, 211 | 0, // Button usage type 212 | 0, 0, // ???? 213 | 4, // New List 214 | //0, 0, Glbl_F9, NULL, 215 | 0, 0, NULL, NULL, 216 | 32, 31, 47, 33, // Left/Top/Right/Bottom 217 | 8, // Box initial style 218 | 0, // Button Up 219 | " Continue", 220 | } 221 | }; 222 | 223 | it_object NBMBox = { 224 | .box = { 225 | 0, 226 | 25, 25, 54, 32, 227 | 3, 228 | } 229 | }; 230 | 231 | it_object OKButton = { 232 | .button = { 233 | 2, 234 | -1, -1, -1, -1, 235 | 0, 236 | 0, 0, 237 | 0, 238 | 0, // Returns 0 239 | 0, NULL, NULL, 240 | 35, 29, 44, 31, 241 | 8, 242 | 0, 243 | " OK", 244 | } 245 | }; 246 | 247 | it_object OOSoundCardMemoryText = { 248 | .text = { 249 | 1, 250 | 27, 27, 251 | 0x20, 252 | "Insufficient Soundcard RAM", 253 | } 254 | }; 255 | 256 | it_object FillHeader = { 257 | .call_far_function = { 258 | 8, 259 | NULL,//PE_FillHeader, 260 | } 261 | }; 262 | 263 | it_object SongLengthText = { 264 | .text = { 265 | 1, 266 | 27, 27, 267 | 0x20, 268 | "Total song time: ", 269 | } 270 | }; 271 | 272 | it_object ShowTime = { 273 | .call_far_function = { 274 | 8, 275 | Music_ShowTime, 276 | } 277 | }; 278 | 279 | it_objlist_6 O1_AutoDetectList = { 280 | 6, 0, //ESCContinueList, 281 | { 282 | &AboutBox, 283 | &ImpulseLogo, 284 | &AutoMiniBox, 285 | &AboutText, 286 | &AutoDetectText, 287 | &CallAutoDetect, 288 | &AutoContinueButton, 289 | NULL, 290 | }, 291 | }; 292 | 293 | it_objlist_2 O1_OutOfSoundCardMemoryList = { 294 | 2, 0, //ESCReturnList, 295 | { 296 | &NBMBox, 297 | &OOSoundCardMemoryText, 298 | &OKButton, 299 | &FillHeader, 300 | NULL, 301 | } 302 | }; 303 | 304 | it_objlist_2 O1_ShowTime = { 305 | 2, 0, //ESCReturnList, 306 | { 307 | &NBMBox, 308 | &ShowTime, 309 | &OKButton, 310 | &SongLengthText, 311 | NULL, 312 | } 313 | }; 314 | 315 | -------------------------------------------------------------------------------- /src/sdriver/drv_oss.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014, Jeffrey Lim. All Rights Reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | 3. The name of the author may not be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 19 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 20 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #include "it_struc.h" 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | static it_drvdata drv; 37 | static int is_initialised = 0; 38 | static int tempo = 125; 39 | static int ossfmt = AFMT_S16_LE; 40 | static int freq = 44100; 41 | static int stereo = 1; 42 | static int tper = 882; 43 | static int dsp = -1; 44 | static int32_t mixbuf[44100*2]; 45 | static int16_t outbuf[44100*2]; 46 | 47 | static const char *drv_oss_DriverDetectCard(it_engine *ite, const char *dname, uint16_t AL, uint16_t version) 48 | { 49 | return NULL; 50 | } 51 | 52 | static const char *drv_oss_DriverInitSound(it_engine *ite) 53 | { 54 | return NULL; 55 | } 56 | 57 | int drv_oss_DriverUninitSound(it_engine *ite) 58 | { 59 | return 0; 60 | } 61 | 62 | static inline void kill_channel(it_engine *ite, it_slave *slave) 63 | { 64 | //slave->Flags &= 0x788D; 65 | slave->Flags = 0x0200; 66 | slave->LpD = 0; 67 | 68 | if((slave->HCN & 0x80) == 0) 69 | ite->chn[slave->HCN].Flags &= ~4; 70 | } 71 | 72 | static inline int update_offs(it_engine *ite, it_slave *slave, int32_t *offs, int32_t *oferr, int32_t *nfreq, const int32_t lpbeg, const int32_t lpend) 73 | { 74 | // TODO: use the actual mixer code (it's faster than this approach) 75 | // it's also possible that the ping pong stuff is completely broken now D: 76 | // --GM 77 | *oferr += *nfreq; 78 | *offs += *oferr>>16; 79 | *oferr &= 0xFFFF; 80 | 81 | if((slave->LpM & 24) == 24 && slave->LpD != 0 && (*offs < lpbeg)) 82 | { 83 | *offs = lpbeg - *offs; 84 | if(lpend <= lpbeg) 85 | { 86 | // IT mixer doesn't kill here 87 | // Temporary measure pending IT mixer port 88 | kill_channel(ite, slave); 89 | return 1; 90 | } 91 | 92 | *offs %= (lpend-lpbeg)*2; 93 | if(*offs < (lpend-lpbeg)) 94 | { 95 | slave->LpD = 0; 96 | if(*nfreq < 0) *nfreq = -*nfreq; 97 | *offs += lpbeg; 98 | } else { 99 | *offs = (lpend - lpbeg) - *offs; 100 | *offs += lpend - 1; 101 | } 102 | } 103 | 104 | if(*offs < 0) 105 | { 106 | if((slave->LpM & 24) != 24) 107 | { 108 | kill_channel(ite, slave); 109 | slave->LpD = 0; 110 | return 1; 111 | } 112 | 113 | *offs = 0; 114 | if(*nfreq < 0) *nfreq = -*nfreq; 115 | slave->LpD = 0; 116 | } 117 | 118 | if(*offs >= lpend) 119 | { 120 | if((slave->LpM & 8) == 0) 121 | { 122 | kill_channel(ite, slave); 123 | return 1; 124 | } 125 | 126 | if((slave->LpM & 24) == 24) 127 | { 128 | if(lpend <= lpbeg) 129 | { 130 | // IT mixer doesn't kill here 131 | // Temporary measure pending IT mixer port 132 | kill_channel(ite, slave); 133 | return 1; 134 | } 135 | 136 | *offs -= lpend; 137 | *offs %= (lpend-lpbeg)*2; 138 | if(*offs >= (lpend-lpbeg)) 139 | { 140 | *offs -= (lpend - lpbeg); 141 | *offs += lpbeg; 142 | } else { 143 | slave->LpD = 1; 144 | 145 | *offs = lpend - *offs - 1; 146 | 147 | if(*nfreq > 0) *nfreq = -*nfreq; 148 | } 149 | 150 | } else { 151 | if(lpend <= lpbeg) 152 | { 153 | // IT mixer doesn't kill here 154 | // Temporary measure pending IT mixer port 155 | kill_channel(ite, slave); 156 | return 1; 157 | } 158 | 159 | *offs -= lpend; 160 | *offs %= (lpend-lpbeg); 161 | *offs += lpbeg; 162 | } 163 | } 164 | 165 | if(*offs < 0 || *offs >= lpend) 166 | { 167 | kill_channel(ite, slave); 168 | return 1; 169 | } 170 | 171 | return 0; 172 | 173 | } 174 | 175 | static int drv_oss_DriverPoll(it_engine *ite, uint16_t PlayMode, uint16_t CurrentPattern) 176 | { 177 | it_host *chn; 178 | it_slave *slave; 179 | int i, j; 180 | 181 | uint16_t cx; 182 | it_slave *si; 183 | uint16_t ax; 184 | 185 | Update(ite, &cx, &si, &ax); 186 | //printf("%i %i %i %i\n", cx, &ite->slave[0] - si, ax, ite->CurrentRow); 187 | printf("%i %i %i\n", ite->ProcessOrder, ite->CurrentPattern, ite->CurrentRow); 188 | 189 | int tsleep = (1000000*10)/(tempo*4); 190 | tper = (freq*10)/(tempo*4); 191 | 192 | if(dsp == -1) 193 | { 194 | dsp = open("/dev/dsp", O_WRONLY); 195 | assert(dsp > 2); 196 | ioctl(dsp, SNDCTL_DSP_SETFMT, &ossfmt); 197 | assert(ossfmt == AFMT_S16_LE); 198 | ioctl(dsp, SNDCTL_DSP_SPEED, &freq); 199 | ioctl(dsp, SNDCTL_DSP_STEREO, &stereo); 200 | printf("OSS opened: fmt=%i, freq=%i, chns=%i\n", ossfmt, freq, 201 | (stereo ? 2 : 1)); 202 | } 203 | 204 | memset(mixbuf, 0, tper*(stereo ? 2 : 1)*4); 205 | memset(outbuf, 0, tper*(stereo ? 2 : 1)*2); 206 | 207 | for(i = 0; i < ite->NumChannels; i++) 208 | { 209 | slave = &ite->slave[i]; 210 | if((slave->Flags & 1) != 0 && (slave->Flags & 0x0200) == 0) 211 | { 212 | // TODO: get the damn thing to behave 213 | 214 | //it_sample *smp = &ite->smp[slave->Smp]; 215 | //printf("smp %i %i %02X\n", slave->Smp, smp->Length, smp->Flg); 216 | int32_t offs = (int32_t)slave->Sample_Offset; 217 | int32_t oferr = (int32_t)slave->SmpErr; 218 | int32_t lpbeg = (int32_t)slave->Loop_Beginning; 219 | int32_t lpend = (int32_t)slave->Loop_End; 220 | int32_t nfreq = (int32_t)slave->Frequency; 221 | 222 | int32_t vol = slave->_16bVol; 223 | vol *= ite->hdr.MV; 224 | vol >>= 8; 225 | 226 | int32_t lvol = vol; 227 | int32_t rvol = vol; 228 | 229 | //printf("pan %i\n", slave->FPP); 230 | if(slave->FPP == 100) 231 | rvol = -rvol; 232 | else if(slave->FPP < 32) 233 | rvol = (rvol * slave->FPP) >> 5; 234 | else 235 | lvol = (lvol * (64 - slave->FPP)) >> 5; 236 | 237 | // TODO: fix bugs in actual thing 238 | //printf("%i %i %i %i\n", slave->Vol, slave->CVl, slave->SVl, ite->GlobalVolume); 239 | 240 | nfreq = (((int64_t)nfreq) << (int64_t)16) / (int64_t)freq; 241 | 242 | if(slave->LpD == 1) nfreq = -nfreq; 243 | 244 | //if(lpend == 0) lpend = smp->Length; 245 | 246 | //lpend = 10000; 247 | 248 | if(ite->SamplePointer[slave->Smp] == NULL) 249 | { 250 | kill_channel(ite, slave); 251 | break; 252 | 253 | } else if(stereo != 0 && slave->Bit != 0) { 254 | int16_t *data = (int16_t *)ite->SamplePointer[slave->Smp]; 255 | 256 | for(j = 0; j < tper*2; j+=2) 257 | { 258 | if(update_offs(ite, slave, &offs, &oferr, &nfreq, lpbeg, lpend) != 0) 259 | break; 260 | 261 | mixbuf[j+0] -= (lvol*(int32_t)data[offs])>>14; 262 | mixbuf[j+1] -= (rvol*(int32_t)data[offs])>>14; 263 | } 264 | 265 | } else if(stereo != 0 && slave->Bit == 0) { 266 | 267 | int8_t *data = (int8_t *)ite->SamplePointer[slave->Smp]; 268 | for(j = 0; j < tper*2; j+=2) 269 | { 270 | if(update_offs(ite, slave, &offs, &oferr, &nfreq, lpbeg, lpend) != 0) 271 | break; 272 | 273 | mixbuf[j+0] -= (lvol*(int32_t)data[offs])>>(14-8); 274 | mixbuf[j+1] -= (rvol*(int32_t)data[offs])>>(14-8); 275 | } 276 | } else if(stereo == 0 && slave->Bit != 0) { 277 | int16_t *data = (int16_t *)ite->SamplePointer[slave->Smp]; 278 | 279 | for(j = 0; j < tper; j++) 280 | { 281 | if(update_offs(ite, slave, &offs, &oferr, &nfreq, lpbeg, lpend) != 0) 282 | break; 283 | 284 | mixbuf[j] -= (vol*(int32_t)data[offs])>>14; 285 | } 286 | 287 | } else { 288 | int8_t *data = (int8_t *)ite->SamplePointer[slave->Smp]; 289 | for(j = 0; j < tper; j++) 290 | { 291 | if(update_offs(ite, slave, &offs, &oferr, &nfreq, lpbeg, lpend) != 0) 292 | break; 293 | 294 | mixbuf[j] -= (vol*(int32_t)data[offs])>>(14-8); 295 | } 296 | } 297 | 298 | slave->Sample_Offset = offs; 299 | slave->SmpErr = oferr; 300 | 301 | } 302 | 303 | // test 304 | if(0) 305 | { 306 | if((slave->Flags & 0x0200) != 0 && (slave->Flags & 1) != 0) 307 | { 308 | printf("Drop channel\n"); 309 | slave->Flags &= ~1; 310 | } 311 | 312 | } 313 | 314 | slave->Flags &= 0x788D; // no idea why this does it but anyway --GM 315 | 316 | //printf("%i %i %i\n", offs, lpbeg, lpend); 317 | 318 | /* 319 | if(slave->Flags != 0) 320 | printf(" %02X:%04X/%p", i, slave->Flags, ite->SamplePointer[slave->Smp]); 321 | */ 322 | } 323 | //printf("\n"); 324 | 325 | for(i = 0; i < tper*(stereo != 0 ? 2 : 1); i++) 326 | { 327 | int32_t v = mixbuf[i]; 328 | 329 | if(v > 0x7FFF) v = 0x7FFF; 330 | if(v < -0x7FFF) v = -0x7FFF; 331 | 332 | outbuf[i] = v; 333 | } 334 | 335 | write(dsp, outbuf, tper*2*(stereo != 0 ? 2 : 1)); 336 | //usleep(tsleep); 337 | return 0; 338 | } 339 | 340 | static int drv_oss_DriverSetTempo(it_engine *ite, uint16_t Tempo) 341 | { 342 | printf("tempo %i\n", Tempo); 343 | tempo = Tempo; 344 | return 0; 345 | } 346 | 347 | static int drv_oss_DriverSetMixVolume(it_engine *ite, uint16_t MixVolume) 348 | { 349 | return 0; 350 | } 351 | 352 | static int drv_oss_DriverSetStereo(it_engine *ite, uint16_t Stereo) 353 | { 354 | return 0; 355 | } 356 | 357 | static int drv_oss_DriverReleaseSample(it_engine *ite, it_sample *smp) 358 | { 359 | return 0; 360 | } 361 | 362 | static int drv_oss_DriverMIDIOut(it_engine *ite, uint8_t al) 363 | { 364 | printf("MIDI %02X\n", al); 365 | return 0; 366 | } 367 | 368 | static int drv_oss_DriverGetWaveform(it_engine *ite) 369 | { 370 | return 0; 371 | } 372 | 373 | it_drvdata *drv_oss_init(it_engine *ite) 374 | { 375 | if(is_initialised) 376 | return &drv; 377 | 378 | drv.BasePort = 0xFFFF; 379 | drv.IRQ = 0xFFFF; 380 | drv.DMA = 0xFFFF; 381 | drv.CmdLineMixSpeed = 0; 382 | 383 | drv.CmdLineDMASize = 1024; 384 | drv.ReverseChannels = 0; 385 | drv.DriverMaxChannels = 256; 386 | drv.StopEndOfPlaySection = 0; 387 | drv.DefaultChannels = 256; 388 | //drv.DefaultChannels = 10; 389 | 390 | drv.DriverFlags = 0; // no midi out, no hiqual (at least for now) 391 | // both do appear to be supported however (well, to some extent) 392 | 393 | drv.DriverDetectCard = drv_oss_DriverDetectCard; 394 | drv.DriverInitSound = drv_oss_DriverInitSound; 395 | 396 | drv.DriverUninitSound = drv_oss_DriverUninitSound; 397 | 398 | drv.DriverPoll = drv_oss_DriverPoll; 399 | drv.DriverSetTempo = drv_oss_DriverSetTempo; 400 | drv.DriverSetMixVolume = drv_oss_DriverSetMixVolume; 401 | drv.DriverSetStereo = drv_oss_DriverSetStereo; 402 | 403 | drv.DriverReleaseSample = drv_oss_DriverReleaseSample; 404 | 405 | drv.DriverMIDIOut = drv_oss_DriverMIDIOut; 406 | drv.DriverGetWaveform = drv_oss_DriverGetWaveform; 407 | 408 | return &drv; 409 | } 410 | 411 | 412 | -------------------------------------------------------------------------------- /src/ui/it_m.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014, Jeffrey Lim. All Rights Reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | 3. The name of the author may not be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 19 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 20 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #include "it_struc.h" 30 | 31 | void M_FunctionHandler(it_engine *ite, void *ObjectList) 32 | { 33 | //ARG ObjectList:DWord 34 | //Push BP 35 | //Mov BP, SP 36 | 37 | /* 38 | MouseSaveEvents(); 39 | 40 | M_FunctionHandler1: 41 | // Draw all objects in list 42 | al = GetKeyboardLock(); 43 | Cmp AL, 2 44 | JE MouseInput1 45 | 46 | Call MouseClearEvents 47 | 48 | LDS SI, ObjectList // DS:SI points to object list 49 | Add SI, 6 // Skip pass list header 50 | Xor AX, AX 51 | 52 | M_FunctionHandler2: 53 | Cmp Word Ptr [SI], 0 // DS:SI points to an offset of 54 | JE M_FunctionHandler4 // an object 55 | 56 | M_FunctionHandler3: 57 | Push AX ; AX = object number 58 | Push DS 59 | Push SI 60 | Push BP 61 | 62 | LES DI, ObjectList ; ES:DI points to object list 63 | Mov SI, [SI] ; DS:SI points to object 64 | Mov BX, [SI] ; BX = object type 65 | Mov CL, 2 66 | ShL BX, CL 67 | 68 | Call DWord Ptr [DrawObjectList+BX] 69 | 70 | Pop BP 71 | Pop SI ; DS:SI Points to an offset of 72 | Pop DS ; an object 73 | Pop AX 74 | Inc AX 75 | Add SI, 2 ; Advance Pointer 76 | Jmp M_FunctionHandler2 ; Next Object 77 | 78 | M_FunctionHandler4: ; Call Prefunction for object 79 | LDS SI, ObjectList ; DS:SI points to object list 80 | Mov AX, [SI] ; AX = Active object number 81 | LEA SI, [ESI+EAX*2+6] ; Skip pas list header (+6) 82 | ; AX = object number 83 | 84 | Cmp Word Ptr [SI], 0 ; if list doesn't point to 85 | JE M_FunctionHandler21 ; anything, don't call prefunc 86 | 87 | M_FunctionHandler20: 88 | Mov SI, [SI] ; DS:SI points to object 89 | Mov BX, [SI] ; BX = object type 90 | ShL BX, 2 91 | 92 | Push BP 93 | Call DWord Ptr [PreFunctionList+BX] 94 | Pop BP 95 | 96 | M_FunctionHandler21: 97 | 98 | #if TUTORIAL 99 | Glbl_TutorialHandler(ite); 100 | #endif 101 | 102 | Call S_UpdateScreen 103 | 104 | M_FunctionHandler5: ; Input... 105 | ; Call K_IsAnyKeyDown 106 | ; And AL, AL 107 | ; JNZ M_KeyBoardInput1 108 | 109 | MouseInput1: 110 | Call MouseInput ; returns 0 if nothing 111 | ; 1 if input (BX, CX, DX set) 112 | ; 2 if no input, but keyboard 113 | ; locked 114 | Cmp AX, 1 115 | JB M_KeyBoardInput1 116 | JA M_FunctionHandler6 ; IdleList 117 | ; Handle postobject, of 118 | ; object BX 119 | 120 | Mov AX, DI 121 | Cmp BX, 0FFFFh 122 | JE M_FunctionHandler23 123 | 124 | LES DI, ObjectList ; ES:DI points to object list 125 | Push ES 126 | Pop DS 127 | 128 | Mov [DI], BX ; Object number in BX. 129 | LEA BX, [EBX*2+EDI+6] ; ES:BX points to offset of 130 | ; active object. 131 | 132 | Mov SI, [BX] ; DS:SI points to object 133 | 134 | Mov SI, [SI] ; SI = object type of active obj 135 | ShL SI, 2 136 | 137 | Push BP 138 | Call DWord Ptr [PostFunctionList+SI] 139 | Pop BP 140 | Jmp M_FunctionHandler23 141 | 142 | M_KeyBoardInput1: 143 | Call MIDIBufferEmpty 144 | JAE M_FunctionHandler8 145 | 146 | Call K_IsKeyWaiting 147 | 148 | Test AX, AX 149 | JNZ M_FunctionHandler8 150 | ; Check for mouse info... 151 | 152 | M_FunctionHandler6: ; IdleList 153 | Cmp CS:ReleaseTimeSlice, 0 154 | JE NoReleaseTimeSlice 155 | 156 | Mov AX, 1680h 157 | Int 2Fh 158 | 159 | NoReleaseTimeSlice: 160 | ; StI 161 | 162 | LDS SI, ObjectList ; DS:SI points to object list 163 | Add SI, 2 ; DS:SI points to idle list 164 | 165 | Cmp Word Ptr [SI], 0 166 | JE M_FunctionHandler5 ; If Offset of IdleList = 0, 167 | ; check for another key 168 | 169 | M_FunctionHandler7: 170 | Mov SI, [SI] 171 | Xor BX, BX ; Clear flag. 172 | 173 | M_FunctionHandler19: 174 | Cmp Word Ptr [SI], 0 175 | JNE M_FunctionHandler18 176 | 177 | Cmp Word Ptr [SI+2], 0 178 | JE M_FunctionHandler29 179 | 180 | M_FunctionHandler18: 181 | Push SI 182 | Push BX 183 | Push DS 184 | Push BP 185 | 186 | Call DWord Ptr [SI] 187 | 188 | Pop BP 189 | Pop DS 190 | Pop BX 191 | 192 | Cmp AX, 5 193 | JE M_FunctionHandlerIdleCommand 194 | 195 | Pop SI 196 | 197 | Add SI, 4 198 | 199 | Or BX, AX 200 | Jmp M_FunctionHandler19 201 | 202 | M_FunctionHandlerIdleCommand: 203 | Pop AX ; Pull off SI from the stack 204 | Mov AX, DI 205 | Jmp M_FunctionHandler10 206 | ; Mov SI, 1 207 | ; Jmp M_FunctionHandler16 208 | 209 | M_FunctionHandler29: 210 | Test BX, BX 211 | JZ M_FunctionHandler5 212 | 213 | Jmp M_FunctionHandler1 214 | 215 | M_FunctionHandler8: 216 | Call K_GetKey ; CX = Keyboard Input Data 217 | ; DX = Translated Input Data 218 | ; else MIDI input if CL = 0 219 | 220 | M_FunctionHandler9: 221 | LES DI, ObjectList ; ES:DI points to object list 222 | Push ES 223 | Pop DS 224 | 225 | Mov BX, [DI] ; BX = active object number 226 | LEA BX, [EDI+EBX*2+6] ; ES:BX points to offset of 227 | ; active object. 228 | Xor AX, AX 229 | 230 | Cmp Word Ptr [BX], 0 231 | JE M_FunctionHandler23 232 | 233 | M_FunctionHandler22: 234 | Mov SI, [BX] ; DS:SI points to object 235 | 236 | Mov SI, [SI] ; SI = object type of active obj 237 | ShL SI, 2 238 | 239 | Push BP 240 | Call DWord Ptr [PostFunctionList+SI] 241 | Pop BP 242 | 243 | M_FunctionHandler23: 244 | Push DS 245 | Push SI 246 | 247 | LDS SI, ObjectList 248 | Add SI, 4 249 | Mov SI, [SI] 250 | Mov Word Ptr CS:GlobalKeyList+2, DS 251 | Mov Word Ptr CS:GlobalKeyList, SI 252 | 253 | Pop SI 254 | Pop DS 255 | 256 | ; Xor BX, BX ; Extra key list starts at 0 257 | 258 | M_FunctionHandler10: 259 | Cmp AX, 1 260 | JB M_FunctionHandler11 ; If AX = 0 261 | JE M_FunctionHandler1 ; Redraw screen if AX = 1 262 | 263 | Cmp AX, 3 264 | JB M_FunctionHandler4 ; Goto preobject if AX = 2 265 | JE M_FunctionHandler5 ; Get next input 266 | 267 | Cmp AX, 5 ; New list 268 | JE M_FunctionHandler16 269 | JA M_FunctionHandler11 ; If > 5 270 | 271 | Call MouseRestoreEvents 272 | 273 | Pop BP 274 | Ret 4 275 | 276 | M_FunctionHandler16: 277 | Mov Word Ptr Offset ObjectList, DX 278 | Mov Word Ptr Offset ObjectList+2, CX 279 | Mov AX, SI 280 | 281 | Jmp M_FunctionHandler10 282 | 283 | M_FunctionHandler11: 284 | LDS SI, CS:GlobalKeyList 285 | 286 | Cmp Word Ptr [SI], 0 287 | JE M_FunctionHandler4 288 | 289 | M_FunctionHandler12: 290 | LodsB 291 | Mov BX, DX 292 | Cmp AL, 1 293 | JE M_FunctionHandler13 ; Keycode compare (1) 294 | Mov BX, CX 295 | JB M_FunctionHandler13 ; Scancode compare (0) 296 | 297 | And BX, 1FFh 298 | 299 | Cmp AL, 3 300 | JB M_FunctionHandlerAlt ; Alt-keycode compare (2) 301 | JE M_FunctionHandlerCtrl ; Ctrl-keycode compare (3) 302 | 303 | Cmp AL, 5 304 | JB M_FunctionHandlerForced ; Always call function (4) 305 | JE M_FunctionHandlerNewListNear ; Chain to new list (5) 306 | 307 | Cmp AL, 7 308 | JB M_FunctionHandlerShift ; Shift-keycode compare (6) 309 | JE M_FunctionHandlerNewListFar ; Chain to far list (7) 310 | 311 | Cmp AL, 9 312 | JB M_FunctionHandlerCapCheck ; Capitalised keycode (8) 313 | JE M_FunctionHandlerMIDI ; MIDI message (9) 314 | 315 | ; Jmp M_FunctionHandler1 316 | Jmp M_FunctionHandler4 ; Undefined compare.. 317 | ; ; -> end of list 318 | 319 | M_FunctionHandlerAlt: 320 | Test CH, 60h 321 | JZ M_FunctionHandler14 322 | Jmp M_FunctionHandler13 323 | 324 | M_FunctionHandlerCtrl: 325 | Test CH, 18h 326 | JZ M_FunctionHandler14 327 | Jmp M_FunctionHandler13 328 | 329 | M_FunctionHandlerShift: 330 | Test CH, 6h 331 | JZ M_FunctionHandler14 332 | Jmp M_FunctionHandler13 333 | 334 | M_FunctionHandlerNewListNear: 335 | LodsW 336 | Mov Word Ptr CS:GlobalKeyList, AX 337 | Jmp M_FunctionHandler11 338 | 339 | M_FunctionHandlerNewListFar: 340 | LodsD 341 | Mov CS:GlobalKeyList, EAX 342 | Jmp M_FunctionHandler11 343 | 344 | M_FunctionHandlerForced: 345 | LodsW 346 | Jmp M_FunctionHandler26 347 | 348 | M_FunctionHandlerCapCheck: ; Capital OK? (8) 349 | Mov BX, DX 350 | Cmp BX, 'A' 351 | JB M_FunctionHandler14 352 | Cmp BX, 'z' 353 | JA M_FunctionHandler14 354 | Cmp BX, 'a' 355 | JB M_FunctionHandlerCapCheck1 356 | 357 | Sub BL, 32 358 | 359 | M_FunctionHandlerCapCheck1: 360 | Jmp M_FunctionHandler13 361 | 362 | M_FunctionHandlerMIDI: 363 | Test CL, CL 364 | JNZ M_FunctionHandler14 365 | Mov BX, CX 366 | And BX, 0F000h 367 | Jmp M_FunctionHandlerCheck 368 | 369 | M_FunctionHandler13: 370 | Test CL, CL 371 | JZ M_FunctionHandler14 372 | 373 | M_FunctionHandlerCheck: 374 | LodsW 375 | Cmp BX, AX 376 | JNE M_FunctionHandler14 377 | 378 | M_FunctionHandler26: 379 | LES DI, ObjectList ; ES:DI points to object list 380 | Push BP 381 | Call DWord Ptr [SI] 382 | Pop BP 383 | Jmp M_FunctionHandler15 384 | 385 | M_FunctionHandler14: 386 | Xor AX, AX 387 | 388 | M_FunctionHandler15: 389 | Add Word Ptr CS:GlobalKeyList, 7 390 | Jmp M_FunctionHandler10 391 | */ 392 | } 393 | 394 | void M_Object1List(it_engine *ite, void *di, int cx) 395 | { 396 | if(cx != -1) 397 | *(int *)di = cx; 398 | 399 | M_FunctionHandler(ite, di); 400 | } 401 | 402 | void M_Object1ListDefault(it_engine *ite, void *di) 403 | { 404 | return M_Object1List(ite, di, -1); 405 | } 406 | 407 | -------------------------------------------------------------------------------- /src/sdriver/drv_sdl.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014, Jeffrey Lim. All Rights Reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | 3. The name of the author may not be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 19 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 20 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #include "it_struc.h" 30 | 31 | #include 32 | 33 | static it_drvdata drv; 34 | static int is_initialised = 0; 35 | static int tempo = 125; 36 | static SDL_AudioSpec sdl_aspec; 37 | static int freq = 44100; 38 | static int stereo = 1; 39 | static int tper = 882; 40 | static int32_t mixbuf[44100*2]; 41 | //static int16_t outbuf[44100*2]; 42 | #define OUTSIZE 32768 43 | static const int outsize = OUTSIZE; 44 | static int16_t outring[OUTSIZE][2]; 45 | static volatile int outoffs_r = 0; 46 | static volatile int outoffs_w = 0; 47 | 48 | void poll_audio_sdl(void *ud, Uint8 *stream, int len) 49 | { 50 | int i; 51 | int real_len = len/4; 52 | int16_t *real_out = (int16_t *)stream; 53 | 54 | int ooffs = outoffs_r; 55 | int olen = (outoffs_w - ooffs); 56 | if(olen < 0) { 57 | olen += outsize; 58 | } 59 | //printf("olen = %d / real_len = %d\n", olen, real_len); 60 | for(i = 0; i < real_len && olen > 0; i++) { 61 | real_out[i*2+0] = outring[ooffs][0]; 62 | real_out[i*2+1] = outring[ooffs][1]; 63 | ooffs += 1; 64 | olen -= 1; 65 | if(ooffs >= outsize) { 66 | ooffs -= outsize; 67 | } 68 | } 69 | outoffs_r = ooffs; 70 | 71 | for(; i < real_len; i++) { 72 | real_out[i*2+0] = 0; 73 | real_out[i*2+1] = 0; 74 | } 75 | } 76 | 77 | static const char *drv_sdl_DriverDetectCard(it_engine *ite, const char *dname, uint16_t AL, uint16_t version) 78 | { 79 | return NULL; 80 | } 81 | 82 | static const char *drv_sdl_DriverInitSound(it_engine *ite) 83 | { 84 | if(SDL_Init(SDL_INIT_AUDIO)) { 85 | return "Audio init failed"; 86 | } 87 | 88 | sdl_aspec.freq = freq; 89 | sdl_aspec.format = AUDIO_S16SYS; 90 | sdl_aspec.channels = (stereo ? 2 : 1); 91 | sdl_aspec.samples = 4096; 92 | sdl_aspec.callback = poll_audio_sdl; 93 | 94 | if(SDL_OpenAudio(&sdl_aspec, NULL)) { 95 | return "Audio open failed"; 96 | } 97 | 98 | SDL_PauseAudio(0); 99 | return NULL; 100 | } 101 | 102 | int drv_sdl_DriverUninitSound(it_engine *ite) 103 | { 104 | SDL_Quit(); 105 | return 0; 106 | } 107 | 108 | static inline void kill_channel(it_engine *ite, it_slave *slave) 109 | { 110 | //slave->Flags &= 0x788D; 111 | slave->Flags = 0x0200; 112 | slave->LpD = 0; 113 | 114 | if((slave->HCN & 0x80) == 0) 115 | ite->chn[slave->HCN].Flags &= ~4; 116 | } 117 | 118 | static inline int update_offs(it_engine *ite, it_slave *slave, int32_t *offs, int32_t *oferr, int32_t *nfreq, const int32_t lpbeg, const int32_t lpend) 119 | { 120 | // TODO: use the actual mixer code (it's faster than this approach) 121 | // it's also psdlible that the ping pong stuff is completely broken now D: 122 | // --GM 123 | *oferr += *nfreq; 124 | *offs += *oferr>>16; 125 | *oferr &= 0xFFFF; 126 | 127 | if((slave->LpM & 24) == 24 && slave->LpD != 0 && (*offs < lpbeg)) 128 | { 129 | *offs = lpbeg - *offs; 130 | if(lpend <= lpbeg) 131 | { 132 | // IT mixer doesn't kill here 133 | // Temporary measure pending IT mixer port 134 | kill_channel(ite, slave); 135 | return 1; 136 | } 137 | 138 | *offs %= (lpend-lpbeg)*2; 139 | if(*offs < (lpend-lpbeg)) 140 | { 141 | slave->LpD = 0; 142 | if(*nfreq < 0) *nfreq = -*nfreq; 143 | *offs += lpbeg; 144 | } else { 145 | *offs = (lpend - lpbeg) - *offs; 146 | *offs += lpend - 1; 147 | } 148 | } 149 | 150 | if(*offs < 0) 151 | { 152 | if((slave->LpM & 24) != 24) 153 | { 154 | kill_channel(ite, slave); 155 | slave->LpD = 0; 156 | return 1; 157 | } 158 | 159 | *offs = 0; 160 | if(*nfreq < 0) *nfreq = -*nfreq; 161 | slave->LpD = 0; 162 | } 163 | 164 | if(*offs >= lpend) 165 | { 166 | if((slave->LpM & 8) == 0) 167 | { 168 | kill_channel(ite, slave); 169 | return 1; 170 | } 171 | 172 | if((slave->LpM & 24) == 24) 173 | { 174 | if(lpend <= lpbeg) 175 | { 176 | // IT mixer doesn't kill here 177 | // Temporary measure pending IT mixer port 178 | kill_channel(ite, slave); 179 | return 1; 180 | } 181 | 182 | *offs -= lpend; 183 | *offs %= (lpend-lpbeg)*2; 184 | if(*offs >= (lpend-lpbeg)) 185 | { 186 | *offs -= (lpend - lpbeg); 187 | *offs += lpbeg; 188 | } else { 189 | slave->LpD = 1; 190 | 191 | *offs = lpend - *offs - 1; 192 | 193 | if(*nfreq > 0) *nfreq = -*nfreq; 194 | } 195 | 196 | } else { 197 | if(lpend <= lpbeg) 198 | { 199 | // IT mixer doesn't kill here 200 | // Temporary measure pending IT mixer port 201 | kill_channel(ite, slave); 202 | return 1; 203 | } 204 | 205 | *offs -= lpend; 206 | *offs %= (lpend-lpbeg); 207 | *offs += lpbeg; 208 | } 209 | } 210 | 211 | if(*offs < 0 || *offs >= lpend) 212 | { 213 | kill_channel(ite, slave); 214 | return 1; 215 | } 216 | 217 | return 0; 218 | 219 | } 220 | 221 | static int drv_sdl_DriverPoll(it_engine *ite, uint16_t PlayMode, uint16_t CurrentPattern) 222 | { 223 | it_host *chn; 224 | it_slave *slave; 225 | int i, j; 226 | 227 | uint16_t cx; 228 | it_slave *si; 229 | uint16_t ax; 230 | 231 | Update(ite, &cx, &si, &ax); 232 | //printf("%i %i %i %i\n", cx, &ite->slave[0] - si, ax, ite->CurrentRow); 233 | printf("%i %i %i\n", ite->ProcessOrder, ite->CurrentPattern, ite->CurrentRow); 234 | 235 | int tsleep = (1000000*10)/(tempo*4); 236 | tper = (freq*10)/(tempo*4); 237 | 238 | memset(mixbuf, 0, tper*(stereo ? 2 : 1)*4); 239 | //memset(outbuf, 0, tper*(stereo ? 2 : 1)*2); 240 | 241 | for(i = 0; i < ite->NumChannels; i++) 242 | { 243 | slave = &ite->slave[i]; 244 | if((slave->Flags & 1) != 0 && (slave->Flags & 0x0200) == 0) 245 | { 246 | // TODO: get the damn thing to behave 247 | 248 | //it_sample *smp = &ite->smp[slave->Smp]; 249 | //printf("smp %i %i %02X\n", slave->Smp, smp->Length, smp->Flg); 250 | int32_t offs = (int32_t)slave->Sample_Offset; 251 | int32_t oferr = (int32_t)slave->SmpErr; 252 | int32_t lpbeg = (int32_t)slave->Loop_Beginning; 253 | int32_t lpend = (int32_t)slave->Loop_End; 254 | int32_t nfreq = (int32_t)slave->Frequency; 255 | 256 | int32_t vol = slave->_16bVol; 257 | vol *= ite->hdr.MV; 258 | vol >>= 8; 259 | 260 | int32_t lvol = vol; 261 | int32_t rvol = vol; 262 | 263 | //printf("pan %i\n", slave->FPP); 264 | if(slave->FPP == 100) 265 | rvol = -rvol; 266 | else if(slave->FPP < 32) 267 | rvol = (rvol * slave->FPP) >> 5; 268 | else 269 | lvol = (lvol * (64 - slave->FPP)) >> 5; 270 | 271 | // TODO: fix bugs in actual thing 272 | //printf("%i %i %i %i\n", slave->Vol, slave->CVl, slave->SVl, ite->GlobalVolume); 273 | 274 | nfreq = (((int64_t)nfreq) << (int64_t)16) / (int64_t)freq; 275 | 276 | if(slave->LpD == 1) nfreq = -nfreq; 277 | 278 | //if(lpend == 0) lpend = smp->Length; 279 | 280 | //lpend = 10000; 281 | 282 | if(ite->SamplePointer[slave->Smp] == NULL) 283 | { 284 | kill_channel(ite, slave); 285 | break; 286 | 287 | } else if(stereo != 0 && slave->Bit != 0) { 288 | int16_t *data = (int16_t *)ite->SamplePointer[slave->Smp]; 289 | 290 | for(j = 0; j < tper*2; j+=2) 291 | { 292 | if(update_offs(ite, slave, &offs, &oferr, &nfreq, lpbeg, lpend) != 0) 293 | break; 294 | 295 | mixbuf[j+0] -= (lvol*(int32_t)data[offs])>>14; 296 | mixbuf[j+1] -= (rvol*(int32_t)data[offs])>>14; 297 | } 298 | 299 | } else if(stereo != 0 && slave->Bit == 0) { 300 | 301 | int8_t *data = (int8_t *)ite->SamplePointer[slave->Smp]; 302 | for(j = 0; j < tper*2; j+=2) 303 | { 304 | if(update_offs(ite, slave, &offs, &oferr, &nfreq, lpbeg, lpend) != 0) 305 | break; 306 | 307 | mixbuf[j+0] -= (lvol*(int32_t)data[offs])>>(14-8); 308 | mixbuf[j+1] -= (rvol*(int32_t)data[offs])>>(14-8); 309 | } 310 | } else if(stereo == 0 && slave->Bit != 0) { 311 | int16_t *data = (int16_t *)ite->SamplePointer[slave->Smp]; 312 | 313 | for(j = 0; j < tper; j++) 314 | { 315 | if(update_offs(ite, slave, &offs, &oferr, &nfreq, lpbeg, lpend) != 0) 316 | break; 317 | 318 | mixbuf[j] -= (vol*(int32_t)data[offs])>>14; 319 | } 320 | 321 | } else { 322 | int8_t *data = (int8_t *)ite->SamplePointer[slave->Smp]; 323 | for(j = 0; j < tper; j++) 324 | { 325 | if(update_offs(ite, slave, &offs, &oferr, &nfreq, lpbeg, lpend) != 0) 326 | break; 327 | 328 | mixbuf[j] -= (vol*(int32_t)data[offs])>>(14-8); 329 | } 330 | } 331 | 332 | slave->Sample_Offset = offs; 333 | slave->SmpErr = oferr; 334 | 335 | } 336 | 337 | // test 338 | if(0) 339 | { 340 | if((slave->Flags & 0x0200) != 0 && (slave->Flags & 1) != 0) 341 | { 342 | printf("Drop channel\n"); 343 | slave->Flags &= ~1; 344 | } 345 | 346 | } 347 | 348 | slave->Flags &= 0x788D; // no idea why this does it but anyway --GM 349 | 350 | //printf("%i %i %i\n", offs, lpbeg, lpend); 351 | 352 | /* 353 | if(slave->Flags != 0) 354 | printf(" %02X:%04X/%p", i, slave->Flags, ite->SamplePointer[slave->Smp]); 355 | */ 356 | } 357 | //printf("\n"); 358 | 359 | //SDL_LockAudio(); 360 | if(stereo) 361 | { 362 | //printf("per = %d / space: %d\n", tper, (outoffs_w - outoffs_r + outsize) % outsize); 363 | for(i = 0; i < tper*2; i += 2) 364 | { 365 | int32_t v0 = mixbuf[i+0]; 366 | int32_t v1 = mixbuf[i+1]; 367 | 368 | if(v0 > 0x7FFF) v0 = 0x7FFF; 369 | if(v0 < -0x7FFF) v0 = -0x7FFF; 370 | if(v1 > 0x7FFF) v1 = 0x7FFF; 371 | if(v1 < -0x7FFF) v1 = -0x7FFF; 372 | 373 | int old_outw = outoffs_w; 374 | int new_outw = (old_outw + 1) % outsize; 375 | while(outoffs_r == new_outw) { 376 | //SDL_UnlockAudio(); 377 | SDL_Delay(10); 378 | //SDL_LockAudio(); 379 | } 380 | outring[old_outw][0] = v0; 381 | outring[old_outw][1] = v1; 382 | outoffs_w = new_outw; 383 | } 384 | 385 | } else { 386 | for(i = 0; i < tper*1; i += 1) 387 | { 388 | int32_t v0 = mixbuf[i+0]; 389 | int32_t v1 = mixbuf[i+0]; 390 | 391 | if(v0 > 0x7FFF) v0 = 0x7FFF; 392 | if(v0 < -0x7FFF) v0 = -0x7FFF; 393 | if(v1 > 0x7FFF) v1 = 0x7FFF; 394 | if(v1 < -0x7FFF) v1 = -0x7FFF; 395 | 396 | int old_outw = outoffs_w; 397 | int new_outw = (old_outw + 1) % outsize; 398 | while(outoffs_r == new_outw) { 399 | //SDL_UnlockAudio(); 400 | SDL_Delay(10); 401 | //SDL_LockAudio(); 402 | } 403 | outring[old_outw][0] = v0; 404 | outring[old_outw][1] = v1; 405 | outoffs_w = new_outw; 406 | } 407 | } 408 | //SDL_UnlockAudio(); 409 | //usleep(1000); 410 | return 0; 411 | } 412 | 413 | static int drv_sdl_DriverSetTempo(it_engine *ite, uint16_t Tempo) 414 | { 415 | printf("tempo %i\n", Tempo); 416 | tempo = Tempo; 417 | return 0; 418 | } 419 | 420 | static int drv_sdl_DriverSetMixVolume(it_engine *ite, uint16_t MixVolume) 421 | { 422 | return 0; 423 | } 424 | 425 | static int drv_sdl_DriverSetStereo(it_engine *ite, uint16_t Stereo) 426 | { 427 | return 0; 428 | } 429 | 430 | static int drv_sdl_DriverReleaseSample(it_engine *ite, it_sample *smp) 431 | { 432 | return 0; 433 | } 434 | 435 | static int drv_sdl_DriverMIDIOut(it_engine *ite, uint8_t al) 436 | { 437 | printf("MIDI %02X\n", al); 438 | return 0; 439 | } 440 | 441 | static int drv_sdl_DriverGetWaveform(it_engine *ite) 442 | { 443 | return 0; 444 | } 445 | 446 | it_drvdata *drv_sdl_init(it_engine *ite) 447 | { 448 | if(is_initialised) 449 | return &drv; 450 | 451 | drv.BasePort = 0xFFFF; 452 | drv.IRQ = 0xFFFF; 453 | drv.DMA = 0xFFFF; 454 | drv.CmdLineMixSpeed = 0; 455 | 456 | drv.CmdLineDMASize = 1024; 457 | drv.ReverseChannels = 0; 458 | drv.DriverMaxChannels = 256; 459 | drv.StopEndOfPlaySection = 0; 460 | drv.DefaultChannels = 256; 461 | //drv.DefaultChannels = 10; 462 | 463 | drv.DriverFlags = 0; // no midi out, no hiqual (at least for now) 464 | // both do appear to be supported however (well, to some extent) 465 | 466 | drv.DriverDetectCard = drv_sdl_DriverDetectCard; 467 | drv.DriverInitSound = drv_sdl_DriverInitSound; 468 | 469 | drv.DriverUninitSound = drv_sdl_DriverUninitSound; 470 | 471 | drv.DriverPoll = drv_sdl_DriverPoll; 472 | drv.DriverSetTempo = drv_sdl_DriverSetTempo; 473 | drv.DriverSetMixVolume = drv_sdl_DriverSetMixVolume; 474 | drv.DriverSetStereo = drv_sdl_DriverSetStereo; 475 | 476 | drv.DriverReleaseSample = drv_sdl_DriverReleaseSample; 477 | 478 | drv.DriverMIDIOut = drv_sdl_DriverMIDIOut; 479 | drv.DriverGetWaveform = drv_sdl_DriverGetWaveform; 480 | 481 | return &drv; 482 | } 483 | 484 | 485 | -------------------------------------------------------------------------------- /src/include/it_struc.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014, Jeffrey Lim. All Rights Reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | 3. The name of the author may not be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 19 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 20 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | 37 | #include "switch.h" 38 | #include "network.h" 39 | #include "it_obj.h" 40 | 41 | #define Trace(s) puts(s) 42 | 43 | #define CREATENEWLOGFILE 0 44 | #define HOSTCHANNELSIZE 80 45 | #define SLAVECHANNELSIZE 128 46 | #define MAXSLAVECHANNELS 256 47 | #define NONOTE 0xFD 48 | 49 | #define MIDICOMMAND_START 0x0000 50 | #define MIDICOMMAND_STOP 0x0020 51 | #define MIDICOMMAND_TICK 0x0040 52 | #define MIDICOMMAND_PLAYNOTE 0x0060 53 | #define MIDICOMMAND_STOPNOTE 0x0080 54 | #define MIDICOMMAND_CHANGEVOLUME 0x00A0 55 | #define MIDICOMMAND_CHANGEPAN 0x00C0 56 | #define MIDICOMMAND_BANKSELECT 0x00E0 57 | #define MIDICOMMAND_PROGRAMSELECT 0x0100 58 | #define MIDICOMMAND_CHANGEPITCH 0xFFFF 59 | 60 | typedef struct it_host_s 61 | { 62 | // 0x0000 63 | uint16_t Flags; uint8_t Msk, Nte; 64 | uint8_t Ins, Vol, Cmd, CVal; 65 | uint8_t OCm, OVal, VCm, VVal; 66 | uint8_t MCh, MPr, Nt2, Smp; 67 | 68 | // 0x0010 69 | uint8_t DKL, EFG, O00, I00; 70 | uint8_t J00, M00, N00, P00; 71 | uint8_t Q00, T00, S00, OxH; 72 | uint8_t W00, VCE, GOE, SFx; 73 | 74 | // 0x0020 75 | uint8_t HCN, CUC, VSe, LTr; 76 | uint16_t SCOffst; uint8_t PLR, PLC; 77 | uint8_t PWF, PPo, PDp, PSp; 78 | uint8_t LPn, LVi, CP, CV; 79 | 80 | // 0x0030 81 | uint8_t VCh, TCD, Too, RTC; 82 | uint32_t Porta_Frequency; 83 | uint8_t VWF, VPo, VDp, VSp; 84 | uint8_t TWF, TPo, TDp, TSp; 85 | 86 | // 0x0040 87 | // Misc Effect Data...... 88 | int16_t _40, _42; 89 | int16_t _44; uint8_t _46, _47; 90 | uint8_t _48, _49, _4A, _4B; 91 | uint8_t _4C, _4D, _4E, _4F; 92 | 93 | } __attribute__((__packed__)) it_host; 94 | 95 | typedef struct it_slen_s 96 | { 97 | uint32_t EnvelopeValue; 98 | uint32_t EnvelopeDelta; 99 | uint16_t EnvPos, CurEnN; 100 | uint16_t NextET, filter; 101 | } __attribute__((__packed__)) it_slen; 102 | 103 | typedef struct it_slave_s 104 | { 105 | // 0x0000 106 | uint16_t Flags; 107 | uint8_t DeviceSpecific[8]; 108 | uint8_t LpM, LpD; 109 | uint32_t Left_Volume; 110 | 111 | // 0x0010 112 | uint32_t Frequency; 113 | uint32_t Frequency_Set; 114 | uint8_t Bit, ViP; uint16_t ViDepth; 115 | uint32_t RVol_MIDIFSet; 116 | 117 | // 0x0020 118 | uint8_t FV, Vol, VS, CVl; 119 | uint8_t SVl, FP; int16_t FadeOut; 120 | uint8_t DCT, DCA, Pan, PS; 121 | uint32_t OldSampleOffset; 122 | 123 | // 0x0030 124 | uint16_t InsOffs; uint8_t Nte, Ins; 125 | uint16_t SmpOffs; uint8_t Smp, FPP; 126 | int16_t HCOffst; uint8_t HCN, NNA; 127 | uint8_t MCh, MPr; uint8_t FCut, FRes; // 0x003E also 16-bit MBank 128 | 129 | // 0x0040 130 | uint32_t Loop_Beginning; 131 | uint32_t Loop_End; 132 | uint16_t SmpErr, _16bVol; 133 | uint32_t Sample_Offset; 134 | 135 | // 0x0050 136 | it_slen V; 137 | 138 | // 0x0060 139 | it_slen P; 140 | 141 | // 0x0070 142 | it_slen Pt; 143 | } __attribute__((__packed__)) it_slave; 144 | 145 | typedef struct it_header_s 146 | { 147 | // 0x0000 148 | uint8_t magic[4]; // "IMPM" 149 | uint8_t SongName[26]; 150 | 151 | // 0x001E 152 | uint16_t PHiligt; 153 | 154 | // 0x0020 155 | uint16_t OrdNum, InsNum; 156 | uint16_t SmpNum, PatNum; 157 | uint16_t Cwt_v, Cmwt; 158 | uint16_t Flags, Special; 159 | 160 | // 0x0030 161 | uint8_t GV, MV, IS, IT; 162 | uint8_t Sep, PWD; uint16_t MsgLgth; 163 | uint32_t Message_Offset; 164 | uint32_t Time_Stamp; 165 | 166 | // 0x0040 167 | uint8_t Chnl_Pan[64]; 168 | 169 | // 0x0080 170 | uint8_t Chnl_Vol[64]; 171 | } __attribute__((__packed__)) it_header; 172 | 173 | typedef struct it_envelope_s 174 | { 175 | // 0x0000 176 | uint8_t Flg, Num, LpB, LpE; 177 | uint8_t SLB, SLE; 178 | 179 | // 0x0006 180 | uint8_t Nodes[25][3]; 181 | 182 | // 183 | uint8_t pad1; 184 | 185 | } __attribute__((__packed__)) it_envelope; 186 | 187 | typedef struct it_instrument_s 188 | { 189 | // 0x0000 190 | uint8_t magic[4]; // "IMPI" 191 | uint8_t FileName[13]; 192 | 193 | // 0x0011 194 | uint8_t NNA, DCT, DCA; 195 | uint16_t FadeOut; int8_t PPS; uint8_t PPC; 196 | uint8_t GbV, DfP, RV, RP; 197 | uint16_t TrkVers; uint8_t NoS, _1F; 198 | 199 | // 0x0020 200 | uint8_t Name[26]; 201 | 202 | // 0x003A 203 | uint8_t IFC, IFR; 204 | uint8_t MCh, MPr; uint16_t MIDIBnk; 205 | 206 | // 0x0040 207 | uint8_t NoteSamp[120][2]; 208 | 209 | // 0x0130 210 | it_envelope VolEnv; 211 | 212 | // 0x0182 213 | it_envelope PanEnv; 214 | 215 | // 0x01D4 216 | it_envelope PitchEnv; 217 | 218 | // 219 | uint8_t pad1[7]; 220 | } __attribute__((__packed__)) it_instrument; 221 | 222 | typedef struct it_sample_s 223 | { 224 | // 0x0000 225 | uint8_t magic[4]; // "IMPS" 226 | uint8_t FileName[13]; 227 | 228 | // 0x0011 229 | uint8_t GvL, Flg, Vol; 230 | uint8_t Name[26]; 231 | 232 | // 0x002E 233 | uint8_t Cvt, DfP; 234 | 235 | // 0x0030 236 | uint32_t Length; 237 | uint32_t Loop_Begin; 238 | uint32_t Loop_End; 239 | uint32_t C5Speed; 240 | 241 | // 0x0040 242 | uint32_t SusLoop_Begin; 243 | uint32_t SusLoop_End; 244 | uint32_t SamplePointer; 245 | uint8_t ViS, ViD, ViR, ViT; 246 | 247 | } __attribute__((__packed__)) it_sample; 248 | 249 | typedef struct it_pattern_s 250 | { 251 | uint16_t Length; 252 | uint16_t Rows; 253 | uint8_t pad1[4]; 254 | uint8_t data[]; 255 | } __attribute__((__packed__)) it_pattern; 256 | 257 | typedef struct it_engine_s it_engine; 258 | 259 | typedef struct it_drvdata_s 260 | { 261 | uint16_t BasePort ;//= 0xFFFF; // * ORDER IS IMPORTANT 262 | uint16_t IRQ ;//= 0xFFFF; // * ORDER IS IMPORTANT 263 | uint16_t DMA ;//= 0xFFFF; // * ORDER IS IMPORTANT 264 | uint16_t CmdLineMixSpeed ;//= 0; // * ORDER IS IMPORTANT 265 | //uint16_t SongDataArea = SongData; // * ORDER IS IMPORTANT 266 | //uint16_t MIDIDataArea = SongData + 4076; 267 | 268 | uint16_t CmdLineDMASize ;//= 1024; // default 269 | uint8_t ReverseChannels ;//= 0; 270 | uint16_t DriverMaxChannels; // = 32; 271 | uint16_t StopEndOfPlaySection; // = 0; 272 | uint16_t DefaultChannels; // = 32; 273 | uint16_t DriverFlags; // = 0; 274 | // Bit 1 = MIDI Out supported 275 | // Bit 2 = Hiqual 276 | // Bit 3 = Output waveform data available 277 | 278 | // Driver vectors 279 | const char *(*DriverDetectCard)(it_engine *ite, const char *fname, uint16_t AL, uint16_t version); 280 | const char *(*DriverInitSound)(it_engine *ite); 281 | int (*DriverReinitSound)(it_engine *ite); 282 | int (*DriverUninitSound)(it_engine *ite); 283 | 284 | int (*DriverPoll)(it_engine *ite, uint16_t PlayMode, uint16_t CurrentPattern); 285 | int (*DriverSetTempo)(it_engine *ite, uint16_t Tempo); 286 | int (*DriverSetMixVolume)(it_engine *ite, uint16_t MixVolume); 287 | int (*DriverSetStereo)(it_engine *ite, uint16_t Stereo); 288 | 289 | int (*DriverLoadSample)(it_engine *ite, uint16_t sidx); 290 | int (*DriverReleaseSample)(it_engine *ite, it_sample *smp); 291 | int (*DriverResetMemory)(it_engine *ite); 292 | int (*DriverGetStatus)(it_engine *ite); 293 | 294 | int (*DriverSoundCardScreen)(it_engine *ite); 295 | int (*DriverGetVariable)(it_engine *ite, uint16_t Var); 296 | int (*DriverSetVariable)(it_engine *ite, uint16_t Var, uint16_t Thing); // TODO! 297 | 298 | // 14? 299 | int (*DriverMIDIOut)(it_engine *ite, uint8_t al); 300 | int (*DriverGetWaveform)(it_engine *ite); 301 | } it_drvdata; 302 | 303 | // This does not pertain to any specific IT structure 304 | struct it_engine_s 305 | { 306 | it_header hdr; 307 | it_host chn[64]; 308 | it_slave slave[256]; 309 | it_instrument ins[100]; 310 | it_sample smp[100]; 311 | it_pattern *pat[200]; 312 | uint8_t ord[0x100]; 313 | //uint8_t patspace[64000]; 314 | //uint8_t patspace[256*64*5]; 315 | uint8_t patspace[128000]; 316 | uint8_t *SamplePointer[100]; 317 | 318 | uint16_t LastSample ;//= 0; 319 | uint16_t PlayMode ;//= 0; 320 | 321 | uint8_t SaveFormat ;//= DEFAULTFORMAT; 322 | uint16_t TimerData ;//= 0; 323 | uint16_t NumTimerData ;//= 0; 324 | uint16_t TopTimerData ;//= 0; 325 | 326 | uint32_t EditTimer ;//= 0; 327 | 328 | // Playmode 0 = Freeplay 329 | // Playmode 1 = Pattern 330 | // Playmode 2 = Song 331 | uint16_t CurrentOrder ;//= 0; // } Must follow 332 | uint16_t CurrentPattern ;//= 0; // } 333 | uint16_t CurrentRow ;//= 0; // } 334 | uint16_t ProcessOrder ;//= 0; 335 | uint16_t ProcessRow ;//= 0; 336 | uint16_t BytesToMix ;//= 0; // = Bytes per frame 337 | uint16_t PatternOffset ;//= 0; 338 | uint16_t PatternSegment ;//= 0; 339 | uint16_t BreakRow ;//= 0; 340 | uint8_t RowDelay ;//= 0; // } Must join on. 341 | uint8_t RowDelayOn ;//= 0; // } 342 | uint8_t PatternArray ;//= 0; 343 | 344 | uint16_t PatternDataSegment; 345 | uint16_t CurrentEditPattern; 346 | uint16_t PatternEditMaxRow; 347 | 348 | uint16_t DecodeExpectedPattern ;//= 0xFFFE; 349 | uint16_t DecodeExpectedRow ;//= 0xFFFE; 350 | 351 | int16_t CmdLineNumChannels ;//= 0xFFFF; 352 | 353 | uint16_t NumberOfRows ;//= 64; // Non zero globals 354 | uint16_t CurrentTick ;//= 6; 355 | uint16_t CurrentSpeed ;//= 6; 356 | uint16_t ProcessTick ;//= 0; 357 | uint8_t Tempo ;//= 125; 358 | uint8_t GlobalVolume ;//= 128; 359 | uint16_t NumChannels ;//= 256; 360 | uint8_t SoloSample ;//= 0xFF; // * ORDER IS IMPORTANT 361 | uint8_t SoloInstrument ;//= 0xFF; // * ORDER IS IMPORTANT 362 | uint16_t AllocateNumChannels ;//= 0; 363 | uint16_t AllocateSlaveOffset ;//= 0; 364 | uint16_t LastSlaveChannel ;//= 0; 365 | 366 | uint8_t PatternLooping ;//= 0; 367 | uint8_t PatternStorage ;//= 1; 368 | // 0 = conventional only 369 | // 1 = selective 370 | // 2 = EMS only. 371 | 372 | uint8_t OrderLockFlag ;//= 0; 373 | 374 | uint8_t MuteChannelTable[64]; 375 | uint8_t ChannelCountTable[400]; 376 | 377 | char *DriverName ;//= NULL; 378 | 379 | 380 | uint8_t LastMIDIByte ;//= 0xFF; 381 | uint16_t MIDIPitchDepthSent ;//= 0x0000; 382 | 383 | uint16_t Seed1 ;//= 0x1234; 384 | uint16_t Seed2 ;//= 0x5678; 385 | 386 | uint8_t DoMIDICycle ;//= 0; 387 | 388 | uint8_t MIDIPrograms[16] ;//= 0xFF; // Do NOT change order! 389 | uint16_t MIDIBanks[16] ;//= 0xFFFF; 390 | uint8_t MIDIPan[16] ;//= 0xFF; 391 | uint16_t MIDIPitch[16] ;//= 0x2000; 392 | 393 | uint16_t ADSCParams[7] ;//= 0; 394 | 395 | uint8_t StopSong ;//= 0; 396 | uint32_t TimerCounter ;//= 0; 397 | uint32_t TotalTimer ;//= 0; 398 | uint32_t TotalTimerHigh ;//= 0; 399 | 400 | // PE stuff 401 | uint16_t TopOrder ;//= 0 402 | uint16_t Order ;//= 0 403 | uint16_t OrderCursor ;//= 0 404 | uint16_t PatternNumber ;//= 0 405 | uint16_t TopRow ;//= 0 406 | uint16_t Row ;//= 0 407 | uint16_t MaxRow ;//= 63 408 | //uint16_t NumberOfRows ;//= 64 409 | 410 | uint8_t LastNote ;//= 60 411 | uint8_t LastInstrument ;//= 1 412 | uint8_t LastVolume ;//= 0FFh 413 | uint8_t LastCommand ;//= 0 414 | uint8_t LastCommandValue ;//= 0 415 | 416 | it_drvdata d; 417 | }; 418 | 419 | // it_obj1.c 420 | #ifdef EDITOR 421 | void M_Object1List(it_engine *ite, void *di, int cx); 422 | extern it_objlist_6 O1_AutoDetectList; 423 | extern it_objlist_2 O1_OutOfSoundCardMemoryList; 424 | extern it_objlist_2 O1_ShowTime; 425 | #else 426 | #define M_Object1List(ite, list, typ) 427 | static void *O1_AutoDetectList; 428 | static void *O1_OutOfSoundCardMemoryList; 429 | static void *O1_ShowTime; 430 | #endif 431 | 432 | // it_music.c 433 | it_engine *ITEngineNew(); 434 | void RecalculateAllVolumes(it_engine *ite); 435 | void InitPlayInstrument(it_engine *ite, it_host *chn, it_slave *slave, int bx); 436 | void ApplyRandomValues(it_engine *ite, it_host *chn); 437 | void SetFilterCutoff(it_engine *ite, it_slave *slave, uint8_t bl); 438 | void SetFilterResonance(it_engine *ite, it_slave *slave, uint8_t bl); 439 | void MIDITranslate(it_engine *ite, it_host *chn, it_slave *slave, uint16_t bx); 440 | it_slave *AllocateChannel(it_engine *ite, it_host *chn, uint8_t *ch); 441 | uint16_t Random(it_engine *ite); 442 | void GetLoopInformation(it_engine *ite, it_slave *slave); 443 | void PitchSlideDown(it_engine *ite, it_host *chn, it_slave *slave, int16_t bx); 444 | void PitchSlideDownAmiga(it_engine *ite, it_host *chn, it_slave *slave, int16_t bx); 445 | void PitchSlideDownLinear(it_engine *ite, it_host *chn, it_slave *slave, int16_t bx); 446 | void PitchSlideUp(it_engine *ite, it_host *chn, it_slave *slave, int16_t bx); 447 | void PitchSlideUpLinear(it_engine *ite, it_host *chn, it_slave *slave, int16_t bx); 448 | void PitchSlideUpAmiga(it_engine *ite, it_host *chn, it_slave *slave, int16_t bx); 449 | int Music_GetWaveForm(it_engine *ite); 450 | void Music_Poll(it_engine *ite); 451 | void Music_InitTempo(it_engine *ite); 452 | void Music_ReinitSoundCard(it_engine *ite); 453 | void Music_UnInitSoundCard(it_engine *ite); 454 | void Music_InitMusic(it_engine *ite); 455 | it_pattern *Music_AllocatePattern(it_engine *ite, uint16_t dx); 456 | uint8_t *Music_AllocateSample(it_engine *ite, uint16_t ax, size_t edx); 457 | void Music_ReleaseSample(it_engine *ite, uint8_t al, uint8_t ah); 458 | void Music_ClearAllSampleNames(it_engine *ite); 459 | void Music_ReleaseAllSamples(it_engine *ite); 460 | void Music_ReleaseAllPatterns(it_engine *ite); 461 | void Music_ClearAllInstruments(it_engine *ite); 462 | void Music_UnInitMusic(it_engine *ite); 463 | void Music_UnloadDriver(it_engine *ite); 464 | void Music_ClearDriverTables(it_engine *ite); 465 | int Music_LoadDriver(it_engine *ite, const char *fname); 466 | const char *Music_AutoDetectSoundCard(it_engine *ite); 467 | void Music_ShowAutoDetectSoundCard(it_engine *ite); 468 | void Update(it_engine *ite, uint16_t *rcx, it_slave **si, uint16_t *ax); 469 | void UpdateSamples(it_engine *ite); 470 | void UpdateInstruments(it_engine *ite); 471 | void UpdateInstruments16(it_engine *ite, it_slave *slave); 472 | void UpdateInstruments5(it_engine *ite, it_slave *slave); 473 | void UpdateData(it_engine *ite); 474 | void UpdateData_PlayMode0(it_engine *ite); 475 | void UpdateData_PlayMode1(it_engine *ite); 476 | void UpdateEffectData(it_engine *ite); 477 | void UpdateData_PlayMode2(it_engine *ite); 478 | uint8_t *Music_GetSampleLocation(it_engine *ite, uint16_t ax, uint32_t *rcx, int *is8bit); 479 | void Music_PlayPattern(it_engine *ite, uint16_t pidx, uint16_t numrows, uint16_t startrow); 480 | void Music_PlaySong(it_engine *ite, uint16_t oidx); 481 | void Music_PlayPartSong(it_engine *ite, uint16_t oidx, uint16_t row); 482 | void Music_StopChannels(it_engine *ite); 483 | void Music_Stop(it_engine *ite); 484 | void Music_InitStereo(it_engine *ite); 485 | uint16_t Music_SoundCardLoadAllSamples(it_engine *ite); 486 | void Music_InitMixTable(it_engine *ite); 487 | uint16_t Music_GetTempo(it_engine *ite); 488 | void Music_ShowTime(it_engine *ite); 489 | void Music_ToggleOrderUpdate(it_engine *ite); 490 | uint16_t Music_ToggleSolo(it_engine *ite, const char *msg, uint8_t *v, uint16_t bp); 491 | 492 | extern const uint32_t PitchTable[]; 493 | extern const int8_t FineSineData[]; 494 | extern const int8_t FineRampDownData[]; 495 | extern const int8_t FineSquareWave[]; 496 | extern const uint32_t *LinearSlideUpTable; 497 | 498 | // it_m_eff.c 499 | void InitNoCommand(it_engine *ite, it_host *chn); 500 | void InitCommandA(it_engine *ite, it_host *chn); 501 | void InitCommandB(it_engine *ite, it_host *chn); 502 | void InitCommandC(it_engine *ite, it_host *chn); 503 | void InitCommandD(it_engine *ite, it_host *chn); 504 | void InitCommandE(it_engine *ite, it_host *chn); 505 | void InitCommandF(it_engine *ite, it_host *chn); 506 | void InitCommandG(it_engine *ite, it_host *chn); 507 | void InitCommandH(it_engine *ite, it_host *chn); 508 | void InitCommandI(it_engine *ite, it_host *chn); 509 | void InitCommandJ(it_engine *ite, it_host *chn); 510 | void InitCommandK(it_engine *ite, it_host *chn); 511 | void InitCommandL(it_engine *ite, it_host *chn); 512 | void InitCommandM(it_engine *ite, it_host *chn); 513 | void InitCommandN(it_engine *ite, it_host *chn); 514 | void InitCommandO(it_engine *ite, it_host *chn); 515 | void InitCommandP(it_engine *ite, it_host *chn); 516 | void InitCommandQ(it_engine *ite, it_host *chn); 517 | void InitCommandR(it_engine *ite, it_host *chn); 518 | void InitCommandS(it_engine *ite, it_host *chn); 519 | void InitCommandT(it_engine *ite, it_host *chn); 520 | void InitCommandU(it_engine *ite, it_host *chn); 521 | void InitCommandV(it_engine *ite, it_host *chn); 522 | void InitCommandW(it_engine *ite, it_host *chn); 523 | void InitCommandX(it_engine *ite, it_host *chn); 524 | void InitCommandY(it_engine *ite, it_host *chn); 525 | void InitCommandZ(it_engine *ite, it_host *chn); 526 | 527 | void NoCommand(it_engine *ite, it_host *chn); 528 | void CommandD(it_engine *ite, it_host *chn); 529 | void CommandE(it_engine *ite, it_host *chn); 530 | void CommandF(it_engine *ite, it_host *chn); 531 | void CommandG(it_engine *ite, it_host *chn); 532 | void CommandH(it_engine *ite, it_host *chn); 533 | void CommandI(it_engine *ite, it_host *chn); 534 | void CommandJ(it_engine *ite, it_host *chn); 535 | void CommandK(it_engine *ite, it_host *chn); 536 | void CommandL(it_engine *ite, it_host *chn); 537 | void CommandN(it_engine *ite, it_host *chn); 538 | void CommandP(it_engine *ite, it_host *chn); 539 | void CommandQ(it_engine *ite, it_host *chn); 540 | void CommandR(it_engine *ite, it_host *chn); 541 | void CommandS(it_engine *ite, it_host *chn); 542 | void CommandT(it_engine *ite, it_host *chn); 543 | void CommandW(it_engine *ite, it_host *chn); 544 | void CommandY(it_engine *ite, it_host *chn); 545 | void VolumeCommandC(it_engine *ite, it_host *chn); 546 | void VolumeCommandD(it_engine *ite, it_host *chn); 547 | void VolumeCommandE(it_engine *ite, it_host *chn); 548 | void VolumeCommandF(it_engine *ite, it_host *chn); 549 | void VolumeCommandG(it_engine *ite, it_host *chn); 550 | 551 | // it_disk.c & co 552 | int D_LoadIT(it_engine *ite, const char *fname); 553 | 554 | // unsorted 555 | 556 | // these can be filled in later, they're really simple and afaik purely for the editor 557 | // - look in IT_I.ASM for the code --GM 558 | #define I_TagSample(ite, idx) 559 | #define I_TagInstrument(ite, idx) 560 | 561 | // here's the screen stuff that needs implementing --GM 562 | #define S_SaveScreen(ite) 563 | #define S_DrawBox(ite, col, x1, y1, w, h) /* args unknown right now */ 564 | #define S_DrawString(ite, x, y, str, col) 565 | #define S_UpdateScreen(ite) 566 | #define S_RestoreScreen(ite) 567 | #define S_SetDirectMode(ite, b) 568 | #define S_DrawSmallBox(ite) 569 | #define S_GetDestination(ite) 570 | 571 | #define SetInfoLine(ite, str) printf("%s\n", (str)); 572 | 573 | #define D_GotoStartingDirectory(ite) 574 | #define D_ShowTime(ite, x, y, time) 575 | 576 | #define MIDI_ClearTable(ite) 577 | 578 | #define StartClock(ite) 579 | 580 | -------------------------------------------------------------------------------- /src/player/it_disk.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014, Jeffrey Lim. All Rights Reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | 3. The name of the author may not be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 19 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 20 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #include "it_struc.h" 30 | 31 | const char *HeaderMsg = "File Header"; 32 | const char *InstrumentMsg = "Instrument \375D"; 33 | const char *SampleMsg = "Sample \375D"; 34 | const char *SHLoadMsg = "Sample Header \375D"; 35 | const char *PatternMsg = "Pattern \375D"; 36 | 37 | // TODO: prevent buffer read overruns 38 | // note, it's entirely likely that I'm slightly off for exceptional behaviour --GM 39 | void D_Decompress16BitData(uint16_t *dest, uint8_t *src, uint16_t len) 40 | { 41 | // Register usage: 42 | // BX = LastValue 43 | // CH = Bitdepth 44 | // CL = 16-Bitdepth, 0 for Bitdepth > 16 45 | // DL = Bitsread 46 | // DH = scratch 47 | 48 | int counter = len>>1; 49 | uint8_t bitdepth = 17; 50 | uint8_t ibitdepth = 0; 51 | uint16_t lastvalue = 0; 52 | uint8_t bitsread = 0; 53 | uint8_t scratch = 0; 54 | 55 | while(counter != 0) 56 | { 57 | // Push CX 58 | 59 | uint32_t eax = *(uint32_t *)src; 60 | eax >>= bitsread; 61 | 62 | bitsread += bitdepth; 63 | src += bitsread>>3; 64 | bitsread &= 7; 65 | 66 | // Pop CX 67 | 68 | if(bitdepth <= 6) 69 | { 70 | eax <<= ibitdepth; 71 | 72 | if((eax & 0xFFFF) != 0x8000) 73 | { 74 | lastvalue += (uint16_t)(((int16_t)eax)>>ibitdepth); 75 | *(dest++) = lastvalue; 76 | counter--; 77 | continue; 78 | } 79 | 80 | uint8_t newbits = (eax>>16) & 15; 81 | newbits++; 82 | 83 | // Advance bits 84 | bitsread += 4; 85 | if(newbits >= bitdepth) 86 | newbits += 1; 87 | 88 | ibitdepth = 16; 89 | bitdepth = newbits; 90 | if(ibitdepth < bitdepth) 91 | { 92 | ibitdepth -= bitdepth; 93 | ibitdepth++; 94 | } else { 95 | ibitdepth -= bitdepth; 96 | } 97 | 98 | } else if(bitdepth <= 16) { 99 | 100 | // Push DX 101 | 102 | uint16_t tmp_dx = 0xFFFF; 103 | tmp_dx >>= ibitdepth; 104 | uint16_t tmp_ax = (uint16_t)eax; 105 | tmp_ax &= (uint16_t)tmp_dx; 106 | tmp_dx >>= 1; 107 | tmp_dx += 8; 108 | tmp_dx -= 16; 109 | if(tmp_ax > (uint16_t)(tmp_dx+16) || tmp_ax <= (uint16_t)tmp_dx) 110 | { 111 | eax <<= ibitdepth; 112 | lastvalue += (uint16_t)(((int16_t)eax)>>ibitdepth); 113 | *(dest++) = lastvalue; 114 | counter--; 115 | continue; 116 | } 117 | 118 | // Pop DX 119 | 120 | uint8_t newbits = (uint8_t)(tmp_ax - tmp_dx); 121 | if(newbits >= bitdepth) 122 | newbits += 1; 123 | 124 | ibitdepth = 16; 125 | bitdepth = newbits; 126 | if(ibitdepth < bitdepth) 127 | { 128 | ibitdepth -= bitdepth; 129 | ibitdepth++; 130 | } else { 131 | ibitdepth -= bitdepth; 132 | } 133 | } else { 134 | 135 | if((eax & 0x10000) == 0) 136 | { 137 | lastvalue += (uint16_t)eax; 138 | *(dest++) = lastvalue; 139 | counter--; 140 | continue; 141 | } 142 | 143 | eax++; // Inc AX actually 144 | bitdepth = (uint8_t)(eax&0xFF); 145 | ibitdepth = 16 - bitdepth; 146 | } 147 | } 148 | 149 | } 150 | 151 | void D_Decompress8BitData(uint8_t *dest, uint8_t *src, uint16_t len) 152 | { 153 | // DS:SI = source 154 | // ES:DI = destination 155 | // CX = count. 156 | 157 | // Register usage: 158 | // BH = Bitdepth 159 | // BL = lastvalue 160 | // CL = 8-bitdepth, undefined for bitdepth > 8 161 | // CH = Bitsread 162 | 163 | // DX = scratch 164 | 165 | int counter = len; // BP = counter; 166 | uint8_t bitdepth = 9; 167 | uint8_t ibitdepth = 0; 168 | uint8_t lastvalue = 0; 169 | uint8_t bitsread = 0; 170 | uint16_t scratch = 0; 171 | 172 | while(counter != 0) 173 | { 174 | // Get bits loaded into AX properly. 175 | uint16_t ax = *(uint16_t *)src; 176 | ax >>= bitsread; 177 | 178 | // Advance SI as necessary. 179 | bitsread += bitdepth; 180 | src += bitsread>>3; 181 | bitsread &= 7; 182 | 183 | uint8_t tmp_al; 184 | if(bitdepth <= 6) 185 | { 186 | ax <<= ibitdepth; 187 | 188 | if((ax & 0xFF) != 0x80) 189 | { 190 | lastvalue += (uint8_t)(((int8_t)ax)>>ibitdepth); 191 | *(dest++) = lastvalue; 192 | counter--; 193 | continue; 194 | } 195 | 196 | tmp_al = (ax>>8); 197 | bitsread += 3; 198 | 199 | tmp_al &= 7; 200 | scratch = bitsread; 201 | bitsread &= 7; 202 | scratch >>= 3; 203 | 204 | src += scratch; 205 | 206 | } else { 207 | tmp_al = (ax & 0xFF); 208 | 209 | if(bitdepth > 8) 210 | { 211 | // 9 bit representation 212 | ax &= 0x1FF; 213 | 214 | if((ax & 0x100) == 0) 215 | { 216 | lastvalue += (uint8_t)tmp_al; 217 | *(dest++) = lastvalue; 218 | counter--; 219 | continue; 220 | } 221 | 222 | } else if(bitdepth == 8) { 223 | if(tmp_al < 0x7C || tmp_al > 0x83) 224 | { 225 | lastvalue += (uint8_t)tmp_al; 226 | *(dest++) = lastvalue; 227 | counter--; 228 | continue; 229 | } 230 | 231 | tmp_al -= 0x7C; 232 | 233 | } else { 234 | 235 | tmp_al <<= 1; 236 | if(tmp_al < 0x78 || tmp_al > 0x86) 237 | { 238 | lastvalue += (uint8_t)(((int8_t)tmp_al)>>1); 239 | *(dest++) = lastvalue; 240 | counter--; 241 | continue; 242 | } 243 | 244 | tmp_al >>= 1; 245 | tmp_al -= 0x3C; 246 | 247 | } 248 | } 249 | 250 | ibitdepth = 8; 251 | tmp_al++; 252 | 253 | //Cmp AL, BH 254 | //SBB AL, 0FFh 255 | //Mov BH, AL 256 | //Sub CL, AL 257 | //AdC CL, 0 258 | if(tmp_al >= bitdepth) 259 | tmp_al++; 260 | bitdepth = tmp_al; 261 | 262 | if(ibitdepth < tmp_al) 263 | { 264 | ibitdepth -= tmp_al; 265 | ibitdepth++; 266 | } else { 267 | ibitdepth -= tmp_al; 268 | } 269 | 270 | continue; 271 | 272 | } 273 | } 274 | 275 | int D_LoadSampleData(it_engine *ite, FILE *fp, uint16_t ax) 276 | { 277 | // DS:SI points to sample header 278 | // AX = sample number (0 based) 279 | 280 | it_sample *smp = &ite->smp[ax]; 281 | 282 | uint32_t edx = smp->Length; 283 | if(edx == 0) return 0; 284 | 285 | uint8_t cl = smp->Flg; 286 | uint16_t bp = ((uint16_t)smp->Cvt) | (((uint16_t)smp->DfP)<<8); 287 | 288 | smp->Flg &= ~0x0C; 289 | smp->Cvt = 1; 290 | bp &= 0xFF; 291 | 292 | bp <<= 1; 293 | uint8_t ch = cl; 294 | ch &= 0x8; cl &= 0x02; 295 | ch <<= 4; 296 | cl >>= 1; 297 | bp |= ((uint16_t)ch)<<8; 298 | bp |= ((uint16_t)cl); 299 | 300 | // BP flags: 301 | // 1: 16 bit 302 | // 2: Convert unsigned->signed 303 | // 4: Swap bytes 304 | // 8: Delta values. 305 | // 16: Byte delta values 306 | // 32: 12-bit sample. 307 | // 64: Stereo prompt. 308 | // 8000h: Compressed. 309 | 310 | 311 | if((bp & 1) != 0) 312 | edx *= 2; 313 | 314 | if((bp & 64) != 0) 315 | { 316 | /* 317 | Cmp CS:DisableStereoMenu, 0 318 | JNE D_NoStereoMenu 319 | { 320 | 321 | PushAD 322 | Push DS ES 323 | 324 | Mov DI, Offset O1_StereoSampleList 325 | Mov CX, 0FFFFh 326 | Call M_Object1List 327 | 328 | Mov CS:TempData, DX 329 | 330 | Pop ES DS 331 | PopAD 332 | 333 | Or BP, CS:TempData // 64 = left 334 | // 64+128 = right 335 | } 336 | D_NoStereoMenu: 337 | */ 338 | edx *= 2; 339 | } 340 | 341 | uint8_t *data = Music_AllocateSample(ite, ax, edx); 342 | ax++; 343 | 344 | int32_t edi = edx; 345 | 346 | if(data == NULL) 347 | { 348 | fseek(fp, smp->Length, SEEK_CUR); // Advance file ptr. 349 | // (pretty sure there's a bug somewhere --GM) 350 | 351 | //PEFunction_OutOfMemoryMessage(ite); 352 | 353 | return 1; 354 | } 355 | 356 | // AX = sample no. 357 | // CH = page no. 358 | // EDI = bytes remaining 359 | // SI = delta accumulator 360 | // BX = file pointer // using variable "fp" instead --GM 361 | 362 | ch = 0; // Start with page 0 363 | uint16_t si = 0; 364 | 365 | uint8_t *srcdata = data; 366 | for(; edi > 0; edi -= 32768) 367 | { 368 | uint32_t ecx; 369 | int is8bit; 370 | //uint8_t *srcdata = Music_GetSampleLocation(ite, ax, &ecx, &is8bit); 371 | 372 | uint32_t buflen = 32768; 373 | 374 | if(edi < buflen) 375 | buflen = edi; 376 | 377 | if((bp & 32) != 0) // 12 bit format? 378 | { 379 | buflen &= 0xFFFF; 380 | buflen *= 3; 381 | buflen += 3; 382 | buflen >>= 2; // = bytes to read. 383 | } 384 | 385 | uint8_t *newsrcdata = srcdata + buflen; 386 | uint16_t packed_len; 387 | uint8_t packed_data[0x10000]; 388 | size_t packed_len_long; 389 | 390 | // DS:DX point to buffer. For compressed samples, use patterndata area. 391 | if((bp & 0x8000) != 0) 392 | { 393 | /* 394 | Push DS 395 | Push CX 396 | Push DX 397 | 398 | Mov DX, Pattern 399 | Mov DS, DX 400 | Assume DS:Pattern 401 | 402 | Mov DS, Word Ptr [PatternDataArea] 403 | Assume DS:Nothing 404 | 405 | Xor DX, DX 406 | Mov CX, 2 407 | Mov AH, 3Fh 408 | Int 21h 409 | Mov CX, [DS:0] // Bytes to read. 410 | Xor DX, DX // Compressed chunk. 411 | */ 412 | fread(&packed_len, 2, 1, fp); 413 | packed_len_long = packed_len; 414 | packed_len_long = fread(packed_data, 1, packed_len_long, fp); 415 | 416 | } else { 417 | buflen = fread(srcdata, 1, buflen, fp); 418 | } 419 | 420 | // Now to decompress samples, if required. 421 | if((bp & 0x8000) != 0) 422 | { 423 | // TODO 424 | if((bp & 1) == 0) 425 | D_Decompress8BitData(srcdata, packed_data, buflen); // 8 bit decode. 426 | else 427 | D_Decompress16BitData((uint16_t *)srcdata, packed_data, buflen); // 16 bit decode 428 | 429 | si = 0; 430 | } 431 | 432 | // flag skipped if sample compressed 433 | if((bp & 0x8000) == 0 && (bp & 32) != 0) // 12-bit sample? 434 | { 435 | // TODO! 436 | abort(); 437 | /* 438 | // CX = number of bytes read. 439 | // = 3*2 number of sample read 440 | buflen = (buflen + 2) / 3; 441 | 442 | // SI = AX * 3 443 | LEA SI, [EAX*2+EAX] // SI = AX * 3 444 | LEA DI, [EAX*4+EDX] 445 | Add SI, DX 446 | 447 | Test CX, CX 448 | JZ ConvertTXSample2 449 | 450 | Push CX 451 | 452 | ConvertTXSample1: 453 | Sub SI, 3 454 | Sub DI, 4 455 | 456 | Mov AX, [SI+1] 457 | ShL AL, 4 458 | ShL EAX, 16 459 | Mov AH, [SI] 460 | Mov AL, [SI+1] 461 | And AL, 0F0h 462 | Mov [DI], EAX 463 | 464 | Loop ConvertTXSample1 465 | 466 | Pop CX 467 | Pop SI 468 | ShL CX, 1 469 | Jmp D_LoadSampleData10 470 | 471 | ConvertTXSample2: 472 | Pop SI 473 | */ 474 | } else { 475 | // CX = number of bytes read 476 | 477 | //SecondDelta: 478 | if((bp & 1) != 0) // 16 bit? 479 | buflen >>= 1; 480 | 481 | //D_LoadSampleData10: 482 | if((bp & 5) == 5) // 16 bit and BSwap? 483 | { 484 | uint16_t ctr = buflen; 485 | uint8_t *dfol = srcdata; 486 | 487 | while(ctr-- != 0) 488 | { 489 | uint8_t datl = dfol[0]; 490 | uint8_t dath = dfol[1]; 491 | dfol[0] = dath; 492 | dfol[1] = datl; 493 | 494 | dfol += 2; 495 | } 496 | } 497 | 498 | if((bp & 24) != 0) // Delta values? 499 | { 500 | if((bp & 1) != 0 && (bp & 16) == 0) 501 | { 502 | // 16 bit delta 503 | uint16_t ctr = buflen; 504 | uint16_t *dfol = (uint16_t *)srcdata; 505 | 506 | while(ctr-- != 0) 507 | { 508 | si += *dfol; 509 | *(dfol++) = si; 510 | } 511 | 512 | } else { 513 | // 8 bit delta 514 | uint16_t ctr = buflen; 515 | uint8_t *dfol = srcdata; 516 | 517 | if((bp & 1) != 0) 518 | ctr *= 2; 519 | 520 | while(ctr-- != 0) 521 | { 522 | si += ((uint16_t)(*dfol))<<8; 523 | *(dfol++) = (si>>8); 524 | } 525 | } 526 | } 527 | 528 | if((bp & 2) == 0) // unsigned->signed? 529 | { 530 | if((bp & 1) == 0) 531 | { 532 | // 8 bit 533 | uint16_t ctr = buflen; 534 | uint8_t *dfol = srcdata; 535 | 536 | while(ctr-- != 0) 537 | *(dfol++) ^= 0x80; 538 | } else { 539 | // 16 bit.. 540 | uint16_t ctr = buflen; 541 | uint16_t *dfol = (uint16_t *)srcdata; 542 | 543 | while(ctr-- != 0) 544 | *(dfol++) ^= 0x8000; 545 | } 546 | } 547 | } 548 | 549 | D_LoadSampleData6: 550 | if((bp & 64) != 0) // Stereo? 551 | { 552 | // TODO! 553 | abort(); 554 | /* 555 | Push SI ES 556 | 557 | Push DS 558 | Pop ES 559 | 560 | Mov SI, DX 561 | Mov DI, DX 562 | 563 | ShR CX, 1 564 | JZ D_LoadSampleDataEndStereo 565 | 566 | Test BP, 1 // 8/16 bit? 567 | JNZ D_LoadSampleDataStereo16BitStart 568 | 569 | Test BP, 128 570 | JZ D_LoadSampleDataStereo8Bit 571 | 572 | Inc SI 573 | 574 | D_LoadSampleDataStereo8Bit: 575 | MovsB 576 | Inc SI 577 | Loop D_LoadSampleDataStereo8Bit 578 | Jmp D_LoadSampleDataEndStereo 579 | 580 | D_LoadSampleDataStereo16BitStart: 581 | Test BP, 128 582 | JZ D_LoadSampledataStereo16Bit 583 | 584 | LodsW 585 | 586 | D_LoadSampleDataStereo16Bit: 587 | MovsW 588 | LodsW 589 | Loop D_LoadSampleDataStereo16Bit 590 | 591 | D_LoadSampleDataEndStereo: 592 | Pop ES SI 593 | 594 | Pop EDI 595 | Pop CX 596 | Pop AX 597 | 598 | Inc CH 599 | Jmp D_LoadSampleDataNextChain 600 | */ 601 | } 602 | 603 | srcdata = newsrcdata; 604 | ch += 2; 605 | 606 | //D_LoadSampleDataNextChain: 607 | } 608 | 609 | return 0; 610 | } 611 | 612 | FILE *D_PreLoadModule(it_engine *ite, const char *fname, uint8_t al) 613 | { 614 | // Returns ES = song segment 615 | // BX = file handle 616 | // DS = Diskdata area 617 | // AX = SaveFormat 618 | 619 | #if DEFAULTFORMAT 620 | if(al == 0) 621 | al = DEFAULTFORMAT; 622 | #endif 623 | 624 | ite->SaveFormat = al; 625 | 626 | //I_ClearTables(ite); 627 | Music_ReleaseAllPatterns(ite); 628 | Music_ReleaseAllSamples(ite); 629 | //Music_ClearAllSampleNames(ite); 630 | Music_ClearAllInstruments(ite); 631 | //Msg_ResetMessage(ite); 632 | //ReleaseTimerData(ite); 633 | 634 | // this is ridiculous, let's write something simpler for now --GM 635 | FILE *fp = fopen(fname, "rb"); 636 | 637 | if(fp == NULL) return NULL; 638 | 639 | return fp; 640 | 641 | /* 642 | Mov DS, CS:DiskDataArea 643 | 644 | Mov BX, CS:CurrentFile 645 | Add BX, BX 646 | Mov BX, [BX] 647 | Add BX, 8 648 | 649 | Push CS 650 | Pop ES 651 | Mov DI, Offset FileName // OK... 652 | Mov SI, BX // Data area no longer 653 | Mov CX, 13 // reqd 654 | Rep MovsB 655 | 656 | Mov AX, 3D00h 657 | Mov DX, BX 658 | Int 21h 659 | JC D_LoadFileOpenErrorMsg 660 | 661 | Mov BX, AX // BX = file handle. 662 | 663 | Call Music_GetSongSegment 664 | Mov ES, AX 665 | */ 666 | } 667 | 668 | void D_PostLoadModule(it_engine *ite, FILE *fp) 669 | { 670 | fclose(fp); // Close file. 671 | 672 | //CheckTimerData(ite); 673 | //GetCurrentTime(ite); 674 | ite->TopTimerData = 0; 675 | //ite->EditTimer = GetTimerCounter(); 676 | 677 | //PE_ResetOrderPattern(ite); 678 | } 679 | 680 | int D_LoadIT(it_engine *ite, const char *fname) 681 | { 682 | FILE *fp = D_PreLoadModule(ite, fname, 0); 683 | printf("loading %p\n", fp); 684 | 685 | S_DrawString(ite, 4, 16, HeaderMsg, 5); 686 | 687 | // why does this load 2KB i mean what --GM 688 | // TODO: serialise this --GM 689 | fread(&ite->hdr, 1, 0xC0, fp); 690 | 691 | printf("ord=%-3i ins=%-3i smp=%-3i pat=%-3i\n", 692 | ite->hdr.OrdNum, 693 | ite->hdr.InsNum, 694 | ite->hdr.SmpNum, 695 | ite->hdr.PatNum); 696 | /* 697 | Mov AH, 3Fh 698 | Mov CX, 2048 699 | Xor DX, DX 700 | Int 21h 701 | */ 702 | 703 | if(ite->hdr.Cwt_v >= 0x0208) 704 | { 705 | ite->hdr.Time_Stamp ^= 0x4B525449; // 'ITRK' - TODO CONFIRM BYTE ORDER 706 | ite->hdr.Time_Stamp = (ite->hdr.Time_Stamp >> 7) | (ite->hdr.Time_Stamp << (32-7)); 707 | ite->hdr.Time_Stamp = -ite->hdr.Time_Stamp; 708 | ite->hdr.Time_Stamp = (ite->hdr.Time_Stamp << 4) | (ite->hdr.Time_Stamp >> (32-4)); 709 | ite->hdr.Time_Stamp ^= 0x4C48544A; // 'JTHL' - TODO CONFIRM BYTE ORDER 710 | printf("Timestamp: %08X\n", ite->hdr.Time_Stamp); 711 | } 712 | 713 | if((ite->hdr.Special & 2) != 0) // Time data? 714 | { 715 | // Seek to 0C0+Orders+ 716 | // (ins+samp+pat)*4 717 | 718 | // TODO! 719 | /* 720 | Mov DX, [DS:22h] 721 | Add DX, [DS:24h] 722 | Add DX, [DS:26h] 723 | ShL DX, 2 724 | Add DX, [DS:20h] 725 | Add DX, 0C0h 726 | Xor CX, CX 727 | Mov AX, 4200h 728 | Int 21h 729 | 730 | Push DS 731 | 732 | Push CS 733 | Pop DS 734 | 735 | Mov AH, 3Fh 736 | Mov CX, 2 737 | Mov DX, Offset NumTimerData 738 | Int 21h 739 | 740 | Push BX // Allocate data for timedata 741 | Mov BX, NumTimerData 742 | Cmp BX, 0FFFFh 743 | JNE D_NoTimerDataOverFlow 744 | 745 | Dec BX 746 | Mov NumTimerData, BX 747 | 748 | D_NoTimerDataOverFlow: 749 | Mov CX, BX 750 | ShR BX, 1 751 | Inc BX 752 | Mov AH, 48h 753 | Int 21h 754 | Pop BX 755 | JC D_LoadTimeDataEnd 756 | 757 | Mov TimerData, AX 758 | Mov DS, AX 759 | ShL CX, 3 760 | Xor DX, DX 761 | Mov AH, 3Fh 762 | Int 21h 763 | 764 | D_LoadTimeDataEnd: 765 | Pop DS 766 | */ 767 | } 768 | 769 | if((ite->hdr.Special & 8) != 0) 770 | { 771 | // TODO: MIDI --GM 772 | 773 | /* 774 | PushA 775 | Push DS 776 | 777 | Call Music_GetMIDIDataArea 778 | Xor DX, DX 779 | Mov CX, 4896 780 | Mov AH, 3Fh 781 | Int 21h 782 | 783 | Pop DS 784 | PopA 785 | */ 786 | } 787 | 788 | if((ite->hdr.Special & 1) != 0) 789 | { 790 | // Load the message 791 | // Move to offset first. 792 | 793 | // TODO 794 | /* 795 | Mov AX, 4200h 796 | Mov CX, [DS:3Ah] 797 | Mov DX, [DS:38h] 798 | Int 21h // Seek to position 799 | 800 | Push DS 801 | 802 | Mov CX, [DS:36h] 803 | Call Msg_GetMessageOffset 804 | Mov AH, 3Fh 805 | Int 21h 806 | 807 | Pop DS 808 | */ 809 | } 810 | 811 | // Actually, load row hilights first... 812 | if((ite->hdr.Special & 4) != 0) 813 | { 814 | // TODO --GM 815 | //ite->RowHilight1 = ite->hdr.PHiligt; 816 | } 817 | 818 | /* 819 | Xor SI, SI 820 | Xor DI, DI 821 | Mov CX, 192 822 | Rep MovsB // Header 823 | */ 824 | 825 | // TODO: verify 826 | // Orders 827 | fseek(fp, 0x00C0, SEEK_SET); 828 | fread(ite->ord, 1, ite->hdr.OrdNum, fp); // XXX: limit OrdNum to >= 1 829 | ite->ord[ite->hdr.OrdNum] = 0xFF; // TODO: verify 830 | 831 | // SI points to first pointer 832 | // this is different from the actual code --GM 833 | uint32_t iptrs[100]; 834 | uint32_t sptrs[100]; 835 | uint32_t pptrs[200]; 836 | assert(ite->hdr.InsNum <= 99); 837 | assert(ite->hdr.SmpNum <= 99); 838 | assert(ite->hdr.PatNum <= 199); 839 | 840 | fread(iptrs, 4, ite->hdr.InsNum, fp); 841 | fread(sptrs, 4, ite->hdr.SmpNum, fp); 842 | fread(pptrs, 4, ite->hdr.PatNum, fp); 843 | 844 | // Instrument time. 845 | uint16_t bp; 846 | it_instrument *ins; 847 | it_sample *smp; 848 | it_pattern *pat; 849 | 850 | for(bp = 0, ins = &ite->ins[0]; bp < ite->hdr.InsNum; bp++, ins++) 851 | { 852 | // TODO: num args 853 | S_DrawString(ite, 4, 17, InstrumentMsg, 5); 854 | 855 | // Move to offset.. 856 | fseek(fp, iptrs[bp], SEEK_SET); 857 | 858 | fread(ins, 1, 554, fp); 859 | 860 | if(ite->hdr.Cmwt < 0x200) 861 | { 862 | // TODO! 863 | abort(); 864 | /* 865 | Mov SI, DX 866 | Call ConvertOldInstrument 867 | */ 868 | } 869 | } 870 | 871 | // Sample header time. 872 | for(bp = 0, smp = &ite->smp[0]; bp < ite->hdr.SmpNum; bp++, smp++) 873 | { 874 | // TODO: num args 875 | S_DrawString(ite, 4, 18, SHLoadMsg, 5); 876 | 877 | // Move to offset.. 878 | fseek(fp, sptrs[bp], SEEK_SET); 879 | 880 | fread(smp, 1, 80, fp); 881 | //printf("smp len %i = %i\n", bp, smp->Length); 882 | } 883 | 884 | // DS now points to song data. 885 | for(bp = 0, smp = &ite->smp[0]; bp < 99; bp++, smp++) 886 | { 887 | if((smp->Flg & 1) != 0) 888 | { 889 | S_DrawString(ite, 4, 19, SampleMsg, 5); 890 | 891 | // Move file pointer. 892 | fseek(fp, smp->SamplePointer, SEEK_SET); 893 | ite->SamplePointer[bp] = NULL; 894 | smp->SamplePointer = 0; 895 | 896 | D_LoadSampleData(ite, fp, bp); 897 | printf("smp %2i flg=%02X len=%i\n", bp, smp->Flg, smp->Length); 898 | 899 | } else { 900 | smp->SamplePointer = 0; 901 | ite->SamplePointer[bp] = NULL; 902 | } 903 | } 904 | 905 | // Pattern time. 906 | for(bp = 0; bp < ite->hdr.PatNum; bp++) 907 | { 908 | S_DrawString(ite, 4, 20, PatternMsg, 5); 909 | 910 | // Move to offset.. 911 | if(pptrs != 0) 912 | { 913 | fseek(fp, pptrs[bp], SEEK_SET); 914 | 915 | fread(ite->patspace, 1, 8, fp); 916 | 917 | uint16_t length = ((uint16_t)ite->patspace[0]) 918 | | (((uint16_t)ite->patspace[1])<<8); 919 | 920 | printf("pat %-3i %-3i %-5i\n", bp, ite->patspace[2], length); 921 | ite->pat[bp] = pat = Music_AllocatePattern(ite, length + 8); 922 | if(pat != NULL) 923 | { 924 | memcpy((uint8_t *)pat, (uint8_t *)ite->patspace, 8); 925 | fread(pat->data, 1, length, fp); 926 | } else { 927 | //PEFunction_OutOfMemoryMessage(ite); 928 | abort(); 929 | } 930 | } 931 | } 932 | 933 | D_PostLoadModule(ite, fp); 934 | return 0; 935 | } 936 | 937 | -------------------------------------------------------------------------------- /src/ui/it.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014, Jeffrey Lim. All Rights Reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | 3. The name of the author may not be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 19 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 20 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #include "it_struc.h" 30 | 31 | // Externals 32 | 33 | /* 34 | Segment Object1 BYTE Public 'Data' 35 | Extrn HelpKeyValue:Word, OrderKeyValue:Word 36 | EndS 37 | 38 | Segment InfoLine BYTE Public 'Code' USE16 39 | Extrn ShowUsageTime:Byte 40 | EndS 41 | 42 | Segment Disk BYTE Public 'Code' USE16 43 | Extrn DiskOptions:Byte 44 | EndS 45 | 46 | Segment Screen BYTE Public 'Code' 47 | Extrn CharacterGenerationOffset:Word 48 | Extrn VGAFlags:Byte 49 | EndS 50 | 51 | Segment Mouse BYTE Public 'Code' 52 | Extrn MouseCharacterGenerationOffset:Word 53 | EndS 54 | 55 | Segment Main DWORD Public 'Code' USE16 56 | Extrn ReleaseTimeSlice:Byte 57 | EndS 58 | 59 | Extrn D_InitDisk:Far 60 | Extrn D_UnInitDisk:Far 61 | Extrn D_DisableFileColours:Far 62 | 63 | Extrn E_InitEMS:Far 64 | Extrn E_UnInitEMS:Far 65 | 66 | Extrn Error_InitHandler:Far 67 | Extrn Error_UnInitHandler:Far 68 | 69 | Extrn K_InitKeyBoard:Far 70 | Extrn K_UnInitKeyBoard:Far 71 | Extrn K_InstallKeyboardType:Far 72 | Extrn K_RemoveKeyboardType:Far 73 | 74 | Extrn K_InstallDOSHandler:Far 75 | Extrn K_UnInstallDOSHandler:Far 76 | Extrn K_SwapKeyBoard:Far 77 | 78 | Extrn O1_AutoDetectList:Far 79 | Extrn O1_ConfirmQuit:Far 80 | Extrn O1_PatternEditList:Far 81 | Extrn O1_CrashRecovery:Far 82 | Extrn O1_KeyboardList:Far 83 | 84 | Extrn M_Object1List:Far 85 | 86 | Extrn S_InitScreen:Far 87 | Extrn S_ClearScreen:Far 88 | Extrn S_UnInitScreen:Far 89 | Extrn S_SetDirectMode:Far 90 | Extrn S_DrawString:Far 91 | 92 | Extrn Music_InitMusic:Far 93 | Extrn Music_UnInitMusic:Far 94 | 95 | Extrn Music_SetLimit:Far 96 | Extrn Music_SetSoundCard:Far 97 | Extrn Music_SetDMA:Far 98 | Extrn Music_SetIRQ:Far 99 | Extrn Music_SetMixSpeed:Far 100 | Extrn Music_SetAddress:Far 101 | Extrn Music_ReverseChannels:Far 102 | Extrn Music_PatternStorage:Far 103 | Extrn Music_SetSoundCardDriver:Far 104 | Extrn Music_Stop:Far 105 | Extrn Music_AutoDetectSoundCard:Far 106 | 107 | IF NETWORKENABLED 108 | Extrn Network_Shutdown:Far 109 | ENDIF 110 | 111 | Extrn PE_InitPatternEdit:Far 112 | Extrn PE_UnInitPatternEdit:Far 113 | Extrn PECheckModified:Far 114 | 115 | Extrn D_RestorePreShellDirectory:Far 116 | Extrn D_GetPreShellDirectory:Far 117 | 118 | Extrn MMTSR_InstallMMTSR:Far 119 | Extrn MMTSR_UninstallMMTSR:Far 120 | 121 | Extrn InitMouse:Far, UnInitMouse:Far 122 | Extrn CmdLineDisableMouse:Far 123 | 124 | Extrn InitTimerHandler:Far, UnInitTimerHandler:Far 125 | 126 | Global Quit:Far, Refresh:Far 127 | Global DOSShell:Far, GetEnvironment:Far 128 | Global CrashRecovery:Far 129 | 130 | Public IsStartupKeyList 131 | Public GetStartupKeyList 132 | 133 | */ 134 | 135 | /* 136 | Segment StartUp BYTE Public 'Code' USE16 137 | Assume CS:StartUp, DS:Nothing, ES:Nothing 138 | */ 139 | 140 | /* 141 | CREATENEWLOGFILE EQU 1 142 | include debug.inc 143 | */ 144 | 145 | // Variables 146 | 147 | #define StackSize 0x1000 148 | 149 | // these are totally going to be useful, har har --GM 150 | const char No386Msg[] = "Sorry, Impulse Tracker requires a 386+ processor to run.\n$"; 151 | const char WindowsMsg[] = "Microsoft Windows detected.\n\n" 152 | "Due to instabilities in Windows, it is highly recommended that you run\n" 153 | "Impulse Tracker in DOS instead.\n\n" 154 | "Press any key to continue..."; 155 | 156 | uint16_t PSP; 157 | uint8_t LoadMMTSR = 1; 158 | uint8_t Pause = 0; 159 | uint8_t COMSPECFound = 0; 160 | uint32_t COMSPEC = 0; 161 | uint8_t Control = 0; 162 | uint8_t CommandTail[] = {1, 0, 13}; 163 | 164 | uint8_t FCB1[] = {0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; 165 | uint8_t FCB2[] = {0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; 166 | 167 | const char COMSPECString[] = "COMSPEC"; 168 | const char DefaultShell[] = "C:\\COMMAND.COM"; 169 | 170 | // I AM NOT PORTING THIS BIT. --GM 171 | /* 172 | EXECData DW 0 ; Inherit same environment block 173 | DW Offset CommandTail, Startup 174 | DW Offset FCB1, Startup 175 | DW Offset FCB2, Startup 176 | */ 177 | const char ShellMsg[] = "Type EXIT to return to Impulse Tracker"; 178 | 179 | #ifdef SHOWREGISTERNAME 180 | #include "wavswitc.h" 181 | #include "username.h" 182 | #endif 183 | 184 | const char CmdLineHelp[] = 185 | #if SHOWVERSION 186 | "Impulse Tracker 2.14, Copyright (C) 1995-2000 Jeffrey Lim\n" 187 | "\n" 188 | " Usage: IT.EXE [Switches]\n" 189 | #else 190 | "Impulse Tracker, Copyright (C) 1995-2000 Jeffrey Lim\n" 191 | #if SHOWREGISTERNAME 192 | "Registered to: " 193 | REGISTERNAME 194 | "\n" 195 | #endif 196 | #endif 197 | "\n" 198 | "Switches:\n" 199 | " SFilename.Drv Select sound card driver\n" 200 | " S#\t\t Quick select sound card\n" 201 | "\tS0: No sound card\t\t S9: Pro Audio Spectrum\n" 202 | "\tS1: PC Speaker\t\t\tS10: Pro Audio Spectrum 16\n" 203 | "\tS2: Sound Blaster 1.xx\t\tS11: Windows Sound System\n" 204 | "\tS3: Sound Blaster 2.xx\t\tS12: ESS ES1868 AudioDrive\n" 205 | "\tS4: Sound Blaster Pro\t\tS13: EWS64 XL Codec\n" 206 | "\tS5: Sound Blaster 16\t\tS14: Ensoniq SoundscapeVIVO\n" 207 | "\tS6: Sound Blaster AWE 32\tS19: Generic MPU401\n" 208 | "\tS7: Gravis UltraSound\t\tS20: Disk Writer (WAV)\n" 209 | "\tS8: AMD Interwave\t\tS21: Disk Writer (MID)\n" 210 | "\n" 211 | " Axxx\tSet Base Address of sound card (hexadecimal)\n" 212 | " I###\tSet IRQ of sound card (decimal)\n" 213 | " D###\tSet DMA of sound card (decimal)\n" 214 | "\n" 215 | " M###\tSet Mixspeed\n" 216 | " L###\tLimit number of channels (4-256)\n" 217 | ; 218 | 219 | const char MixErrorMsg[] = "Error: Mixing speed invalid - setting ignored\n"; 220 | const char AddressErrorMsg[] = "Error: Base Address invalid - setting ignored\n"; 221 | const char IRQErrorMsg[] = "Error: IRQ number invalid - setting ignored\n"; 222 | const char LimitErrorMsg[] = "Error: Channel limit number invalid - setting ignored\n"; 223 | const char ContinueMsg[] = "Press any key to continue..."; 224 | 225 | #if 0 226 | StartupList DB 0 227 | StartupMode DB 0 ; Load? Or Load/Play? or Load/Save 228 | StartupFileOffset DW 0 229 | StartupFileSegment DW 0 230 | StartupKeyListFunction DW Offset GetStartupKeyList1 231 | 232 | ; CX,DX 233 | StartupInformation DW 11Ch, 0 ; Enter 234 | DW 1Ch, 0 ; Release Enter 235 | DW 10Fh, 0 ; Tab 236 | DW 10Fh, 0 ; Tab 237 | DW 10Fh, 0 ; Tab 238 | DW 90Eh, 127 ; Ctrl-Backspace 239 | 240 | ENDSTARTUPINFORMATION EQU $ 241 | 242 | SaveInformation DW 0, 0 ; Loading screen key-loss 243 | DW 1FFh, 13h ; Ctrl-S 244 | DW 0, 0 ; Saving screen key-loss 245 | DW 1FFh, 11h ; Ctrl-Q 246 | DW 1FFh, 'Y' ; 'Y' 247 | 248 | ENDSAVEINFORMATION EQU $ 249 | 250 | StartupQueueOffset DW Offset StartupInformation 251 | StartupQueueEnd DW Offset ENDSTARTUPINFORMATION 252 | StartupQueueNextFunction DW Offset GetStartupKeyList2 253 | 254 | ;ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ 255 | ;³ Functions ³ 256 | ;ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ 257 | 258 | #endif 259 | uint8_t CapitaliseAL(uint8_t c) 260 | { 261 | if(c >= 'a' && c <= 'z') 262 | c += 'A'-'a'; 263 | 264 | return c; 265 | } 266 | 267 | #if 0 268 | Proc GetDecimalNumber ; Returns CX 269 | 270 | LodsB 271 | Cmp AL, '0' 272 | JB GetDecimalNumber1 273 | Cmp AL, '9' 274 | JBE GetDecimalNumber2 275 | 276 | GetDecimalNumber1: 277 | StC 278 | Ret 279 | 280 | GetDecimalNumber2: 281 | Xor CX, CX 282 | 283 | GetDecimalNumber3: 284 | Mov BL, AL 285 | Sub BL, '0' 286 | Xor BH, BH 287 | Mov AX, 10 288 | Mul CX 289 | Add AX, BX 290 | Mov CX, AX 291 | LodsB 292 | And DX, DX 293 | JNZ GetDecimalNumber1 294 | 295 | Cmp AL, '0' 296 | JB GetDecimalNumber4 297 | Cmp AL, '9' 298 | JA GetDecimalNumber4 299 | Jmp GetDecimalNumber3 300 | 301 | GetDecimalNumber4: 302 | ClC 303 | Ret 304 | 305 | EndP GetDecimalNumber 306 | #endif 307 | 308 | void Quit1(it_engine *ite) 309 | { 310 | //PECheckModified(); 311 | Music_Stop(ite); 312 | 313 | #if NETWORKENABLED 314 | Network_Shutdown(); 315 | #endif 316 | 317 | //MMTSR_UninstallMMTSR(); 318 | //PE_UnInitPatternEdit(); 319 | Music_UnInitMusic(ite); 320 | //UnInitMouse(); 321 | //S_UnInitScreen(); 322 | //E_UnInitEMS(); 323 | //K_UnInitKeyBoard(); 324 | //Error_UnInitHandler(); 325 | //D_UnInitDisk(); 326 | //K_RemoveKeyboardType(); 327 | //UnInitTimerHandler(); 328 | 329 | exit(0); 330 | } 331 | 332 | void Start(it_engine *ite, const char *cmdtail) 333 | { 334 | const char *v; 335 | char c; 336 | 337 | // 386 check. 338 | 339 | printf("Impulse Tracker Startup\n"); 340 | 341 | // if(do_some_386_check()) { printf(No386Msg); exit(2) }; 342 | 343 | //Found386: 344 | // Push 0B800h ; DEBUG!!!!! 345 | // Pop GS ; DEBUG!!!!! 346 | 347 | /* 348 | Push CX 349 | PopF 350 | 351 | ClD 352 | 353 | Mov [CS:PSP], ES 354 | 355 | Mov AX, ES 356 | Mov BX, SS 357 | Sub BX, AX 358 | Add BX, StackSize / 16 ; Add BX, 359 | Mov AH, 4Ah ; Re-allocate memory 360 | Int 21h 361 | */ 362 | 363 | // Check for 386 here. 364 | 365 | /* 366 | ; Do command line stuff. 367 | Mov SI, 81h ; DS:SI points to cmdtail 368 | */ 369 | 370 | v = cmdtail; 371 | for(;;) 372 | { 373 | /* 374 | Push ES 375 | Pop DS 376 | */ 377 | 378 | c = *(v++); 379 | 380 | CmdLine3: 381 | if(c == '\r' || c == '\x00') 382 | goto CmdLineEnd; 383 | 384 | c = CapitaliseAL(c); 385 | 386 | CmdLine2: 387 | switch(c) 388 | { 389 | case 'K': 390 | // KeyboardSwap 391 | break; 392 | 393 | case 'F': 394 | // DisableColours 395 | break; 396 | 397 | case 'C': 398 | // SetControl 399 | break; 400 | 401 | case 'H': 402 | case '?': 403 | // ShowCmdLineHelp 404 | break; 405 | 406 | case 'S': 407 | // SetSoundCard1 408 | break; 409 | 410 | case 'D': 411 | // SetDMA1 412 | break; 413 | 414 | case 'M': 415 | // SetMixSpeed1 416 | break; 417 | 418 | case 'I': 419 | // SetIRQ1 420 | break; 421 | 422 | case 'A': 423 | // SetAddress1 424 | break; 425 | 426 | case 'V': 427 | // OverrideVGA 428 | break; 429 | 430 | case 'L': 431 | // Limit1 432 | break; 433 | 434 | case 'R': 435 | // Reverse1 436 | break; 437 | 438 | case 'X': 439 | // DisableFeatures 440 | break; 441 | 442 | case 'P': 443 | // PatternStorage 444 | break; 445 | 446 | case 'T': 447 | // NoShowUsageTime 448 | break; 449 | 450 | case 'W': 451 | // ConvertModule 452 | break; 453 | } 454 | 455 | /* 456 | NoShowUsageTime: 457 | LodsB 458 | Cmp AL, '1' 459 | JNE NoReleaseTimeSlice 460 | 461 | Push DS 462 | 463 | Push InfoLine 464 | Pop DS 465 | Assume DS:InfoLine 466 | 467 | Mov [ShowUsageTime], 0 468 | 469 | Pop DS 470 | Jmp CmdLine1 471 | Assume DS:Nothing 472 | 473 | NoReleaseTimeSlice: 474 | Cmp AL, '2' 475 | JNE CmdLine3 476 | 477 | NoReleaseTimeSlice2: 478 | Push DS 479 | 480 | Push Main 481 | Pop DS 482 | Assume DS:Main 483 | 484 | Mov [ReleaseTimeSlice], 1 485 | 486 | Pop DS 487 | Jmp CmdLine1 488 | 489 | PatternStorage: 490 | LodsB 491 | Sub AL, '0' 492 | JC PatternStorageEnd 493 | Cmp AL, 2 494 | JA PatternStorageEnd 495 | Call Music_PatternStorage 496 | Jmp CmdLine1 497 | 498 | PatternStorageEnd: 499 | Jmp CmdLine3 500 | 501 | DisableFeatures: 502 | LodsB 503 | Cmp AL, '1' 504 | JB CmdLine3 505 | JE DisableMMTSR 506 | 507 | Cmp AL, '3' 508 | JB DisableMouse 509 | JE DisableDetectDriveMap 510 | 511 | Cmp AL, '5' 512 | JB DisableCacheFiles 513 | Jmp CmdLine3 514 | 515 | DisableMouse: 516 | Call CmdLineDisableMouse 517 | Jmp CmdLine1 518 | 519 | DisableMMTSR: 520 | Mov [LoadMMTSR], 0 521 | Jmp CmdLine1 522 | 523 | DisableDetectDriveMap: 524 | Push Disk 525 | Pop DS 526 | Assume DS:Disk 527 | 528 | Or [DiskOptions], 1 529 | Jmp CmdLine1 530 | Assume DS:Nothing 531 | 532 | DisableCacheFiles: 533 | Push Disk 534 | Pop DS 535 | Assume DS:Disk 536 | 537 | Or [DiskOptions], 2 538 | Jmp CmdLine1 539 | Assume DS:Nothing 540 | 541 | KeyboardSwap: 542 | Mov AX, Object1 543 | Mov DS, AX 544 | Assume DS:Object1 545 | 546 | Mov [HelpKeyValue], 157h 547 | Mov [OrderKeyValue], 13Bh 548 | 549 | Jmp CmdLine1 550 | Assume DS:Nothing 551 | 552 | DisableColours: 553 | Call D_DisableFileColours 554 | Jmp CmdLine1 555 | 556 | Reverse1: 557 | Call Music_ReverseChannels 558 | Jmp CmdLine1 559 | 560 | OverrideVGA: 561 | LodsB 562 | 563 | Mov CX, Screen 564 | Mov DS, CX 565 | Assume DS:Screen 566 | 567 | Cmp AL, '1' 568 | JE OverrideVGA1 569 | Cmp AL, '2' 570 | JE Matrox 571 | Cmp AL, '3' 572 | JE WaitforRetrace 573 | Cmp AL, '4' 574 | JE Retrace 575 | Jmp CmdLine3 576 | 577 | OverrideVGA1: 578 | Or [VGAFlags], 1 579 | Jmp CmdLine1 580 | 581 | WaitforRetrace: 582 | Or [VGAFlags], 4 583 | Jmp CmdLine1 584 | 585 | Retrace: 586 | Or [VGAFlags], 2 587 | Jmp CmdLine1 588 | 589 | Matrox: 590 | Mov [CharacterGenerationOffset], 256*32 591 | 592 | Mov AX, Mouse 593 | Mov DS, AX 594 | Assume DS:Mouse 595 | Mov [MouseCharacterGenerationOffset], 256*32 596 | 597 | Jmp CmdLine1 598 | Assume DS:Nothing 599 | 600 | SetControl: 601 | Mov [CS:Control], 1 602 | Jmp CmdLine1 603 | 604 | ShowCmdLineHelp: 605 | Push CS 606 | Pop DS 607 | 608 | Mov AH, 9 609 | Mov DX, Offset CmdLineHelp 610 | Int 21h 611 | 612 | Mov AX, 4C00h 613 | Int 21h 614 | 615 | SetSoundCard1: 616 | Call GetDecimalNumber 617 | JC SetSoundCardDriver 618 | Cmp CX, 21 619 | JA SetSoundCard2 620 | 621 | Push AX 622 | Mov AX, CX 623 | Call Music_SetSoundCard 624 | Pop AX 625 | 626 | SetSoundCard2: 627 | Jmp CmdLine3 628 | 629 | SetSoundCardDriver: 630 | Cmp AL, 32 631 | JBE CmdLine3 632 | 633 | Dec SI 634 | Call Music_SetSoundCardDriver 635 | 636 | SetSoundCardDriver1: 637 | LodsB 638 | Cmp AL, 32 639 | JA SetSoundCardDriver1 640 | 641 | Mov Byte Ptr [SI-1], 0 642 | Cmp AL, 32 643 | JE CmdLine1 644 | Jmp CmdLineEnd 645 | 646 | ConvertModule: 647 | Mov [CS:StartupList], 1 648 | Mov [CS:StartupFileOffset], SI 649 | Mov [CS:StartupFileSegment], DS 650 | Jmp SetSoundCardDriver1 651 | 652 | SetDMA1: 653 | LodsB 654 | Cmp AL, '0' 655 | JB CmdLine3 656 | Cmp AL, '7' 657 | JA CmdLine3 658 | Sub AL, '0' 659 | Call Music_SetDMA 660 | Jmp CmdLine1 661 | 662 | SetMixSpeed1: 663 | Call GetDecimalNumber 664 | JC SetMixSpeedError 665 | Push AX 666 | Call Music_SetMixSpeed 667 | Pop AX 668 | Jmp CmdLine3 669 | 670 | SetMixSpeedError: 671 | Push CS 672 | Pop DS 673 | Assume DS:StartUp 674 | 675 | Mov AH, 9 676 | Mov DX, Offset MixErrorMsg 677 | Int 21h 678 | 679 | Mov [Pause], 1 680 | Jmp CmdLine1 681 | Assume DS:Nothing 682 | 683 | SetIRQ1: 684 | Call GetDecimalNumber 685 | JC IRQError 686 | Cmp CX, 15 687 | JA IRQError 688 | 689 | Push AX 690 | Call Music_SetIRQ 691 | Pop AX 692 | Jmp CmdLine3 693 | 694 | IRQError: 695 | Push CS 696 | Pop DS 697 | Assume DS:StartUp 698 | 699 | Mov AH, 9 700 | Mov DX, Offset IRQErrorMsg 701 | Int 21h 702 | 703 | Mov [Pause], 1 704 | Jmp CmdLine1 705 | Assume DS:Nothing 706 | 707 | 708 | SetAddress1: 709 | LodsB 710 | 711 | Xor DX, DX 712 | Mov CL, 4 713 | 714 | Cmp AL, '0' 715 | JB SetAddress2 716 | Cmp AL, '9' 717 | JA SetAddress2 718 | Sub AL, '0' 719 | Jmp SetAddress3 720 | 721 | SetAddress2: 722 | Call CapitaliseAL 723 | 724 | Cmp AL, 'A' 725 | JB CmdLine2 726 | Cmp AL, 'F' 727 | JA CmdLine2 728 | Sub AL, '@' 729 | 730 | SetAddress3: 731 | Test DX, 0F000h 732 | JNZ AddressError 733 | 734 | ShL DX, CL 735 | Or DL, AL 736 | 737 | LodsB 738 | Cmp AL, '0' 739 | JB SetAddress4 740 | Cmp AL, '9' 741 | JA SetAddress4 742 | Sub AL, '0' 743 | Jmp SetAddress3 744 | 745 | SetAddress4: 746 | Call CapitaliseAL 747 | Cmp AL, 'A' 748 | JB SetAddress5 749 | Cmp AL, 'F' 750 | JA SetAddress5 751 | 752 | Sub AL, '@' 753 | Jmp SetAddress3 754 | 755 | SetAddress5: 756 | Call Music_SetAddress 757 | Jmp CmdLine3 758 | 759 | AddressError: 760 | Push CS 761 | Pop DS 762 | Assume DS:StartUp 763 | 764 | Mov AH, 9 765 | Mov DX, Offset AddressErrorMsg 766 | Int 21h 767 | 768 | Mov [Pause], 1 769 | Jmp CmdLine1 770 | Assume DS:Nothing 771 | 772 | Limit1: 773 | Call GetDecimalNumber 774 | JC LimitError 775 | Cmp CX, 256 776 | JA LimitError 777 | Cmp CX, 4 778 | JB LimitError 779 | 780 | Push AX 781 | Call Music_SetLimit 782 | Pop AX 783 | Jmp CmdLine3 784 | 785 | LimitError: 786 | Push CS 787 | Pop DS 788 | Assume DS:StartUp 789 | 790 | Mov AH, 9 791 | Mov DX, Offset LimitErrorMsg 792 | Int 21h 793 | 794 | Mov [Pause], 1 795 | Jmp CmdLine1 796 | Assume DS:Nothing 797 | */ 798 | } 799 | 800 | 801 | CmdLineEnd: 802 | printf("Command Line Parsed\n"); 803 | 804 | printf("Windows Detection\n"); 805 | 806 | // if(windows_exists() && windows_version() < 4) { printf(WindowsMsg); press_a_key(); } 807 | 808 | Start1: 809 | // Get Comspec 810 | if(Pause == 1) 811 | { 812 | /* 813 | Mov DX, Offset ContinueMsg 814 | Mov AH, 9 815 | Int 21h 816 | 817 | Xor AX, AX 818 | Int 16h 819 | */ 820 | } 821 | 822 | NoPause: 823 | printf("Retrieving Environment\n"); 824 | 825 | /* 826 | Mov SI, Offset COMSPECString 827 | Mov CX, 7 828 | Call GetEnvironment 829 | JC Start2 830 | 831 | Mov [COMSPECFound], 1 832 | Mov [Word Ptr COMSPEC], DI 833 | Mov [Word Ptr COMSPEC+2], ES 834 | 835 | Start2: 836 | */ 837 | //Mov FS, [CS:PSP] 838 | 839 | printf("Initialising Screen Module\n"); 840 | 841 | //S_InitScreen(); 842 | 843 | printf("Initialising Disk Module\n"); 844 | 845 | //D_InitDisk(); 846 | 847 | printf("Initialising Expanded Memory Module\n"); 848 | 849 | //E_InitEMS(); 850 | 851 | printf("Initialising Music Module\n"); 852 | 853 | Music_InitMusic(ite); 854 | 855 | printf("Initialising Keyboard Module\n"); 856 | 857 | //K_InitKeyBoard(); 858 | 859 | printf("Initialising Edit Module\n"); 860 | 861 | //PE_InitPatternEdit(); 862 | 863 | printf("Initialising Custom Keyboard Layout\n"); 864 | 865 | //K_InstallKeyboardType(); 866 | 867 | printf("Initialising Error Handler Module\n"); 868 | 869 | //Error_InitHandler(); 870 | 871 | if(LoadMMTSR != 0) 872 | { 873 | printf("Initialising MMTSR Module\n"); 874 | 875 | //MMTSR_InstallMMTSR(); 876 | } 877 | 878 | printf("Initialising Mouse Module\n"); 879 | 880 | //InitMouse(); 881 | 882 | //S_ClearScreen(); 883 | 884 | printf("Initialising Timer Module\n"); 885 | 886 | //InitTimerHandler(); 887 | 888 | printf("Initialising Soundcard\n"); 889 | 890 | Music_AutoDetectSoundCard(ite); 891 | 892 | printf("Entering Main Message Loop\n"); 893 | 894 | /* 895 | Mov DI, Offset O1_AutoDetectList 896 | Mov CX, 0FFFFh 897 | M_Object1List(); 898 | Jmp Quit1 899 | */ 900 | Quit1(ite); 901 | } 902 | 903 | int Quit(it_engine *ite) 904 | { 905 | /* 906 | Mov DI, Offset O1_ConfirmQuit 907 | Mov CX, 3 908 | Call M_Object1List 909 | 910 | And DX, DX 911 | JNZ Quit1 912 | 913 | Mov AX, 1 914 | RetF 915 | */ 916 | Quit1(ite); 917 | return 0; 918 | } 919 | 920 | #if 0 921 | ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ 922 | 923 | Proc IsStartupKeyList Far 924 | 925 | Mov AL,CS:StartupList 926 | 927 | Ret 928 | 929 | EndP IsStartupKeyList 930 | 931 | ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ 932 | 933 | Proc GetStartupKeyList Far 934 | 935 | Jmp [CS:StartupKeyListFunction] 936 | 937 | GetStartupKeyList1: 938 | Push SI 939 | Mov SI, [CS:StartupQueueOffset] 940 | 941 | Mov CX, [CS:SI] 942 | Mov DX, [CS:SI+2] 943 | 944 | Add SI, 4 945 | Mov [CS:StartupQueueOffset], SI 946 | 947 | Cmp SI, [CS:StartupQueueEnd] 948 | 949 | Pop SI 950 | JB GetStartupKeyList1End 951 | 952 | Mov AX, [CS:StartupQueueNextFunction] 953 | Mov [CS:StartupKeyListFunction], AX 954 | 955 | GetStartupKeyList1End: 956 | Ret 957 | 958 | GetStartupKeyList2: 959 | Push DS 960 | Push SI 961 | 962 | LDS SI, [DWord Ptr CS:StartupFileOffset] 963 | LodsB 964 | 965 | Mov [CS:StartupFileOffset], SI 966 | 967 | Pop SI 968 | Pop DS 969 | 970 | Cmp AL, 32 971 | JE GetStartupKeyList2EndOfString 972 | And AX, 0FFh 973 | JZ GetStartupKeyList2EndOfString 974 | 975 | Mov DX, AX 976 | Mov CX, 1FFh 977 | 978 | Ret 979 | 980 | GetStartupKeyList2EndOfString: 981 | Mov [CS:StartupQueueOffset], Offset SaveInformation 982 | Mov [CS:StartupQueueEnd], Offset ENDSAVEINFORMATION 983 | Mov [CS:StartupQueueNextfunction], Offset GetStartupKeyList3 984 | Mov [CS:StartupKeyListFunction], Offset GetStartupKeyList1 985 | 986 | Mov CX, 11Ch ; Enter 987 | Mov DX, 0 988 | 989 | Ret 990 | 991 | GetStartupKeyList3: ; Save module then quit 992 | Xor CX, CX 993 | Xor DX, DX 994 | Mov [CS:StartupList], 0 995 | Ret 996 | 997 | EndP GetStartupKeyList 998 | 999 | ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ 1000 | 1001 | Proc CrashRecovery Far ; CtrlAltDel location. 1002 | 1003 | ClD 1004 | StI 1005 | 1006 | Call S_ClearScreen 1007 | Call S_InitScreen 1008 | Call D_InitDisk 1009 | Call InitMouse 1010 | 1011 | Mov DI, Offset O1_CrashRecovery 1012 | Mov CX, 0FFFFh 1013 | Call M_Object1List 1014 | 1015 | Mov DI, Offset O1_PatternEditList 1016 | Mov CX, 0FFFFh 1017 | Jmp M_Object1List 1018 | 1019 | EndP CrashRecovery 1020 | 1021 | ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ 1022 | 1023 | Proc GetEnvironment Far ; DS:SI points to string. 1024 | ; CX = length of string. 1025 | ; Returns ES:DI 1026 | 1027 | Mov ES, [CS:PSP] 1028 | Mov ES, [ES:2Ch] ; DS:00 points to environ. 1029 | Xor DI, DI 1030 | 1031 | GetEnvironment1: 1032 | Push DI 1033 | Push CX 1034 | Push SI 1035 | 1036 | RepE CmpSB 1037 | 1038 | Pop SI 1039 | Pop CX 1040 | Pop DI 1041 | 1042 | JE GetEnvironment3 ; From RepE 1043 | 1044 | Xor AL, AL 1045 | 1046 | GetEnvironment2: 1047 | ScasB 1048 | JNE GetEnvironment2 1049 | 1050 | Cmp [Byte Ptr ES:DI], AL 1051 | JNE GetEnvironment1 1052 | 1053 | StC 1054 | Ret 1055 | 1056 | GetEnvironment3: 1057 | Add DI, CX 1058 | Inc DI ; Skip past '=' 1059 | ClC 1060 | Ret 1061 | 1062 | EndP GetEnvironment 1063 | 1064 | ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ 1065 | 1066 | Proc Refresh Far 1067 | 1068 | Call D_GetPreShellDirectory 1069 | Call S_InitScreen 1070 | Call D_InitDisk 1071 | Call InitMouse 1072 | Call D_RestorePreShellDirectory 1073 | 1074 | Mov AX, 1 1075 | Ret 1076 | 1077 | EndP Refresh 1078 | 1079 | ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ 1080 | 1081 | Proc DOSShell Far 1082 | 1083 | PushAD 1084 | Push DS 1085 | Push ES 1086 | 1087 | PushF 1088 | 1089 | Call D_GetPreShellDirectory 1090 | 1091 | Cmp [CS:Control], 0 1092 | JNE DOSShell2 1093 | 1094 | Call K_UnInitKeyBoard 1095 | Jmp DOSShell3 1096 | 1097 | DOSShell2: 1098 | Call K_InstallDOSHandler 1099 | DOSShell3: 1100 | 1101 | Mov AX, 3 1102 | Int 10h ; Clr screen. 1103 | 1104 | Call UnInitMouse 1105 | 1106 | Push CS 1107 | Push CS 1108 | Pop DS 1109 | Pop ES 1110 | Assume DS:StartUp 1111 | 1112 | Mov AH, 9 1113 | Mov DX, Offset ShellMsg 1114 | Int 21h 1115 | 1116 | Mov AX, 4B00h 1117 | Mov BX, Offset ExecData 1118 | Mov DX, Offset DefaultShell 1119 | Cmp [COMSPECFound], 0 1120 | JE DOSShell1 1121 | 1122 | LDS DX, [COMSPEC] 1123 | 1124 | DOSShell1: 1125 | ClI 1126 | Int 21h 1127 | Assume DS:Nothing 1128 | 1129 | PopF 1130 | 1131 | Call S_InitScreen 1132 | Call D_InitDisk 1133 | Call InitMouse 1134 | 1135 | Cmp [CS:Control], 0 1136 | JNE DOSShell4 1137 | 1138 | Call K_InitKeyBoard 1139 | Jmp DOSShell5 1140 | 1141 | DOSShell4: 1142 | Call K_UnInstallDOSHandler 1143 | 1144 | DOSShell5: 1145 | Call D_RestorePreShellDirectory 1146 | 1147 | Pop ES 1148 | Pop DS 1149 | PopAD 1150 | 1151 | Mov AX, 1 1152 | Ret 1153 | 1154 | EndP DOSShell 1155 | Assume DS:Nothing 1156 | 1157 | ;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ 1158 | 1159 | 1160 | EndS 1161 | 1162 | ;ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ 1163 | ;³ Stack Segment ³ 1164 | ;ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ 1165 | 1166 | Segment StackSeg PARA Stack 'Stack' 1167 | StackData DB StackSize Dup(?) 1168 | EndS 1169 | 1170 | ;ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ 1171 | 1172 | End Start 1173 | #endif 1174 | 1175 | int main(int argc, char *argv[]) 1176 | { 1177 | it_engine *ite = ITEngineNew(); 1178 | Start(ite, ""); 1179 | return 0; 1180 | } 1181 | 1182 | -------------------------------------------------------------------------------- /src/player/it_m_eff.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2014, Jeffrey Lim. All Rights Reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | 3. The name of the author may not be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 19 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 20 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #include "it_struc.h" 30 | 31 | uint8_t SlideTable[9] = { 1, 4, 8, 16, 32, 64, 96, 128, 255 }; 32 | 33 | void InitVolumeEffectH(it_engine *ite, it_host *chn, uint8_t ah); 34 | void InitCommandD7(it_engine *ite, it_host *chn, it_slave *slave); 35 | void InitCommandG11(it_engine *ite, it_host *chn); 36 | void InitCommandX2(it_engine *ite, it_host *chn, uint8_t al); 37 | void CommandD2(it_engine *ite, it_host *chn, it_slave *slave, uint8_t al); 38 | void CommandEChain(it_engine *ite, it_host *chn, int16_t bx); 39 | void CommandFChain(it_engine *ite, it_host *chn, int16_t bx); 40 | void InitVibrato(it_engine *ite, it_host *chn); 41 | void CommandH5(it_engine *ite, it_host *chn, it_slave *slave, int8_t al); 42 | void InitTremelo(it_engine *ite, it_host *chn); 43 | void CommandR2(it_engine *ite, it_host *chn, it_slave *slave, int8_t al); 44 | 45 | /* 46 | // Not transcribing further unless there is a good reason to. 47 | int32_t GetC5Speed(uint8_t *ds, uint8_t *es, uint16_t bx) 48 | { 49 | if(*(uint8_t *)(ds + di + 0x0F) == 101) 50 | { 51 | // OK.. we have a MIDI sample 52 | // Check whether the midi sample points to a valid sample 53 | // And if so, use that sample's C5 speed. 54 | 55 | uint16_t si = *(uint8_t *)(ds + di + 0x03); // Not a note? 56 | uint32_t ebp = *(uint8_t *)(ds + di + 0x04); 57 | 58 | if(ebp != 0) // No sample? 59 | { 60 | si += si; 61 | ebp = *(uint16_t *)(es + 64710 + ebp + ebp); 62 | uint8_t al = *(uint8_t *)(es + ebp + si + 0x40) // AL = note 63 | uint8_t ah = *(uint8_t *)(es + ebp + si + 0x41) // AH = sample. 64 | 65 | if(ah != 0) // No sample? 66 | { 67 | si = ah*2; 68 | si = *(uint16_t *)(es + 64910 + si) // Sample offset 69 | 70 | if(*(uint8_t *)(es + si + 0x12) == 1) 71 | { 72 | bx = si; 73 | } 74 | } 75 | } 76 | } 77 | 78 | return *(uint8_t *)(es + bx + 0x3C); // EAX = C5Spd 79 | } 80 | */ 81 | 82 | void InitVolumeEffect(it_engine *ite, it_host *chn) // Done A, B, H 83 | { 84 | if((chn->Msk & 0x44) == 0) 85 | return; 86 | 87 | uint8_t al = chn->Vol; 88 | uint8_t ah = al; 89 | 90 | al &= 0x7F; 91 | if(al < 65) 92 | return; 93 | al -= 65; 94 | 95 | if((ah & 0x80) != 0) 96 | { 97 | al += 60; 98 | } 99 | 100 | uint8_t dl = 10; 101 | ah = 0; 102 | uint8_t tmpquo = al / dl; 103 | uint8_t tmprem = al % dl; 104 | al = tmpquo; // Effect number 105 | ah = tmprem; // Effect parameter 106 | chn->VCm = al; // Store effect number 107 | 108 | // Memory for effects A->D, (EFG)/H dont' share. 109 | 110 | // Effects Ax and Bx (fine volume slide up and down) require immediate 111 | // handling. No flags required. (effect 0 and 1) 112 | 113 | // Effects Cx, Dx, Ex, Fx (volume/pitch slides) require flag to be 114 | // set (effects 2->5) 115 | 116 | // Effects Gx and Hx need init (handling) code + flags. 117 | // (effects 6 and 7). 118 | 119 | if(ah != 0) 120 | { 121 | if(al >= 4) 122 | { 123 | if(al < 6) 124 | { 125 | // Ex Fx 126 | chn->EFG = ah<<2; 127 | } else if(al <= 6) { 128 | // Gx 129 | if((ite->hdr.Flags & 0x0020) != 0) // Link command G? 130 | { 131 | chn->GOE = SlideTable[ah-1]; 132 | } else { 133 | chn->EFG = SlideTable[ah-1]; 134 | } 135 | } 136 | } else { 137 | // Ax Bx Cx Dx 138 | chn->VVal = ah; 139 | } 140 | } 141 | 142 | if((chn->Flags & 0x04) != 0) 143 | { 144 | // Channel not on! 145 | // TODO: work out what this comment means and which it applies to 146 | // (I think it applies to this block) 147 | 148 | it_slave *slave = &ite->slave[chn->SCOffst]; 149 | 150 | if(al <= 1) 151 | { 152 | if(al != 1) 153 | { 154 | al = chn->VVal; 155 | al += slave->VS; 156 | if(al > 64) 157 | al = 64; 158 | } else { 159 | al = chn->VVal; 160 | al -= slave->VS; 161 | if((al & 0x80) != 0) 162 | al = 0; 163 | } 164 | 165 | CommandD2(ite, chn, slave, al); 166 | return; 167 | } else { 168 | chn->Flags |= 0x0100; 169 | 170 | if(al > 6) 171 | { 172 | InitVolumeEffectH(ite, chn, ah); 173 | return; 174 | } else if(al == 6) { 175 | InitCommandG11(ite, chn); 176 | return; 177 | } 178 | return; 179 | } 180 | } else { 181 | if(al == 7) 182 | InitVolumeEffectH(ite, chn, ah); 183 | } 184 | } 185 | 186 | void InitVolumeEffectH(it_engine *ite, it_host *chn, uint8_t ah) 187 | { 188 | ah <<= 2; 189 | if(ah != 0) 190 | chn->VDp = ah; 191 | 192 | if((chn->Flags & 4) != 0) 193 | InitVibrato(ite, chn); 194 | } 195 | 196 | void VolumeCommandC(it_engine *ite, it_host *chn) 197 | { 198 | it_slave *slave = &ite->slave[chn->SCOffst]; 199 | uint8_t al = chn->VVal + slave->VS; 200 | 201 | if(al > 64) 202 | { 203 | chn->Flags &= ~0x0100; // Turn off effect calling 204 | al = 64; 205 | } 206 | 207 | CommandD2(ite, chn, slave, al); 208 | } 209 | 210 | void VolumeCommandD(it_engine *ite, it_host *chn) 211 | { 212 | it_slave *slave = &ite->slave[chn->SCOffst]; 213 | uint8_t al = slave->VS - chn->VVal; 214 | 215 | //if((al & 0x80) != 0) // JNC, not JNS 216 | if(slave->VS < chn->VVal) 217 | { 218 | chn->Flags &= ~0x0100; // Turn off effect calling 219 | al = 0; 220 | } 221 | 222 | CommandD2(ite, chn, slave, al); 223 | } 224 | 225 | void VolumeCommandE(it_engine *ite, it_host *chn) // Pitch slide down 226 | { 227 | CommandEChain(ite, chn, ((int16_t)(uint16_t)chn->EFG)<<2); 228 | } 229 | 230 | void VolumeCommandF(it_engine *ite, it_host *chn) 231 | { 232 | CommandFChain(ite, chn, ((int16_t)(uint16_t)chn->EFG)<<2); 233 | } 234 | 235 | void VolumeCommandG(it_engine *ite, it_host *chn) 236 | { 237 | if((chn->Flags & 0x16) == 0) 238 | return; 239 | 240 | uint16_t bx = chn->EFG; 241 | if((ite->hdr.Flags & 0x0020) != 0) // Link command G? 242 | bx = chn->GOE; 243 | 244 | if(bx == 0) 245 | return; 246 | 247 | bx <<= 2; 248 | it_slave *slave = &ite->slave[chn->SCOffst]; 249 | 250 | if(chn->_42 != 1) 251 | { 252 | // Slide down 253 | PitchSlideDown(ite, chn, slave, bx); 254 | 255 | // Check that frequency is above porta 256 | // to frequency. 257 | int32_t eaxs = slave->Frequency; 258 | if(eaxs <= chn->Porta_Frequency) 259 | { 260 | chn->Flags &= ~0x0110; // Turn off calling 261 | slave->Frequency = eaxs = chn->Porta_Frequency; 262 | } 263 | 264 | slave->Frequency_Set = eaxs; 265 | 266 | } else { 267 | // Slide up! 268 | PitchSlideUp(ite, chn, slave, bx); 269 | 270 | // Check that 271 | // 1) Channel is on 272 | // 2) Frequency (set) is below porta to 273 | // frequency 274 | int32_t eaxs = slave->Frequency; 275 | 276 | if((slave->Flags & 0x0200) != 0 || eaxs > chn->Porta_Frequency) 277 | { 278 | slave->Flags &= ~0x0200; 279 | chn->Flags |= 0x0004; // Turn on. 280 | chn->Flags &= ~0x0110; // Turn off calling 281 | slave->Frequency = eaxs = chn->Porta_Frequency; 282 | } 283 | 284 | slave->Frequency_Set = eaxs; 285 | 286 | } 287 | } 288 | 289 | void InitNoCommand(it_engine *ite, it_host *chn) // DS:DI points to CIT area. 290 | { 291 | it_slave *slave; 292 | uint8_t cl = chn->Msk; // CL = mask 293 | uint8_t ch = chn->Flags; // CH = channel info. 294 | 295 | if((cl & 0x33) == 0) 296 | goto NoOldEffect; // InitCommand1 297 | 298 | uint8_t al = chn->Nt2; 299 | 300 | // Note here! 301 | // Check for noteoff. 302 | if(al >= 120) 303 | { 304 | if((ch & 0x04) == 0) // Taken if the channel's off. 305 | { 306 | // Jump point. 307 | goto NoOldEffect; // InitNoCommand1 308 | } 309 | 310 | slave = &ite->slave[chn->SCOffst]; 311 | 312 | //if(0) 313 | if(al > 0xFE) // Noteoff 314 | { 315 | slave->Flags |= 0x0004; // Note off 316 | // if(slave->VS == 0) // Volume = 0??? 317 | // goto InitNoCommand13; 318 | } else { 319 | //if(al == 0xFE || al == 0xFF) 320 | if(al == 0xFE) 321 | { 322 | ch &= ~4; 323 | 324 | if(chn->Smp != 100 && (ite->d.DriverFlags & 2) == 0) 325 | { 326 | slave->Flags = 0x0200; 327 | goto NoOldEffect; 328 | } 329 | 330 | // MIDINoteCut: 331 | // ch &= ~4; 332 | slave->Flags |= 0x0200; 333 | } else { 334 | slave->Flags |= 8; // Note fade 335 | goto NoOldEffect; 336 | } 337 | } 338 | } else { 339 | if((ch & 4) != 0 && (cl & 0x11) == 0 && ite->slave[chn->SCOffst].Nte != chn->Nte) 340 | goto NoOldEffect; // InitNoCommand1 341 | 342 | if((cl & 0x44) != 0 && chn->Vol >= 193 && chn->Vol <= 202 && (chn->Flags & 4) != 0) 343 | return InitVolumeEffect(ite, chn); 344 | 345 | slave = AllocateChannel(ite, chn, &ch); 346 | if(slave == NULL) 347 | goto NoOldEffect; 348 | 349 | // Channel allocated. 350 | // put volume 351 | slave->Vol = slave->VS = chn->VSe; 352 | it_sample *smp = &ite->smp[slave->SmpOffs]; 353 | 354 | if((ite->hdr.Flags & 4) == 0 && (smp->DfP & 0x80) != 0) 355 | slave->PS = slave->Pan = chn->CP = smp->DfP & 0x7F; 356 | 357 | uint32_t eax = smp->C5Speed; 358 | 359 | slave->OldSampleOffset = 0; 360 | slave->SmpErr = 0; 361 | slave->Sample_Offset = 0; 362 | 363 | // Calculate frequency. 364 | uint64_t da = (uint64_t)eax * (uint64_t)PitchTable[chn->Nt2]; 365 | eax = (uint32_t)(((uint64_t)da)>>(uint64_t)16); 366 | slave->Frequency = slave->Frequency_Set = eax; 367 | 368 | ch |= 4; 369 | ch &= ~16; 370 | } 371 | 372 | GetLoopInformation(ite, slave); 373 | 374 | InitNoCommand1: 375 | if((cl & (0x22 + 0x44)) == 0) 376 | goto InitNoCommand3; 377 | 378 | // Instrument mode and old effects? 379 | if((ite->hdr.Flags & 0x14) != 0x14) 380 | goto NoOldEffect; 381 | 382 | if(cl & 0x22) 383 | goto NoOldEffect; 384 | 385 | if(chn->Ins == 0xFF) 386 | goto NoOldEffect; 387 | 388 | slave->FadeOut = 0x0400; 389 | InitPlayInstrument(ite, chn, slave, chn->Ins); 390 | 391 | NoOldEffect: 392 | // TODO: fix this dreadful flow code once everything works --GM 393 | if((cl & 0x44) == 0) 394 | goto InitNoCommand7; 395 | 396 | if(chn->Vol <= 64) 397 | { 398 | chn->VSe = chn->Vol; 399 | goto InitNoCommand8; // Volume set... 400 | } 401 | 402 | if((chn->Vol & 0x7F) >= 65) 403 | goto InitNoCommand7; 404 | 405 | // Panning set! 406 | InitNoCommandPanning: 407 | chn->Flags = (chn->Flags & 0xFF00) | (0xFF & (uint16_t)ch); 408 | 409 | InitCommandX2(ite, chn, chn->Vol - 128); // Destroys (SI), AX 410 | 411 | InitNoCommand7: 412 | if((cl & 0x22) == 0) // Instrument present? Change volume 413 | goto InitNoCommand3; 414 | 415 | // Get instrument offset. 416 | if(chn->Smp == 0xFF) 417 | goto InitNoCommand3; 418 | 419 | chn->VSe = ite->smp[chn->Smp-1].Vol; // Default volume 420 | 421 | InitNoCommand8: 422 | if((ch & 4) == 0) 423 | goto InitNoCommand3; 424 | 425 | slave = &ite->slave[chn->SCOffst]; 426 | 427 | slave->Vol = slave->VS = chn->VSe; 428 | slave->Flags |= 0x10; // recalc volume 429 | 430 | InitNoCommand3: 431 | // Randomise volume if required. 432 | if((chn->Flags & 0x80) == 0) 433 | { 434 | chn->Flags = (chn->Flags & 0xFF00) | (0xFF & (uint16_t)ch); 435 | return InitVolumeEffect(ite, chn); 436 | } 437 | 438 | chn->Flags = (chn->Flags & 0xFF00) | (0xFF & (uint16_t)ch); 439 | ApplyRandomValues(ite, chn); 440 | return InitVolumeEffect(ite, chn); 441 | } 442 | 443 | void InitCommandA(it_engine *ite, it_host *chn) 444 | { 445 | uint16_t ax = chn->CVal; 446 | 447 | if(ax != 0) 448 | { 449 | ite->CurrentTick -= ite->CurrentSpeed; 450 | ite->ProcessTick -= ite->CurrentSpeed; 451 | ite->CurrentTick += ax; 452 | ite->ProcessTick += ax; 453 | ite->CurrentSpeed = ax; 454 | } 455 | 456 | return InitNoCommand(ite, chn); 457 | } 458 | 459 | void InitCommandB(it_engine *ite, it_host *chn) 460 | { 461 | uint16_t ax = chn->CVal; 462 | 463 | if(ax < ite->CurrentOrder) 464 | ite->StopSong = 1; 465 | 466 | ax--; 467 | ite->ProcessOrder = ax; 468 | ite->ProcessRow = 0xFFFE; 469 | 470 | return InitNoCommand(ite, chn); 471 | } 472 | 473 | void InitCommandC(it_engine *ite, it_host *chn) 474 | { 475 | if(ite->PatternLooping == 0) 476 | { 477 | ite->BreakRow = chn->CVal; 478 | ite->ProcessRow = 0xFFFE; 479 | } 480 | 481 | return InitNoCommand(ite, chn); 482 | } 483 | 484 | void InitCommandD(it_engine *ite, it_host *chn) 485 | { 486 | InitNoCommand(ite, chn); 487 | 488 | if(chn->CVal != 0) 489 | chn->DKL = chn->CVal; 490 | 491 | if((chn->Flags & 4) == 0) 492 | return; 493 | 494 | it_slave *slave = &ite->slave[chn->SCOffst]; 495 | 496 | return InitCommandD7(ite, chn, slave); 497 | } 498 | 499 | void InitCommandD7(it_engine *ite, it_host *chn, it_slave *slave) 500 | { 501 | // Jmp point for Lxx 502 | 503 | slave->Flags |= 16; // Recalc vol 504 | 505 | // TODO: verify 506 | if((chn->DKL & 0x0F) == 0) { 507 | // Slide up. 508 | chn->VCh = chn->DKL>>4; 509 | chn->Flags |= 1; 510 | 511 | if(chn->VCh == 0x0F) 512 | return CommandD(ite, chn); 513 | } else if((chn->DKL & 0xF0) == 0) { 514 | // Slide down 515 | chn->VCh = -chn->DKL; 516 | chn->Flags |= 1; 517 | 518 | if(chn->VCh == (uint8_t)-0x0F) 519 | return CommandD(ite, chn); 520 | } else if((chn->DKL & 0x0F) == 0x0F) { 521 | InitCommandD5: 522 | // Slide up (fine) 523 | chn->VCh = 0; 524 | 525 | uint8_t al = (chn->DKL >> 4) + slave->VS; 526 | if(al > 64) 527 | al = 64; 528 | 529 | slave->Vol = slave->VS = chn->VSe = al; 530 | 531 | } else if((chn->DKL & 0xF0) == 0xF0) { 532 | // Slide down (fine) 533 | chn->VCh = 0; 534 | 535 | uint8_t al = slave->VS - (chn->DKL & 0x0F); 536 | 537 | if((al & 0x80) != 0) 538 | al = 0; 539 | 540 | slave->Vol = slave->VS = chn->VSe = al; 541 | } 542 | } 543 | 544 | void InitCommandE(it_engine *ite, it_host *chn) 545 | { 546 | InitNoCommand(ite, chn); 547 | 548 | if(chn->CVal != 0) 549 | chn->EFG = chn->CVal; 550 | 551 | if((chn->Flags & 4) == 0) 552 | return; 553 | 554 | it_slave *slave = &ite->slave[chn->SCOffst]; 555 | 556 | // OK.. now processing is dependent 557 | // upon slide mode. 558 | 559 | if(chn->EFG == 0) // still no slide?? 560 | return; 561 | 562 | if((chn->EFG & 0xF0) >= 0xE0) 563 | { 564 | if((chn->EFG & 0x0F) == 0) 565 | return; 566 | 567 | uint8_t al = chn->EFG & 0x0F; 568 | if((chn->EFG & 0xF0) != 0xE0) 569 | al <<= 2; 570 | 571 | PitchSlideDown(ite, chn, slave, al); 572 | 573 | slave->Frequency_Set = slave->Frequency; 574 | } else { 575 | chn->_40 = ((int16_t)chn->EFG)<<2; 576 | 577 | // call update only if necess. 578 | chn->Flags |= 1; 579 | } 580 | } 581 | 582 | void InitCommandF(it_engine *ite, it_host *chn) 583 | { 584 | // TODO: verify 585 | InitNoCommand(ite, chn); 586 | 587 | if(chn->CVal != 0) 588 | chn->EFG = chn->CVal; 589 | 590 | if((chn->Flags & 4) == 0) 591 | return; 592 | 593 | it_slave *slave = &ite->slave[chn->SCOffst]; 594 | 595 | // OK.. now processing is dependent 596 | // upon slide mode. 597 | 598 | if(chn->EFG == 0) // still no slide?? 599 | return; 600 | 601 | if((chn->EFG & 0xF0) >= 0xE0) 602 | { 603 | if((chn->EFG & 0x0F) == 0) 604 | return; 605 | 606 | uint8_t al = chn->EFG & 0x0F; 607 | if((chn->EFG & 0xF0) != 0xE0) 608 | al <<= 2; 609 | 610 | PitchSlideUp(ite, chn, slave, al); 611 | 612 | slave->Frequency_Set = slave->Frequency; 613 | } else { 614 | // note: not negative. this point proves crucial for some things --GM 615 | chn->_40 = (((int16_t)chn->EFG)<<2); 616 | 617 | // call update only if necess. 618 | chn->Flags |= 1; 619 | } 620 | } 621 | 622 | // InitCommandG15 = InitNoCommand 623 | void InitCommandG(it_engine *ite, it_host *chn) 624 | { 625 | // Check whether channel on/owned 626 | if(chn->CVal != 0) 627 | { 628 | // Compatibility Gxx? 629 | if((ite->hdr.Flags & 0x20) != 0) 630 | chn->GOE = chn->CVal; 631 | else 632 | chn->EFG = chn->CVal; 633 | } 634 | 635 | if((chn->Flags & 4) == 0) 636 | { 637 | InitNoCommand(ite, chn); 638 | } else { 639 | InitCommandG11(ite, chn); 640 | } 641 | } 642 | 643 | void InitCommandG11(it_engine *ite, it_host *chn) 644 | { 645 | // added some flow comments because, well, the flow is weird --GM 646 | 647 | // Jumped to from Lxx 648 | it_slave *slave = &ite->slave[chn->SCOffst]; 649 | 650 | int skipnote = 0; 651 | 652 | if((chn->Msk & 0x22) != 0 && (chn->Smp != 0)) // false -> G13 653 | { 654 | int has_g18 = 0; 655 | // Checking for change of Sample or instrument. 656 | if((ite->hdr.Flags & 0x20) == 0) // false -> GXXCompat1 657 | { 658 | // Don't overwrite note if MIDI! 659 | if(chn->Smp != 101) // false -> G13 660 | { 661 | uint8_t oldsmp = slave->Smp; 662 | uint8_t oldins = slave->Ins; 663 | slave->Nte = chn->Nte; 664 | slave->Ins = chn->Ins; 665 | 666 | /* 667 | flow here is kinda odd: 668 | 669 | INS SMP 670 | = = -> G13 671 | ! = -> G18 672 | = ! -> G16 673 | ! ! -> G16 674 | */ 675 | 676 | if(oldsmp != chn->Smp-1) // Sample the same? 677 | { 678 | // G16 679 | it_sample *smp = &ite->smp[chn->Smp-1]; 680 | slave->Flags = (slave->Flags & 0xFF) | 0x0100; 681 | 682 | // Now to update sample info. 683 | slave->SmpOffs = chn->Smp-1; 684 | slave->Smp = chn->Smp-1; 685 | 686 | slave->ViDepth = 0; // Reset vibrato.. 687 | slave->LpD = 0; // Reset loop direction. 688 | slave->OldSampleOffset = 0; 689 | slave->SmpErr = 0; 690 | slave->Sample_Offset = 0; 691 | 692 | slave->SVl = smp->GvL*2; 693 | 694 | if((smp->Flg & 1) == 0) 695 | { 696 | slave->Flags = 0x0200; 697 | chn->Flags &= ~4; 698 | return; 699 | } 700 | 701 | // 16 bit... 702 | slave->Bit = (smp->Flg & 2); 703 | 704 | GetLoopInformation(ite, slave); 705 | 706 | // follow onto G18 707 | has_g18 = 1; 708 | } else if(oldins != chn->Ins) { // Ins the same? 709 | // follow onto G18 710 | has_g18 = 1; 711 | } 712 | } 713 | 714 | } else { 715 | // GXXCompat1 716 | chn->Smp = slave->Smp+1; 717 | 718 | it_sample *smp = &ite->smp[slave->Smp]; 719 | slave->SVl = smp->GvL*2; 720 | 721 | // follow onto G18 722 | has_g18 = 1; 723 | } 724 | 725 | // G18 726 | if(has_g18) 727 | { 728 | if((ite->hdr.Flags & 4) != 0) // Instrument/sample mode? 729 | // false -> G14 730 | { 731 | // Now for instruments 732 | slave->FadeOut = 0x0400; 733 | it_instrument *ins = &ite->ins[chn->Ins-1]; 734 | 735 | uint16_t oldflags = slave->Flags; 736 | 737 | InitPlayInstrument(ite, chn, slave, chn->Ins); 738 | 739 | if((oldflags & 1) != 0) 740 | slave->Flags &= ~0x100; 741 | 742 | slave->SVl = ((uint16_t)ins->GbV * (uint16_t)slave->SVl)>>7; 743 | // follow onto G14 744 | } 745 | 746 | skipnote = 1; // -> G14 common jump 747 | } 748 | } 749 | 750 | // G13 (refers to the actual mask condition) 751 | if((skipnote != 0) || (chn->Msk & 0x11) != 0) // false -> G1 752 | { 753 | // G14 754 | // OK. Time to calc freq. 755 | if(chn->Nt2 > 119) // false -> G5 756 | { 757 | if((chn->Flags & 4) != 0) // false -> G1 758 | { 759 | if(chn->Nt2 > 0xFE) 760 | { 761 | // Note off 762 | slave->Flags |= 4; 763 | GetLoopInformation(ite, slave); 764 | 765 | } else if(chn->Nt2 != 0xFE) { 766 | slave->Flags |= 8; 767 | 768 | } else { 769 | // Note cut! 770 | chn->Flags &= ~4; 771 | slave->Flags = 0x200; // Cut. 772 | } 773 | } 774 | 775 | } else { 776 | // Don't overwrite note if MIDI! 777 | if(chn->Smp != 101) 778 | slave->Nte = chn->Nt2; 779 | 780 | it_sample *smp = &ite->smp[slave->SmpOffs]; 781 | 782 | uint64_t c5 = ((uint64_t)smp->C5Speed) * (uint64_t)PitchTable[chn->Nt2]; 783 | 784 | c5 >>= (uint64_t)16; 785 | 786 | chn->Porta_Frequency = c5; 787 | chn->Flags |= 16; 788 | } 789 | } 790 | 791 | int revol = -1; 792 | if((chn->Msk & 0x44) != 0) 793 | { 794 | if(chn->Vol <= 64) 795 | { 796 | revol = chn->Vol; 797 | } else if((chn->Vol & 0x7F) < 65) { 798 | // Panning set... 799 | InitCommandX2(ite, chn, chn->Vol - 128); 800 | } 801 | } 802 | 803 | if(revol == -1 && (chn->Msk & 0x22) != 0) 804 | revol = ite->smp[slave->SmpOffs].Vol; 805 | 806 | if(revol != -1) 807 | { 808 | slave->Flags |= 16; // recalc volume. 809 | chn->VSe = slave->Vol = slave->VS = revol; 810 | } 811 | 812 | if((chn->Flags & 16) != 0) // Slide on??? 813 | { 814 | // Work out magnitude + dirn 815 | int16_t ax = chn->EFG; 816 | 817 | if((ite->hdr.Flags & 0x20) != 0) // Command G memory 818 | ax = chn->GOE; 819 | 820 | ax <<= 2; 821 | if(ax != 0) 822 | { 823 | chn->_40 = ax; 824 | 825 | if(chn->Porta_Frequency > slave->Frequency_Set) 826 | { 827 | // slide up 828 | chn->_42 = 1 | (chn->_42 & 0xFF00); 829 | 830 | if((chn->Flags & 0x100) == 0) 831 | chn->Flags |= 1; // Update effect if necess. 832 | 833 | } else if(chn->Porta_Frequency < slave->Frequency_Set) { 834 | // slide down. 835 | chn->_42 = 0 | (chn->_42 & 0xFF00); 836 | 837 | if((chn->Flags & 0x100) == 0) 838 | chn->Flags |= 1; // Update effect if necess. 839 | 840 | } 841 | 842 | // equal?!?!? 843 | // then don't update effect. 844 | } 845 | } 846 | 847 | // Don't call volume effects if it has a Gxx! 848 | if((chn->Flags & 0x100) == 0) // comment this out and you'll get a stack overflow on a Gx VE --GM 849 | InitVolumeEffect(ite, chn); 850 | } 851 | 852 | void InitCommandH(it_engine *ite, it_host *chn) 853 | { 854 | if((chn->Msk & 0x11) != 0 && chn->Nte <= 119) 855 | { 856 | chn->VPo = 0; 857 | chn->LVi = 0; 858 | } 859 | 860 | uint8_t ah = (chn->CVal & 0x0F); // AH = depth 861 | uint8_t al = (chn->CVal & 0xF0); // AL = speed. 862 | 863 | if(ah != 0 || al != 0) 864 | { 865 | al >>= 2; 866 | if(al != 0) 867 | chn->VSp = al; 868 | 869 | ah <<= 2; 870 | if(ah != 0) 871 | { 872 | if((ite->hdr.Flags & 0x10) != 0) 873 | ah *= 2; 874 | 875 | chn->VDp = ah; 876 | } 877 | } 878 | 879 | InitNoCommand(ite, chn); 880 | 881 | if((chn->Flags & 4) != 0) 882 | { 883 | // Update mode. 884 | chn->Flags |= 1; 885 | InitVibrato(ite, chn); 886 | } 887 | } 888 | 889 | void InitCommandI(it_engine *ite, it_host *chn) 890 | { 891 | InitNoCommand(ite, chn); 892 | 893 | if(chn->CVal != 0) 894 | chn->I00 = chn->CVal; 895 | 896 | if((chn->Flags & 4) != 0) 897 | { 898 | // OK.. now to handle tremor 899 | chn->Flags |= 1; 900 | 901 | uint8_t al = chn->I00 & 0x0F; // AL = Offtime 902 | uint8_t ah = chn->I00 >> 4; // AH = ontime 903 | 904 | if((ite->hdr.Flags & 16) != 0) 905 | { 906 | al++; 907 | ah++; 908 | } 909 | 910 | uint16_t ax = (uint16_t)al | (((uint16_t)ah)<<8); 911 | chn->_40 = ax; // fucking hell Jeff ;_; --GM 912 | 913 | CommandI(ite, chn); 914 | } 915 | } 916 | 917 | void InitCommandJ(it_engine *ite, it_host *chn) 918 | { 919 | InitNoCommand(ite, chn); 920 | 921 | chn->_40 = 0; 922 | if(chn->CVal != 0) 923 | chn->J00 = chn->CVal; 924 | 925 | if((chn->Flags & 4) != 0) 926 | { 927 | chn->Flags |= 1; // Update when channel on 928 | 929 | // TODO: verify - i think this actually stores the freq to mul by, 930 | // which is 32-bit --GM 931 | chn->_44 = (60+(chn->J00&0x0F))*4; 932 | chn->_42 = (60+(chn->J00>>4))*4; 933 | } 934 | } 935 | 936 | void InitCommandK(it_engine *ite, it_host *chn) 937 | { 938 | if(chn->CVal != 0) 939 | chn->DKL = chn->CVal; 940 | 941 | InitNoCommand(ite, chn); 942 | 943 | if((chn->Flags & 4) != 0) 944 | { 945 | InitVibrato(ite, chn); 946 | it_slave *slave = &ite->slave[chn->SCOffst]; 947 | InitCommandD7(ite, chn, slave); 948 | 949 | chn->Flags |= 2; // Always update. 950 | } 951 | } 952 | 953 | void InitCommandL(it_engine *ite, it_host *chn) 954 | { 955 | if(chn->CVal != 0) 956 | chn->DKL = chn->CVal; 957 | 958 | if((chn->Flags & 4) != 0) 959 | { 960 | InitCommandG11(ite, chn); 961 | it_slave *slave = &ite->slave[chn->SCOffst]; 962 | InitCommandD7(ite, chn, slave); 963 | 964 | chn->Flags |= 2; // Always update. 965 | } 966 | } 967 | 968 | void InitCommandM2(it_engine *ite, it_host *chn, uint8_t al) 969 | { 970 | if((chn->Flags & 4) != 0) 971 | { 972 | it_slave *slave = &ite->slave[chn->SCOffst]; 973 | 974 | slave->CVl = al; 975 | slave->Flags |= 16; // recalc volume 976 | } 977 | 978 | chn->CV = al; 979 | } 980 | 981 | void InitCommandM(it_engine *ite, it_host *chn) 982 | { 983 | InitNoCommand(ite, chn); 984 | 985 | if(chn->CVal > 0x40) return; 986 | 987 | InitCommandM2(ite, chn, chn->CVal); 988 | } 989 | 990 | void InitCommandN(it_engine *ite, it_host *chn) 991 | { 992 | if(chn->CVal != 0) 993 | chn->N00 = chn->CVal; 994 | 995 | InitNoCommand(ite, chn); 996 | 997 | if((chn->N00 & 0x0F) == 0) 998 | { 999 | chn->_40 = (chn->_40 & 0xFF00) | ((((int16_t)chn->N00)>>4) & 0xFF); 1000 | chn->Flags |= 2; // Always update effect 1001 | 1002 | } else if((chn->N00 & 0xF0) == 0) { 1003 | chn->_40 = (chn->_40 & 0xFF00) | ((-(int16_t)chn->N00) & 0xFF); 1004 | chn->Flags |= 2; 1005 | 1006 | } else if((chn->N00 & 0x0F) == 0x0F) { 1007 | uint8_t al = (chn->N00>>4) + chn->CV; 1008 | 1009 | if(al > 64) al = 64; 1010 | 1011 | return InitCommandM2(ite, chn, al); 1012 | 1013 | } else if((chn->N00 & 0xF0) == 0xF0) { 1014 | // 1015 | uint8_t al = (chn->N00>>4) - chn->CV; 1016 | 1017 | if((chn->N00>>4) < chn->CV) al = 0; 1018 | 1019 | return InitCommandM2(ite, chn, al); 1020 | 1021 | } 1022 | } 1023 | 1024 | void InitCommandO(it_engine *ite, it_host *chn) 1025 | { 1026 | if(chn->CVal != 0) 1027 | chn->O00 = chn->CVal; 1028 | 1029 | InitNoCommand(ite, chn); 1030 | 1031 | if((chn->Msk & 0x33) == 0) return; 1032 | if(chn->Nt2 >= 120) return; 1033 | if((chn->Flags & 4) == 0) return; 1034 | 1035 | uint32_t eax; 1036 | it_slave *slave = &ite->slave[chn->SCOffst]; 1037 | eax = ((uint32_t)chn->O00) + (((uint32_t)chn->OxH)<<8); 1038 | eax <<= 8; 1039 | 1040 | if(eax >= slave->Loop_End) 1041 | { 1042 | if((ite->hdr.Flags & 16) == 0) return; 1043 | eax = slave->Loop_End-1; 1044 | } 1045 | 1046 | slave->OldSampleOffset = slave->Sample_Offset = eax; 1047 | slave->SmpErr = 0; 1048 | } 1049 | 1050 | void InitCommandP(it_engine *ite, it_host *chn) 1051 | { 1052 | if(chn->CVal != 0) 1053 | chn->P00 = chn->CVal; 1054 | 1055 | InitNoCommand(ite, chn); 1056 | 1057 | uint8_t dl = chn->CP; 1058 | if((chn->Flags & 4) != 0) 1059 | { 1060 | it_slave *slave = &ite->slave[chn->SCOffst]; 1061 | dl = slave->PS; // Pan set 1062 | } 1063 | 1064 | if(dl == 100) // Surround?? 1065 | return; 1066 | 1067 | uint8_t al = chn->P00; 1068 | 1069 | if((al & 0x0F) == 0) 1070 | { 1071 | chn->_40 = (chn->_40 & 0xFF00) + ((-(int16_t)(al >> 4)) & 0x00FF); 1072 | chn->Flags |= 2; // Always update effect 1073 | 1074 | } else if((al & 0xF0) == 0) { 1075 | chn->_40 = (chn->_40 & 0xFF00) + (((int16_t)al) & 0x00FF); 1076 | chn->Flags |= 2; 1077 | 1078 | } else if((al & 0x0F) == 0x0F) { 1079 | uint8_t xal = dl - (al>>4); 1080 | 1081 | if(dl < (al>>4)) xal = 0; 1082 | 1083 | InitCommandX2(ite, chn, xal); 1084 | 1085 | } else if((al & 0xF0) == 0xF0) { 1086 | al = al + dl; 1087 | 1088 | if(al > 64) al = 64; 1089 | 1090 | InitCommandX2(ite, chn, al); 1091 | 1092 | } 1093 | 1094 | } 1095 | 1096 | void InitCommandQ(it_engine *ite, it_host *chn) 1097 | { 1098 | InitNoCommand(ite, chn); 1099 | 1100 | if(chn->CVal != 0) 1101 | chn->Q00 = chn->CVal; 1102 | 1103 | if((chn->Flags & 4) != 0) 1104 | { 1105 | chn->Flags |= 1; 1106 | 1107 | if((chn->Msk & 0x11) != 0) 1108 | { 1109 | chn->RTC = chn->CVal & 0x0F; // retrig countdown 1110 | 1111 | } else { 1112 | CommandQ(ite, chn); 1113 | 1114 | } 1115 | } 1116 | 1117 | } 1118 | 1119 | void InitCommandR(it_engine *ite, it_host *chn) 1120 | { 1121 | uint8_t ah = chn->CVal & 0x0F; // AH = depth 1122 | uint8_t al = chn->CVal & 0xF0; // AL = speed. 1123 | 1124 | if(ah != 0 || al != 0) 1125 | { 1126 | al >>= 2; 1127 | if(al != 0) chn->TSp = al; 1128 | 1129 | ah <<= 1; 1130 | if(ah != 0) chn->TDp = ah; 1131 | } 1132 | 1133 | InitNoCommand(ite, chn); 1134 | 1135 | if((chn->Flags & 4) != 0) 1136 | { 1137 | chn->Flags |= 1; // Update mode. 1138 | InitTremelo(ite, chn); 1139 | } 1140 | } 1141 | 1142 | void InitCommandS(it_engine *ite, it_host *chn) 1143 | { 1144 | uint8_t al = chn->CVal; 1145 | it_slave *slave; 1146 | uint16_t cx; 1147 | 1148 | if(al != 0) 1149 | chn->S00 = al; 1150 | 1151 | al = chn->S00; 1152 | 1153 | uint8_t ah = al; 1154 | ah &= 0xF0; 1155 | al &= 0x0F; 1156 | 1157 | chn->_40 = (ah<<8) | al; // Misc effects data. 1158 | 1159 | switch(ah>>4) 1160 | { 1161 | case 0x0: // 0 1162 | case 0x1: // 1 1163 | case 0x2: // 2 1164 | break; 1165 | 1166 | case 0x3: // 3 - set vibrato waveform 1167 | if(al <= 3) chn->VWF = al; 1168 | break; 1169 | 1170 | case 0x4: // 4 - set tremelo waveform 1171 | if(al <= 3) chn->TWF = al; 1172 | break; 1173 | 1174 | case 0x5: // 5 - set panbrello waveform 1175 | if(al <= 3) 1176 | { 1177 | chn->PWF = al; 1178 | chn->PPo = 0; 1179 | } 1180 | break; 1181 | 1182 | case 0x6: // 6 - extra delay of x frames 1183 | ite->CurrentTick += al; 1184 | ite->ProcessTick += al; 1185 | break; 1186 | 1187 | case 0x7: // 7 - instrument functions 1188 | switch(al) 1189 | { 1190 | case 0x0: // Past note cut 1191 | InitNoCommand(ite, chn); 1192 | al = chn->HCN | 0x80; 1193 | 1194 | for(slave = &ite->slave[0], cx = ite->NumChannels; cx != 0; cx--, slave++) 1195 | { 1196 | if(al != slave->HCN) continue; 1197 | 1198 | if((ite->d.DriverFlags & 2) != 0) 1199 | slave->Flags |= 0x200; 1200 | else 1201 | slave->Flags = 0x200; 1202 | } 1203 | return; 1204 | 1205 | case 0x1: // Past note off 1206 | case 0x2: // Past note fade 1207 | InitNoCommand(ite, chn); 1208 | ah = (al == 0x1 ? 4 : 8); 1209 | for(slave = &ite->slave[0], cx = ite->NumChannels; cx != 0; cx--, slave++) 1210 | { 1211 | if(al == slave->HCN) 1212 | { 1213 | slave->Flags |= ah; 1214 | GetLoopInformation(ite, slave); 1215 | } 1216 | } 1217 | return; 1218 | 1219 | case 0x3: // Set NNA to cut 1220 | case 0x4: // Set NNA to continue 1221 | case 0x5: // Set NNA to off 1222 | case 0x6: // Set NNA to fade 1223 | InitNoCommand(ite, chn); 1224 | if((chn->Flags & 4) != 0) 1225 | { 1226 | it_slave *slave = &ite->slave[chn->SCOffst]; 1227 | slave->NNA = al-3; 1228 | } 1229 | 1230 | return; 1231 | 1232 | // the comments are backwards here so I've fixed them --GM 1233 | case 0x7: // Set volume envelope off 1234 | InitNoCommand(ite, chn); 1235 | 1236 | if((chn->Flags & 4) != 0) 1237 | { 1238 | it_slave *slave = &ite->slave[chn->SCOffst]; 1239 | slave->Flags &= ~0x1000; 1240 | } 1241 | 1242 | return; 1243 | 1244 | case 0x8: // Set volume envelope on 1245 | InitNoCommand(ite, chn); 1246 | 1247 | if((chn->Flags & 4) != 0) 1248 | { 1249 | it_slave *slave = &ite->slave[chn->SCOffst]; 1250 | slave->Flags |= 0x1000; 1251 | } 1252 | 1253 | return; 1254 | 1255 | case 0x9: // Set panning envelope off 1256 | InitNoCommand(ite, chn); 1257 | 1258 | if((chn->Flags & 4) != 0) 1259 | { 1260 | it_slave *slave = &ite->slave[chn->SCOffst]; 1261 | slave->Flags &= ~0x2000; 1262 | } 1263 | break; 1264 | 1265 | case 0xA: // Set panning envelope on 1266 | InitNoCommand(ite, chn); 1267 | 1268 | if((chn->Flags & 4) != 0) 1269 | { 1270 | it_slave *slave = &ite->slave[chn->SCOffst]; 1271 | slave->Flags |= 0x2000; 1272 | } 1273 | break; 1274 | 1275 | case 0xB: // Set pitch envelope off 1276 | InitNoCommand(ite, chn); 1277 | 1278 | if((chn->Flags & 4) != 0) 1279 | { 1280 | it_slave *slave = &ite->slave[chn->SCOffst]; 1281 | slave->Flags |= ~0x4000; 1282 | } 1283 | break; 1284 | 1285 | case 0xC: // Set pitch envelope on 1286 | InitNoCommand(ite, chn); 1287 | 1288 | if((chn->Flags & 4) != 0) 1289 | { 1290 | it_slave *slave = &ite->slave[chn->SCOffst]; 1291 | slave->Flags |= 0x4000; 1292 | } 1293 | break; 1294 | 1295 | case 0xD: 1296 | case 0xE: 1297 | case 0xF: 1298 | break; 1299 | } break; 1300 | 1301 | case 0x8: // 8 - set pan 1302 | ah = al; 1303 | ah <<= 4; 1304 | al |= ah; 1305 | ah = 0; 1306 | 1307 | if(((al+2)&0xFF) < al) ah++; 1308 | al += 2; 1309 | al >>= 2; 1310 | al |= (ah << 6); 1311 | // TODO: verify 1312 | 1313 | InitNoCommand(ite, chn); 1314 | InitCommandX2(ite, chn, al); 1315 | return; 1316 | 1317 | case 0x9: // 9 - set surround 1318 | if(al == 1) 1319 | { 1320 | al = 100; 1321 | InitNoCommand(ite, chn); 1322 | InitCommandX2(ite, chn, al); 1323 | return; 1324 | } 1325 | 1326 | break; 1327 | 1328 | case 0xA: // A - Set high order offset 1329 | chn->OxH = al; 1330 | break; 1331 | 1332 | case 0xB: // B - loop control 1333 | InitNoCommand(ite, chn); 1334 | 1335 | if(al == 0) 1336 | { 1337 | chn->PLR = ite->CurrentRow; 1338 | 1339 | } else if(chn->PLC == 0) { 1340 | chn->PLC = al; 1341 | ite->ProcessRow = ((uint16_t)chn->PLR)-1; 1342 | ite->PatternLooping = 1; 1343 | 1344 | } else if((--chn->PLC) != 0) { 1345 | ite->ProcessRow = ((uint16_t)chn->PLR)-1; 1346 | ite->PatternLooping = 1; 1347 | 1348 | } else { 1349 | chn->PLR = 1+ite->CurrentRow; 1350 | 1351 | } 1352 | return; 1353 | 1354 | case 0xC: // C - note cut 1355 | chn->Flags |= 1; 1356 | break; 1357 | 1358 | case 0xD: // D - note delay 1359 | chn->Flags |= 2; 1360 | return; 1361 | 1362 | case 0xE: // E - pattern delay 1363 | if(ite->RowDelayOn == 0) 1364 | { 1365 | ite->RowDelay = al+1; 1366 | ite->RowDelayOn = 1; 1367 | } 1368 | 1369 | break; 1370 | 1371 | case 0xF: // F - MIDI Macro select 1372 | chn->SFx = al; 1373 | break; 1374 | } 1375 | 1376 | InitNoCommand(ite, chn); 1377 | } 1378 | 1379 | void InitCommandT(it_engine *ite, it_host *chn) 1380 | { 1381 | if(chn->CVal != 0) 1382 | chn->T00 = chn->CVal; 1383 | 1384 | if(chn->T00 >= 0x20) 1385 | { 1386 | ite->Tempo = chn->T00; 1387 | Music_InitTempo(ite); 1388 | InitNoCommand(ite, chn); 1389 | 1390 | } else { 1391 | InitNoCommand(ite, chn); 1392 | chn->Flags |= 2; // Update mode 1393 | 1394 | } 1395 | } 1396 | 1397 | void InitCommandU(it_engine *ite, it_host *chn) 1398 | { 1399 | if((chn->Msk & 0x11) != 0) 1400 | { 1401 | chn->VPo = 0; 1402 | chn->LVi = 0; 1403 | } 1404 | 1405 | uint8_t ah = chn->CVal & 0x0F; // AH = depth 1406 | uint8_t al = chn->CVal & 0xF0; // AL = speed. 1407 | 1408 | if(al != 0) 1409 | { 1410 | al >>= 2; 1411 | chn->VSp = al; 1412 | } 1413 | 1414 | if(ah != 0) 1415 | { 1416 | if((ite->hdr.Flags & 16) != 0) 1417 | ah *= 2; 1418 | 1419 | chn->VDp = ah; 1420 | } 1421 | 1422 | InitNoCommand(ite, chn); 1423 | 1424 | if((chn->Flags & 4) != 0) 1425 | { 1426 | chn->Flags |= 1; // Update mode. 1427 | InitVibrato(ite, chn); 1428 | } 1429 | 1430 | } 1431 | 1432 | void InitCommandV(it_engine *ite, it_host *chn) 1433 | { 1434 | if(chn->CVal <= 0x80) 1435 | { 1436 | ite->GlobalVolume = chn->CVal; 1437 | RecalculateAllVolumes(ite); 1438 | } 1439 | 1440 | InitNoCommand(ite, chn); 1441 | } 1442 | 1443 | void InitCommandW(it_engine *ite, it_host *chn) 1444 | { 1445 | // Global volume slides! 1446 | 1447 | InitNoCommand(ite, chn); 1448 | 1449 | if(chn->CVal != 0) 1450 | chn->W00 = chn->CVal; 1451 | 1452 | if(chn->W00 == 0) 1453 | { 1454 | return; 1455 | 1456 | } else if((chn->W00 & 0xF0) == 0) { 1457 | chn->_40 = (chn->_40 & 0xFF00) | (0xFF & (int16_t)(-chn->W00)); 1458 | chn->Flags |= 2; 1459 | 1460 | } else if((chn->W00 & 0x0F) == 0) { 1461 | chn->_40 = (chn->_40 & 0xFF00) | (0xFF & (int16_t)(chn->W00>>4)); 1462 | chn->Flags |= 2; 1463 | 1464 | } else if((chn->W00 & 0xF0) == 0xF0) { 1465 | if(ite->GlobalVolume >= (chn->W00 & 0x0F)) 1466 | ite->GlobalVolume -= (chn->W00 & 0x0F); 1467 | else 1468 | ite->GlobalVolume = 0; 1469 | 1470 | RecalculateAllVolumes(ite); 1471 | 1472 | } else if((chn->W00 & 0x0F) == 0x0F) { 1473 | ite->GlobalVolume += (chn->W00>>4); 1474 | if((ite->GlobalVolume & 0x80) != 0) 1475 | ite->GlobalVolume = 128; 1476 | 1477 | RecalculateAllVolumes(ite); 1478 | 1479 | } 1480 | } 1481 | 1482 | void InitCommandX(it_engine *ite, it_host *chn) 1483 | { 1484 | InitNoCommand(ite, chn); 1485 | 1486 | uint16_t ax = chn->CVal; 1487 | ax += 2; 1488 | ax >>= 2; 1489 | InitCommandX2(ite, chn, (uint8_t)ax); 1490 | } 1491 | 1492 | void InitCommandX2(it_engine *ite, it_host *chn, uint8_t al) 1493 | { 1494 | if((chn->Flags & 4) != 0) 1495 | { 1496 | it_slave *slave = &ite->slave[chn->SCOffst]; 1497 | slave->PS = slave->Pan = al; 1498 | slave->Flags |= 64+2; // Recalculate pan 1499 | } 1500 | 1501 | chn->CP = al; 1502 | } 1503 | 1504 | void InitCommandY(it_engine *ite, it_host *chn) 1505 | { 1506 | uint8_t ah = chn->CVal & 0x0F; // AH = depth 1507 | uint8_t al = chn->CVal & 0xF0; 1508 | 1509 | if(ah != 0 || al != 0) 1510 | { 1511 | al >>= 4; 1512 | if(al != 0) 1513 | chn->PSp = al; 1514 | 1515 | ah <<= 1; 1516 | if(ah != 0) 1517 | chn->PDp = ah; 1518 | } 1519 | 1520 | InitNoCommand(ite, chn); 1521 | 1522 | if((chn->Flags & 4) != 0) 1523 | { 1524 | chn->Flags |= 1; // Update mode. 1525 | CommandY(ite, chn); 1526 | } 1527 | } 1528 | 1529 | void InitCommandZ(it_engine *ite, it_host *chn) 1530 | { 1531 | // Macros start at 120h, 320h 1532 | InitNoCommand(ite, chn); 1533 | 1534 | uint16_t bx = chn->CVal; 1535 | it_slave *slave = &ite->slave[chn->SCOffst]; 1536 | 1537 | if((bx & 0x80) == 0) 1538 | { 1539 | bx = chn->SFx & 0x0F; // 0->7Fh - BX = SFx number 1540 | bx <<= 5; 1541 | bx += 0x120; 1542 | MIDITranslate(ite, chn, slave, bx); 1543 | 1544 | } else { 1545 | // Macros! 1546 | bx &= 0x7F; 1547 | bx <<= 5; // BX = (xx-80x)*20h 1548 | bx += 0x320; 1549 | MIDITranslate(ite, chn, slave, bx); 1550 | 1551 | } 1552 | } 1553 | 1554 | void NoCommand(it_engine *ite, it_host *chn) 1555 | { 1556 | // DS:DI points to CIT Area 1557 | } 1558 | 1559 | void CommandD(it_engine *ite, it_host *chn) 1560 | { 1561 | it_slave *slave = &ite->slave[chn->SCOffst]; 1562 | uint8_t al = chn->VCh + slave->VS; // Volset. 1563 | 1564 | if((al & 0x80) == 0) 1565 | { 1566 | if(al > 64) 1567 | { 1568 | chn->Flags &= ~1; 1569 | al = 64; 1570 | } 1571 | 1572 | } else { 1573 | chn->Flags &= ~1; 1574 | al = 0; 1575 | } 1576 | 1577 | CommandD2(ite, chn, slave, al); 1578 | } 1579 | 1580 | void CommandD2(it_engine *ite, it_host *chn, it_slave *slave, uint8_t al) 1581 | { 1582 | slave->Vol = al; 1583 | slave->VS = al; 1584 | chn->VSe = al; 1585 | slave->Flags |= 16; // Recalc vol 1586 | } 1587 | 1588 | void CommandE(it_engine *ite, it_host *chn) 1589 | { 1590 | CommandEChain(ite, chn, chn->_40); 1591 | } 1592 | 1593 | void CommandEChain(it_engine *ite, it_host *chn, int16_t bx) 1594 | { 1595 | it_slave *slave = &ite->slave[chn->SCOffst]; 1596 | PitchSlideDown(ite, chn, slave, bx); 1597 | slave->Frequency_Set = slave->Frequency; 1598 | } 1599 | 1600 | void CommandF(it_engine *ite, it_host *chn) 1601 | { 1602 | CommandFChain(ite, chn, chn->_40); 1603 | } 1604 | 1605 | void CommandFChain(it_engine *ite, it_host *chn, int16_t bx) 1606 | { 1607 | it_slave *slave = &ite->slave[chn->SCOffst]; 1608 | PitchSlideUp(ite, chn, slave, bx); 1609 | slave->Frequency_Set = slave->Frequency; 1610 | } 1611 | 1612 | void CommandG(it_engine *ite, it_host *chn) 1613 | { 1614 | if((chn->Flags & 16) == 0) 1615 | return; 1616 | 1617 | int16_t bx = chn->_40; 1618 | it_slave *slave = &ite->slave[chn->SCOffst]; 1619 | 1620 | if((chn->_42 & 0xFF) != 1) 1621 | { 1622 | // Slide down 1623 | PitchSlideDown(ite, chn, slave, bx); 1624 | 1625 | // Check that frequency is above porta 1626 | // to frequency. 1627 | uint32_t eax = slave->Frequency; 1628 | if(eax <= chn->Porta_Frequency) 1629 | { 1630 | eax = chn->Porta_Frequency; 1631 | chn->Flags &= ~(3 | 16); // Turn off calling 1632 | slave->Frequency = eax; 1633 | } 1634 | 1635 | slave->Frequency_Set = eax; 1636 | 1637 | } else { 1638 | // Slide up! 1639 | PitchSlideUp(ite, chn, slave, bx); 1640 | 1641 | // Check that 1642 | // 1) Channel is on 1643 | // 2) Frequency (set) is below porta to 1644 | // frequency 1645 | uint32_t eax = slave->Frequency; 1646 | 1647 | if((slave->Flags & 0x200) == 0 && eax < chn->Porta_Frequency) 1648 | { 1649 | slave->Frequency_Set = eax; 1650 | return; 1651 | } 1652 | 1653 | slave->Flags &= ~0x200; 1654 | chn->Flags |= 4; // Turn on. 1655 | eax = chn->Porta_Frequency; 1656 | chn->Flags &= ~(3 | 16); // Turn off calling 1657 | slave->Frequency = eax; 1658 | slave->Frequency_Set = eax; 1659 | } 1660 | 1661 | } 1662 | 1663 | void InitVibrato(it_engine *ite, it_host *chn) 1664 | { 1665 | if((ite->hdr.Flags & 0x10) == 0) 1666 | { 1667 | CommandH(ite, chn); 1668 | 1669 | } else { 1670 | it_slave *slave = &ite->slave[chn->SCOffst]; 1671 | slave->Flags |= 32; // Freq change... 1672 | CommandH5(ite, chn, slave, chn->LVi); 1673 | } 1674 | } 1675 | 1676 | void CommandH(it_engine *ite, it_host *chn) 1677 | { 1678 | it_slave *slave = &ite->slave[chn->SCOffst]; 1679 | slave->Flags |= 32; // Freq change... 1680 | 1681 | // Add speed. / Save value 1682 | chn->VPo += chn->VSp; 1683 | 1684 | // Mov BH, [DI+38h] // AL = waveform 1685 | // gg wp --GM 1686 | 1687 | int8_t al; 1688 | if(chn->VWF != 3) 1689 | { 1690 | // probably not wise to try to emulate out-of-range vibrato types. 1691 | // well, at least for now. we can research these later. --GM 1692 | switch(chn->VWF) 1693 | { 1694 | case 0: 1695 | al = FineSineData[chn->VPo]; 1696 | break; 1697 | case 1: 1698 | al = FineRampDownData[chn->VPo]; 1699 | break; 1700 | case 2: 1701 | al = FineSquareWave[chn->VPo]; 1702 | break; 1703 | default: 1704 | printf("PANIC: out of range vibrato types not emulated!\n"); 1705 | abort(); 1706 | } 1707 | 1708 | } else { 1709 | al = (Random(ite)&127)-64; // Random. 1710 | 1711 | } 1712 | 1713 | chn->LVi = al; // Save last vibrato. 1714 | 1715 | CommandH5(ite, chn, slave, al); 1716 | } 1717 | 1718 | void CommandH5(it_engine *ite, it_host *chn, it_slave *slave, int8_t al) 1719 | { 1720 | int16_t ax = ((int16_t)al) * (int16_t)(int8_t)(chn->VDp); 1721 | ax <<= 2; 1722 | ax += 0x80; 1723 | ax >>= 8; // actual code then simply uses AH --GM 1724 | 1725 | if((ite->hdr.Flags & 16) != 0) 1726 | { 1727 | // don't ask me why sackit does weird things here, 1728 | // i could have sworn Jeff had done a one's complement 1729 | // but that seems to not be the case (in IT 2.14 at least) --GM 1730 | 1731 | ax = -ax; 1732 | } 1733 | 1734 | //MovZX BX, AH 1735 | 1736 | // AH = EEx/FEx command value 1737 | if(ax < 0) 1738 | PitchSlideDown(ite, chn, slave, -ax); 1739 | else 1740 | PitchSlideUp(ite, chn, slave, ax); 1741 | } 1742 | 1743 | void CommandI(it_engine *ite, it_host *chn) 1744 | { 1745 | it_slave *slave = &ite->slave[chn->SCOffst]; 1746 | 1747 | slave->Flags |= 16; // recalc volume; 1748 | 1749 | chn->TCD--; 1750 | 1751 | if((chn->TCD & 0x80) != 0 || chn->TCD == 0) 1752 | { 1753 | chn->Too ^= 1; 1754 | chn->TCD = (uint8_t)(chn->Too != 0 ? (chn->_40>>8) : (chn->_40&0xFF)); 1755 | } 1756 | 1757 | if(chn->Too != 1) 1758 | slave->Vol = 0; 1759 | 1760 | } 1761 | 1762 | void CommandJ(it_engine *ite, it_host *chn) 1763 | { 1764 | it_slave *slave = &ite->slave[chn->SCOffst]; 1765 | int16_t bx = chn->_40; 1766 | 1767 | slave->Flags |= 32; 1768 | 1769 | bx += 2; 1770 | if(bx >= 6) 1771 | { 1772 | chn->_40 = 0; 1773 | return; 1774 | } 1775 | 1776 | chn->_40 = bx; 1777 | uint64_t rad = (uint64_t)slave->Frequency; 1778 | rad *= (uint64_t)PitchTable[(bx == 2 ? chn->_42 : chn->_44)/4]; 1779 | 1780 | //printf("honk %lX\n", rad); 1781 | // FIXME work out how this damn thing works 1782 | rad >>= (uint64_t)16; 1783 | /* 1784 | if((rad & (uint64_t)0xFFFF000000000000LLU) != 0) 1785 | rad &= ~(uint64_t)0xFFFFFFFFLLU; 1786 | else 1787 | rad >>= (uint64_t)rad; 1788 | */ 1789 | 1790 | slave->Frequency = (uint32_t)rad; 1791 | } 1792 | 1793 | void CommandK(it_engine *ite, it_host *chn) 1794 | { 1795 | CommandH(ite, chn); 1796 | CommandD(ite, chn); 1797 | } 1798 | 1799 | void CommandL(it_engine *ite, it_host *chn) 1800 | { 1801 | if((chn->Flags & 16) != 0) 1802 | { 1803 | CommandG(ite, chn); 1804 | chn->Flags |= 1; 1805 | } 1806 | 1807 | CommandD(ite, chn); 1808 | } 1809 | 1810 | void CommandN(it_engine *ite, it_host *chn) 1811 | { 1812 | uint8_t al = chn->CV + chn->_40; 1813 | 1814 | if((al & 0x80) == 0) 1815 | al = 0; 1816 | else if(al > 64) 1817 | al = 64; 1818 | 1819 | InitCommandM2(ite, chn, al); 1820 | } 1821 | 1822 | void CommandP(it_engine *ite, it_host *chn) 1823 | { 1824 | int8_t al = chn->CP; 1825 | 1826 | if((chn->Flags & 4) != 0) 1827 | { 1828 | it_slave *slave = &ite->slave[chn->SCOffst]; 1829 | al = slave->PS; 1830 | } 1831 | 1832 | al += (int8_t)(chn->_40 & 0xFF); 1833 | 1834 | if(al < 0) 1835 | al = 0; 1836 | else if(al > 64) 1837 | al = 64; 1838 | 1839 | InitCommandX2(ite, chn, al); 1840 | } 1841 | 1842 | void CommandQ(it_engine *ite, it_host *chn) 1843 | { 1844 | chn->RTC--; 1845 | if(chn->RTC != 0 && chn->RTC != 0xFF) 1846 | return; 1847 | 1848 | // OK... reset counter. 1849 | chn->RTC = chn->Q00 & 0x0F; // retrig count done. 1850 | //And BX, 0F00Fh 1851 | 1852 | it_slave *slave = &ite->slave[chn->SCOffst]; 1853 | 1854 | if((ite->d.DriverFlags & 2) != 0) // Hiqual? 1855 | { 1856 | if((ite->hdr.Flags & 4) == 0) // Instrument mode? 1857 | { 1858 | // Sample mode 1859 | memcpy(slave+64, slave, sizeof(it_slave)); 1860 | 1861 | (slave+64)->Flags |= 0x200; // Cut 1862 | (slave+64)->HCN |= 0x80; // Disowned 1863 | } else { 1864 | // Instrument mode 1865 | 1866 | it_slave *dest = &ite->slave[0]; 1867 | uint16_t cx = ite->NumChannels; 1868 | 1869 | for(; cx != 0; cx--, dest++) 1870 | { 1871 | if((dest->Flags & 1) == 0) 1872 | { 1873 | memcpy(dest, slave, sizeof(it_slave)); 1874 | dest->Flags |= 0x200; // Cut 1875 | dest->HCN |= 0x80; // Disowned 1876 | slave = dest; 1877 | 1878 | // TODO: verify C behaviour 1879 | chn->SCOffst = (dest - &ite->slave[0]); 1880 | break; 1881 | } 1882 | } 1883 | } 1884 | } 1885 | 1886 | slave->OldSampleOffset = 0; 1887 | slave->SmpErr = 0; 1888 | slave->Sample_Offset = 0; 1889 | 1890 | slave->Flags |= 0x540; 1891 | 1892 | uint8_t al = slave->VS; 1893 | int check = 0; 1894 | switch(chn->Q00>>4) 1895 | { 1896 | case 0x0: 1897 | return; 1898 | 1899 | case 0x1: 1900 | al--; 1901 | check = -1; 1902 | break; 1903 | 1904 | case 0x2: 1905 | al -= 2; 1906 | check = -1; 1907 | break; 1908 | 1909 | case 0x3: 1910 | al -= 4; 1911 | check = -1; 1912 | break; 1913 | 1914 | case 0x4: 1915 | al -= 8; 1916 | check = -1; 1917 | break; 1918 | 1919 | case 0x5: 1920 | al -= 16; 1921 | check = -1; 1922 | break; 1923 | 1924 | case 0x6: 1925 | al <<= 1; 1926 | al /= 3; 1927 | break; 1928 | 1929 | case 0x7: 1930 | al >>= 1; 1931 | break; 1932 | 1933 | case 0x8: 1934 | return; 1935 | 1936 | case 0x9: 1937 | al++; 1938 | check = 1; 1939 | break; 1940 | 1941 | case 0xA: 1942 | al += 2; 1943 | check = 1; 1944 | break; 1945 | 1946 | case 0xB: 1947 | al += 4; 1948 | check = 1; 1949 | break; 1950 | 1951 | case 0xC: 1952 | al += 8; 1953 | check = 1; 1954 | break; 1955 | 1956 | case 0xD: 1957 | al += 16; 1958 | check = 1; 1959 | break; 1960 | 1961 | case 0xE: 1962 | al = (al + al + al) >> 1; 1963 | check = 1; 1964 | break; 1965 | 1966 | case 0xF: 1967 | al <<= 1; 1968 | check = 1; 1969 | break; 1970 | } 1971 | 1972 | if(check < 0 && (al & 0x80) != 0) 1973 | al = 0; 1974 | else if(check > 0 && al > 64) 1975 | al = 64; 1976 | 1977 | slave->VS = slave->Vol = al; 1978 | chn->VSe = al; 1979 | slave->Flags |= 16; // recalc volume flag 1980 | 1981 | if(chn->Smp == 101) // MIDI sample 1982 | MIDITranslate(ite, chn, slave, MIDICOMMAND_STOPNOTE); 1983 | 1984 | } 1985 | 1986 | void InitTremelo(it_engine *ite, it_host *chn) 1987 | { 1988 | if((ite->hdr.Flags & 0x10) == 0) 1989 | { 1990 | CommandR(ite, chn); 1991 | 1992 | } else { 1993 | it_slave *slave = &ite->slave[chn->SCOffst]; 1994 | slave->Flags |= 64; // Volume change... 1995 | CommandR2(ite, chn, slave, chn->LTr); 1996 | 1997 | } 1998 | } 1999 | 2000 | void CommandR(it_engine *ite, it_host *chn) 2001 | { 2002 | it_slave *slave = &ite->slave[chn->SCOffst]; 2003 | slave->Flags |= 64; // Volume change 2004 | 2005 | // TODO: verify 2006 | 2007 | // Add speed. / Save value 2008 | chn->TPo += chn->TSp; 2009 | 2010 | int8_t al; 2011 | if(chn->TWF != 3) 2012 | { 2013 | // probably not wise to try to emulate out-of-range vibrato types. 2014 | // well, at least for now. we can research these later. --GM 2015 | switch(chn->TWF) 2016 | { 2017 | case 0: 2018 | al = FineSineData[chn->TPo]; 2019 | break; 2020 | case 1: 2021 | al = FineRampDownData[chn->TPo]; 2022 | break; 2023 | case 2: 2024 | al = FineSquareWave[chn->TPo]; 2025 | break; 2026 | default: 2027 | printf("PANIC: out of range vibrato types not emulated!\n"); 2028 | abort(); 2029 | } 2030 | 2031 | } else { 2032 | al = (Random(ite)&127)-64; // Random. 2033 | 2034 | } 2035 | 2036 | CommandR2(ite, chn, slave, al); 2037 | } 2038 | 2039 | void CommandR2(it_engine *ite, it_host *chn, it_slave *slave, int8_t al) 2040 | { 2041 | int16_t ax; 2042 | ax = al; 2043 | ax *= (int16_t)(int8_t)(chn->TDp); 2044 | ax <<= 2; 2045 | ax += 0x80; 2046 | ax >>= 8; 2047 | 2048 | al = slave->Vol + ax; 2049 | 2050 | if((al & 0x80) != 0) 2051 | al = 0; 2052 | if(al > 64) 2053 | al = 64; 2054 | 2055 | slave->Vol = al; 2056 | } 2057 | 2058 | void CommandS(it_engine *ite, it_host *chn) 2059 | { 2060 | // Have to handle SDx, SCx 2061 | // AH = command, AL = value. 2062 | uint8_t ah = (chn->_40>>8); 2063 | uint8_t al = (chn->_40&0xFF); 2064 | 2065 | if(ah == 0xD0) 2066 | { 2067 | // this is just an 8-bit dec in a 16-bit value --GM 2068 | if(chn->_40 == 0) chn->_40 |= 0xFF; 2069 | else chn->_40--; 2070 | 2071 | if((chn->_40 & 0x80) == 0 && (chn->_40 & 0xFF) != 0) 2072 | return; 2073 | 2074 | chn->Flags &= ~3; 2075 | InitNoCommand(ite, chn); 2076 | 2077 | chn->Flags |= 64; 2078 | 2079 | // Check whether chn is on 2080 | if((ite->hdr.Chnl_Vol[chn->HCN] & 0x80) == 0) return; 2081 | if((chn->Flags & 32) != 0) return; 2082 | if((chn->Flags & 4) == 0) return; // Channel was off. 2083 | 2084 | it_slave *slave = &ite->slave[chn->SCOffst]; 2085 | slave->Flags |= 0x800; 2086 | 2087 | } else if(ah == 0xC0) { 2088 | if((chn->Flags & 4) == 0) return; 2089 | 2090 | // this is just an 8-bit dec in a 16-bit value --GM 2091 | if(chn->_40 == 0) chn->_40 |= 0xFF; 2092 | else chn->_40--; 2093 | 2094 | if((chn->_40 & 0x80) == 0 && (chn->_40 & 0xFF) != 0) 2095 | return; 2096 | 2097 | it_slave *slave = &ite->slave[chn->SCOffst]; // Note cut. 2098 | 2099 | chn->Flags &= ~4; 2100 | 2101 | if(slave->Smp != 100 && (ite->d.DriverFlags & 2) == 0) 2102 | slave->Flags = 0x200; 2103 | else 2104 | slave->Flags |= 0x200; 2105 | } 2106 | } 2107 | 2108 | void CommandT(it_engine *ite, it_host *chn) 2109 | { 2110 | // TODO: verify - flow somewhat different from original source --GM 2111 | 2112 | if((chn->T00 & 0xF0) != 0) 2113 | { 2114 | // Slide up 2115 | ite->Tempo += chn->T00; 2116 | ite->Tempo -= 0x10; 2117 | if(ite->Tempo > 0xFF) 2118 | ite->Tempo = 0xFF; 2119 | 2120 | } else { 2121 | // Slide down 2122 | ite->Tempo -= 0x10; 2123 | if(ite->Tempo < 0x20) 2124 | ite->Tempo = 0x20; 2125 | } 2126 | 2127 | ite->d.DriverSetTempo(ite, ite->Tempo); 2128 | } 2129 | 2130 | void CommandW(it_engine *ite, it_host *chn) 2131 | { 2132 | // Global volume slide! 2133 | int16_t ax = (int16_t)(int8_t)(chn->_40 & 0xFF); 2134 | ax += ite->GlobalVolume; 2135 | 2136 | if((ax & 0x8000) != 0) 2137 | ax = 0; 2138 | 2139 | if((ax & 0xFF) > 128) 2140 | ax = 128; 2141 | 2142 | ite->GlobalVolume = ax; 2143 | 2144 | RecalculateAllVolumes(ite); 2145 | } 2146 | 2147 | void CommandY(it_engine *ite, it_host *chn) 2148 | { 2149 | // TODO! 2150 | } 2151 | 2152 | #if 0 2153 | void CommandY(it_engine *ite, it_host *chn) 2154 | { 2155 | Test Byte Ptr [DI], 4 2156 | JZ CommandY5 2157 | 2158 | it_slave *slave = &ite->slave[chn->SCOffst]; 2159 | 2160 | Mov BH, [DI+28h] // AL = waveform 2161 | Cmp BH, 3 2162 | JAE CommandY1 2163 | 2164 | Mov BL, [DI+29h] // Pos 2165 | Add BL, [DI+2Bh] // Add speed. 2166 | Mov [DI+29h], BL // Save value 2167 | 2168 | Mov AL, [FineSineData+BX] // AL = -64 -> 64 2169 | 2170 | Jmp CommandY2 2171 | 2172 | CommandY1: // Random panning make 2173 | // speed the delay time. 2174 | Dec Byte Ptr [DI+29h] 2175 | JZ CommandY6 2176 | JS CommandY6 2177 | 2178 | Mov AL, [DI+2Ch] 2179 | Jmp CommandY2 2180 | 2181 | CommandY6: 2182 | Mov BL, [DI+2Bh] 2183 | Mov [DI+29h], BL // reset countdown. 2184 | 2185 | Call Random 2186 | And AL, 127 2187 | Sub AL, 64 2188 | 2189 | Mov [DI+2Ch], AL 2190 | 2191 | CommandY2: 2192 | IMul Byte Ptr [DI+2Ah] 2193 | SAL AX, 2 2194 | Add AX, 80h 2195 | MovZX BX, AH 2196 | // AH = panning change 2197 | Mov AL, [SI+2Bh] // AL = panning 2198 | Cmp AL, 100 // Surround? 2199 | JE CommandY5 2200 | 2201 | Add AL, AH 2202 | JNS CommandY3 2203 | 2204 | Xor AL, AL 2205 | 2206 | CommandY3: 2207 | Cmp AL, 64 2208 | JBE CommandY4 2209 | 2210 | Mov AL, 64 2211 | 2212 | CommandY4: 2213 | Or Byte Ptr [SI], 2 // Panning change 2214 | Mov [SI+2Ah], AL 2215 | 2216 | CommandY5: 2217 | Ret 2218 | 2219 | } 2220 | #endif 2221 | 2222 | --------------------------------------------------------------------------------