[56] | 1 | /* |
---|
| 2 | * Abuse - dark 2D side-scrolling platform game |
---|
| 3 | * Copyright (c) 1995 Crack dot Com |
---|
| 4 | * |
---|
| 5 | * This software was released into the Public Domain. As with most public |
---|
| 6 | * domain software, no warranty is made or implied by Crack dot Com or |
---|
| 7 | * Jonathan Clark. |
---|
| 8 | */ |
---|
| 9 | |
---|
| 10 | #include "config.h" |
---|
| 11 | |
---|
[2] | 12 | extern "C" |
---|
| 13 | { |
---|
| 14 | #include <sys/types.h> |
---|
| 15 | #include <stdio.h> |
---|
| 16 | #include <fcntl.h> |
---|
| 17 | #include <sys/ioctl.h> |
---|
| 18 | #include <unistd.h> |
---|
| 19 | #include <stdlib.h> |
---|
| 20 | #include <malloc.h> |
---|
| 21 | #include <sys/stat.h> |
---|
| 22 | #include <linux/soundcard.h> |
---|
| 23 | #include <sys/time.h> |
---|
| 24 | #include "DoomDef.h" |
---|
| 25 | }; |
---|
| 26 | |
---|
| 27 | #include "sndserver.h" |
---|
| 28 | #include "wadread.h" |
---|
| 29 | |
---|
| 30 | #define SOUNDDIR LIBDIR "/sfx/" |
---|
| 31 | |
---|
| 32 | typedef struct wadinfo_struct |
---|
| 33 | { |
---|
| 34 | char identification[4]; // should be IWAD |
---|
| 35 | int numlumps; |
---|
| 36 | int infotableofs; |
---|
| 37 | } wadinfo_t; |
---|
| 38 | |
---|
| 39 | typedef struct filelump_struct |
---|
| 40 | { |
---|
| 41 | int filepos; |
---|
| 42 | int size; |
---|
| 43 | char name[8]; |
---|
| 44 | } filelump_t; |
---|
| 45 | |
---|
| 46 | static int mytime = 0; // an internal time keeper |
---|
| 47 | int numsounds; // number of sound effects |
---|
| 48 | int longsound; // longest sound effect |
---|
| 49 | int lengths[NUMSFX]; // lengths of all sound effects |
---|
[17] | 50 | uint8_t mixbuffer[MIXBUFFERSIZE]; // mixing buffer |
---|
[2] | 51 | int sfxdevice; // file descriptor of sfx device |
---|
| 52 | int musdevice; // file descriptor of music device |
---|
[17] | 53 | uint8_t *channels[8]; // the channel data pointers |
---|
| 54 | uint8_t *channelsend[8]; // the channel data end pointers |
---|
[2] | 55 | int channelstart[8]; // time that the channel started playing |
---|
| 56 | int channelhandles[8]; // the channel handles |
---|
| 57 | |
---|
| 58 | static void derror(char *msg) |
---|
| 59 | { |
---|
| 60 | fprintf(stderr, "error: %s\n", msg); |
---|
| 61 | exit(-1); |
---|
| 62 | } |
---|
| 63 | |
---|
| 64 | int mix(void) |
---|
| 65 | { |
---|
| 66 | |
---|
| 67 | register int i, j, d; |
---|
| 68 | |
---|
| 69 | // if (channels[0]) fprintf(stderr, "."); |
---|
| 70 | |
---|
| 71 | // for (d=i=0 ; i<8 ; i++) |
---|
| 72 | // d |= (int) channels[i]; |
---|
| 73 | // if (!d) return 0; |
---|
| 74 | |
---|
| 75 | // mix into the mixing buffer |
---|
| 76 | for (i=0 ; i<MIXBUFFERSIZE ; i++) |
---|
| 77 | { |
---|
| 78 | d = 0; |
---|
| 79 | j = 8; |
---|
| 80 | do { |
---|
| 81 | if (channels[--j]) |
---|
| 82 | { |
---|
| 83 | d += *channels[j]++ - 128; |
---|
| 84 | } |
---|
| 85 | } while (j); |
---|
| 86 | if (d > 127) mixbuffer[i] = 255; |
---|
| 87 | else if (d < -128) mixbuffer[i] = 0; |
---|
[17] | 88 | else mixbuffer[i] = (uint8_t) (d+128); |
---|
[2] | 89 | // if (d > 127) mixbuffer[i] = 0; |
---|
| 90 | // else if (d < -128) mixbuffer[i] = 255; |
---|
[17] | 91 | // else mixbuffer[i] = (uint8_t) (-d+127); |
---|
[2] | 92 | } |
---|
| 93 | |
---|
| 94 | // check for freed channels |
---|
| 95 | for (j=0 ; j<8 ; j++) |
---|
| 96 | { |
---|
| 97 | if (channels[j] == channelsend[j]) channels[j] = 0; |
---|
| 98 | } |
---|
| 99 | |
---|
| 100 | return 1; |
---|
| 101 | |
---|
| 102 | } |
---|
| 103 | |
---|
| 104 | void grabdata(int c, char **v) |
---|
| 105 | { |
---|
| 106 | |
---|
| 107 | int i; |
---|
| 108 | |
---|
| 109 | numsounds = NUMSFX; |
---|
| 110 | longsound = 0; |
---|
| 111 | |
---|
| 112 | openwad("../frame/doom.wad"); |
---|
| 113 | |
---|
| 114 | for (i=1 ; i<NUMSFX ; i++) |
---|
| 115 | { |
---|
| 116 | if (!S_sfx[i].link) |
---|
| 117 | { |
---|
| 118 | S_sfx[i].data = getsfx(S_sfx[i].name, &lengths[i]); |
---|
| 119 | if (longsound < lengths[i]) longsound = lengths[i]; |
---|
| 120 | } else { |
---|
| 121 | S_sfx[i].data = S_sfx[i].link->data; |
---|
| 122 | lengths[i] = lengths[(S_sfx[i].link - S_sfx)/sizeof(struct sfxinfo_t)]; |
---|
| 123 | } |
---|
| 124 | /* |
---|
| 125 | // test only |
---|
| 126 | { |
---|
| 127 | int fd; |
---|
| 128 | char name[10]; |
---|
| 129 | sprintf(name, "sfx%d", i); |
---|
| 130 | fd = open(name, O_WRONLY|O_CREAT, 0644); |
---|
| 131 | write(fd, S_sfx[i].data, lengths[i]); |
---|
| 132 | close(fd); |
---|
| 133 | } |
---|
| 134 | */ |
---|
| 135 | } |
---|
| 136 | |
---|
| 137 | } |
---|
| 138 | |
---|
| 139 | void opensfxdev(int c, char **v) |
---|
| 140 | { |
---|
| 141 | |
---|
| 142 | int i, rc; |
---|
| 143 | |
---|
| 144 | // open the sound device |
---|
| 145 | sfxdevice = open("/dev/dsp", O_WRONLY, 0); |
---|
| 146 | if (sfxdevice < 0) derror("Could not open /dev/dsp"); |
---|
| 147 | |
---|
| 148 | // set it up for the proper sound format |
---|
| 149 | i = 8; |
---|
| 150 | rc = ioctl(sfxdevice, SNDCTL_DSP_SAMPLESIZE, &i); |
---|
| 151 | if (rc < 0) fprintf(stderr, "SAMPLESIZE failed\n"); |
---|
| 152 | i = 11111; |
---|
| 153 | rc = ioctl(sfxdevice, SNDCTL_DSP_SPEED, &i); |
---|
| 154 | if (rc < 0) fprintf(stderr, "SPEED failed\n"); |
---|
| 155 | i = 0; |
---|
| 156 | rc = ioctl(sfxdevice, SNDCTL_DSP_STEREO, &i); |
---|
| 157 | if (rc < 0) fprintf(stderr, "STEREO failed\n"); |
---|
| 158 | // i = 2; |
---|
| 159 | // rc = ioctl(sfxdevice, SNDCTL_DSP_SUBDIVIDE, &i); |
---|
| 160 | // if (rc < 0) fprintf(stderr, "SUBDIVIDE failed\n"); |
---|
| 161 | |
---|
| 162 | } |
---|
| 163 | |
---|
| 164 | void closesfxdev(void) |
---|
| 165 | { |
---|
| 166 | close(sfxdevice); |
---|
| 167 | } |
---|
| 168 | |
---|
| 169 | void openmusdev(int c, char **v) |
---|
| 170 | { |
---|
| 171 | } |
---|
| 172 | |
---|
| 173 | void closemusdev(void) |
---|
| 174 | { |
---|
| 175 | } |
---|
| 176 | |
---|
| 177 | static struct timeval last={0,0}, now; |
---|
| 178 | static struct timezone whocares; |
---|
| 179 | |
---|
| 180 | void updatesounds(void) |
---|
| 181 | { |
---|
| 182 | int deltatime; |
---|
| 183 | int rc; |
---|
| 184 | |
---|
| 185 | rc = mix(); |
---|
| 186 | rc = ioctl(sfxdevice, SNDCTL_DSP_POST, 0); |
---|
| 187 | // rc = ioctl(sfxdevice, SNDCTL_DSP_SYNC, 0); |
---|
| 188 | if (rc < 0) fprintf(stderr, "SYNC failed?!\n"); |
---|
| 189 | write(sfxdevice, mixbuffer, MIXBUFFERSIZE); |
---|
| 190 | /* |
---|
| 191 | gettimeofday(&now, &whocares); |
---|
| 192 | deltatime = (now.tv_sec - last.tv_sec)*1000000 + now.tv_usec - last.tv_usec; |
---|
| 193 | deltatime = deltatime - (1 * MIXBUFFERSIZE * 1000000) / (1 * SPEED); |
---|
| 194 | last = now; |
---|
| 195 | if (deltatime < 0) |
---|
| 196 | usleep (-deltatime); |
---|
| 197 | if (rc) |
---|
| 198 | { |
---|
| 199 | write(sfxdevice, mixbuffer, MIXBUFFERSIZE); |
---|
| 200 | fprintf(stderr, "."); |
---|
| 201 | } |
---|
| 202 | */ |
---|
| 203 | } |
---|
| 204 | |
---|
| 205 | int addsfx(int sfxid, int volume) |
---|
| 206 | { |
---|
| 207 | |
---|
| 208 | int i; |
---|
| 209 | int rc = -1; |
---|
[17] | 210 | static uint16_t handlenums = 0; |
---|
[2] | 211 | int oldest = mytime; |
---|
| 212 | int oldestnum = 0; |
---|
| 213 | |
---|
| 214 | for (i=0 ; i<8 ; i++) |
---|
| 215 | { |
---|
| 216 | if (!channels[i]) |
---|
| 217 | { |
---|
| 218 | channelsend[i] = |
---|
[17] | 219 | (channels[i] = (uint8_t *) S_sfx[sfxid].data) + lengths[sfxid]; |
---|
[2] | 220 | if (!handlenums) handlenums = 100; |
---|
| 221 | channelhandles[i] = rc = handlenums++; |
---|
| 222 | channelstart[i] = mytime; |
---|
| 223 | break; |
---|
| 224 | } |
---|
| 225 | else |
---|
| 226 | { |
---|
| 227 | if (channelstart[i] < oldest) |
---|
| 228 | { |
---|
| 229 | oldestnum = i; |
---|
| 230 | oldest = channelstart[i]; |
---|
| 231 | } |
---|
| 232 | } |
---|
| 233 | } |
---|
| 234 | |
---|
| 235 | // if no channels were available, kill oldest sound and replace it |
---|
| 236 | if (i == 8) |
---|
| 237 | { |
---|
| 238 | channelsend[oldestnum] = |
---|
[17] | 239 | (channels[oldestnum] = (uint8_t *) S_sfx[sfxid].data) |
---|
[2] | 240 | + lengths[sfxid]; |
---|
| 241 | if (!handlenums) handlenums = 100; |
---|
| 242 | channelhandles[oldestnum] = rc = handlenums++; |
---|
| 243 | channelstart[i] = mytime; |
---|
| 244 | } |
---|
| 245 | |
---|
| 246 | return rc; |
---|
| 247 | |
---|
| 248 | } |
---|
| 249 | |
---|
[17] | 250 | void output_uint16(int num) |
---|
[2] | 251 | { |
---|
| 252 | |
---|
[17] | 253 | static uint8_t buff[5] = { 0, 0, 0, 0, '\n' }; |
---|
[2] | 254 | static char *badbuff = "xxxx\n"; |
---|
| 255 | |
---|
| 256 | // outputs a 16-bit # in hex or "xxxx" if -1. |
---|
| 257 | if (num < 0) |
---|
| 258 | { |
---|
| 259 | write(1, badbuff, 5); |
---|
| 260 | } else { |
---|
| 261 | buff[0] = num>>12; |
---|
| 262 | buff[0] += buff[0] > 9 ? 'a'-10 : '0'; |
---|
| 263 | buff[1] = (num>>8) & 0xf; |
---|
| 264 | buff[1] += buff[1] > 9 ? 'a'-10 : '0'; |
---|
| 265 | buff[2] = (num>>4) & 0xf; |
---|
| 266 | buff[2] += buff[2] > 9 ? 'a'-10 : '0'; |
---|
| 267 | buff[3] = num & 0xf; |
---|
| 268 | buff[3] += buff[3] > 9 ? 'a'-10 : '0'; |
---|
| 269 | write(1, buff, 5); |
---|
| 270 | } |
---|
| 271 | |
---|
| 272 | } |
---|
| 273 | |
---|
| 274 | void initdata(void) |
---|
| 275 | { |
---|
| 276 | int i; |
---|
[17] | 277 | for (i=0 ; i<sizeof(channels)/sizeof(uint8_t *) ; i++) channels[i] = 0; |
---|
[2] | 278 | gettimeofday(&last, &whocares); |
---|
| 279 | usleep(100000); |
---|
| 280 | } |
---|
| 281 | |
---|
| 282 | int main(int c, char **v) |
---|
| 283 | { |
---|
| 284 | |
---|
| 285 | int done = 0; |
---|
| 286 | int rc, nrc, sndnum, handle = 0; |
---|
[17] | 287 | uint8_t commandbuf[10]; |
---|
[2] | 288 | fd_set fdset, scratchset; |
---|
| 289 | struct timeval zerowait = { 0, 0 }; |
---|
| 290 | |
---|
| 291 | grabdata(c, v); // get sound data |
---|
| 292 | initdata(); // init any data |
---|
| 293 | |
---|
| 294 | opensfxdev(c, v); // open sfx device |
---|
| 295 | openmusdev(c, v); // open music device |
---|
| 296 | fprintf(stderr, "ready\n"); |
---|
| 297 | |
---|
| 298 | // parse commands and play sounds until done |
---|
| 299 | FD_ZERO(&fdset); |
---|
| 300 | FD_SET(0, &fdset); |
---|
| 301 | while (!done) |
---|
| 302 | { |
---|
| 303 | mytime++; |
---|
| 304 | do { |
---|
| 305 | scratchset = fdset; |
---|
| 306 | rc = select(FD_SETSIZE, &scratchset, 0, 0, &zerowait); |
---|
| 307 | if (rc > 0) |
---|
| 308 | { |
---|
| 309 | // fprintf(stderr, "select is true\n"); |
---|
| 310 | // got a command |
---|
| 311 | nrc = read(0, commandbuf, 1); |
---|
| 312 | if (!nrc) { done = 1; rc = 0; } |
---|
| 313 | else { |
---|
| 314 | switch (commandbuf[0]) |
---|
| 315 | { |
---|
| 316 | case 'p': // play a new sound effect |
---|
| 317 | read(0, commandbuf, 3); |
---|
| 318 | commandbuf[0] -= commandbuf[0]>='a' ? 'a'-10 : '0'; |
---|
| 319 | commandbuf[1] -= commandbuf[1]>='a' ? 'a'-10 : '0'; |
---|
| 320 | sndnum = (commandbuf[0]<<4) + commandbuf[1]; |
---|
| 321 | // fprintf(stderr, "cmd: play sound %d\n", sndnum); |
---|
| 322 | handle = addsfx(sndnum, 127); // returns the handle |
---|
| 323 | // outputushort(handle); |
---|
| 324 | break; |
---|
| 325 | case 'q': |
---|
| 326 | read(0, commandbuf, 1); |
---|
| 327 | done = 1; rc = 0; |
---|
| 328 | break; |
---|
| 329 | case 's': |
---|
| 330 | { |
---|
| 331 | int fd; |
---|
| 332 | read(0, commandbuf, 3); |
---|
| 333 | commandbuf[2] = 0; |
---|
| 334 | fd = open((char*)commandbuf, O_CREAT|O_WRONLY, 0644); |
---|
| 335 | commandbuf[0] -= commandbuf[0]>='a' ? 'a'-10 : '0'; |
---|
| 336 | commandbuf[1] -= commandbuf[1]>='a' ? 'a'-10 : '0'; |
---|
| 337 | sndnum = (commandbuf[0]<<4) + commandbuf[1]; |
---|
| 338 | write(fd, S_sfx[sndnum].data, lengths[sndnum]); |
---|
| 339 | close(fd); |
---|
| 340 | } |
---|
| 341 | break; |
---|
| 342 | default: |
---|
| 343 | fprintf(stderr, "Did not recognize command\n"); |
---|
| 344 | break; |
---|
| 345 | } |
---|
| 346 | } |
---|
| 347 | } |
---|
| 348 | } while (rc > 0); |
---|
| 349 | updatesounds(); |
---|
| 350 | } |
---|
| 351 | |
---|
| 352 | closesfxdev(); |
---|
| 353 | closemusdev(); |
---|
| 354 | |
---|
| 355 | } |
---|