📄 asap.c
字号:
if (song[j << (2 + sap_stereo)] != 0xfe) break; j = song[(j << (2 + sap_stereo)) + 1]; } while (j < song_len && !seen[j]); song_pos[sap_songs++] = (UBYTE) j; j++; while (j < song_len && !seen[j]) { seen[j] = TRUE; if (song[j << (2 + sap_stereo)] != 0xfe) j++; else j = song[(j << (2 + sap_stereo)) + 1]; } } return sap_songs != 0;}static int load_tmc(const unsigned char *module, unsigned int module_len){ unsigned int i; if (module_len < 0x1d0) return FALSE; if (!load_native(module, module_len, tmc_obx, 't')) return FALSE; tmc_per_frame = module[37]; if (tmc_per_frame < 1 || tmc_per_frame > 4) return FALSE; sap_fastplay = perframe2fastplay[tmc_per_frame - 1]; i = 0; /* find first instrument */ while (module[0x66 + i] == 0) { if (++i >= 64) return FALSE; /* no instrument */ } i = (module[0x66 + i] << 8) + module[0x26 + i] - sap_music - 1 + 6; if (i >= module_len) return FALSE; /* skip trailing jumps */ do { if (i <= 0x1b5) return FALSE; /* no pattern to play */ i -= 16; } while (module[i] >= 0x80); while (i >= 0x1b5) { if (module[i] >= 0x80) sap_songs++; i -= 16; } return TRUE;}static int load_tm2(const unsigned char *module, unsigned int module_len){ unsigned int i; unsigned int song_end; unsigned char c; if (module_len < 0x3a4) return FALSE; i = module[0x25]; if (i < 1 || i > 4) return FALSE; sap_fastplay = perframe2fastplay[i - 1]; if (!load_native(module, module_len, tm2_obx, 'T')) return FALSE; /* TODO: quadrophonic */ if (module[0x1f] != 0)#ifdef STEREO_SOUND sap_stereo = 1;#else return FALSE;#endif sap_player = 0x500; song_end = 0xffff; for (i = 0; i < 0x80; i++) { unsigned int instr_addr = module[0x86 + i] + (module[0x306 + i] << 8); if (instr_addr != 0 && instr_addr < song_end) song_end = instr_addr; } for (i = 0; i < 0x100; i++) { unsigned int pattern_addr = module[0x106 + i] + (module[0x206 + i] << 8); if (pattern_addr != 0 && pattern_addr < song_end) song_end = pattern_addr; } if (song_end < sap_music + 0x380U + 2U * 17U) return FALSE; i = song_end - sap_music - 0x380; if (0x386 + i >= module_len) return FALSE; i -= i % 17; /* skip trailing stop/jump commands */ do { if (i == 0) return FALSE; i -= 17; c = module[0x386 + 16 + i]; } while (c == 0 || c >= 0x80); /* count stop/jump commands */ while (i > 0) { i -= 17; c = module[0x386 + 16 + i]; if (c == 0 || c >= 0x80) sap_songs++; } return TRUE;}static int tag_matches(const char *tag, const UBYTE *sap_ptr, const UBYTE *sap_end){ size_t len = strlen(tag); return (sap_ptr + len + 8 < sap_end) && memcmp(tag, sap_ptr, len) == 0;}static int parse_hex(const UBYTE **ps, UWORD *retval){ int chars = 0; *retval = 0; while (**ps != 0x0d) { char c; if (++chars > 4) return FALSE; c = (char) *(*ps)++; *retval <<= 4; if (c >= '0' && c <= '9') *retval += c - '0'; else if (c >= 'A' && c <= 'F') *retval += c - 'A' + 10; else if (c >= 'a' && c <= 'f') *retval += c - 'a' + 10; else return FALSE; } return chars != 0;}static int parse_dec(const UBYTE **ps, unsigned int *retval){ int chars = 0; *retval = 0; while (**ps != 0x0d) { char c; if (++chars > 3) return FALSE; c = (char) *(*ps)++; *retval *= 10; if (c >= '0' && c <= '9') *retval += c - '0'; else return FALSE; } return chars != 0;}static int load_sap(const UBYTE *sap_ptr, const UBYTE * const sap_end){ if (!tag_matches("SAP", sap_ptr, sap_end)) return FALSE; sap_type = '?'; sap_player = 0xffff; sap_music = 0xffff; sap_init = 0xffff; sap_ptr += 3; for (;;) { if (sap_ptr + 8 >= sap_end || sap_ptr[0] != 0x0d || sap_ptr[1] != 0x0a) return FALSE; sap_ptr += 2; if (sap_ptr[0] == 0xff) break; if (tag_matches("TYPE ", sap_ptr, sap_end)) { sap_ptr += 5; sap_type = *sap_ptr++; } else if (tag_matches("PLAYER ", sap_ptr, sap_end)) { sap_ptr += 7; if (!parse_hex(&sap_ptr, &sap_player)) return FALSE; } else if (tag_matches("MUSIC ", sap_ptr, sap_end)) { sap_ptr += 6; if (!parse_hex(&sap_ptr, &sap_music)) return FALSE; } else if (tag_matches("INIT ", sap_ptr, sap_end)) { sap_ptr += 5; if (!parse_hex(&sap_ptr, &sap_init)) return FALSE; } else if (tag_matches("SONGS ", sap_ptr, sap_end)) { sap_ptr += 6; if (!parse_dec(&sap_ptr, &sap_songs) || sap_songs < 1 || sap_songs > 255) return FALSE; } else if (tag_matches("DEFSONG ", sap_ptr, sap_end)) { sap_ptr += 8; if (!parse_dec(&sap_ptr, &sap_defsong)) return FALSE; } else if (tag_matches("FASTPLAY ", sap_ptr, sap_end)) { sap_ptr += 9; if (!parse_dec(&sap_ptr, &sap_fastplay) || sap_fastplay < 1 || sap_fastplay > 312) return FALSE; } else if (tag_matches("STEREO", sap_ptr, sap_end))#ifdef STEREO_SOUND sap_stereo = 1;#else return FALSE;#endif /* ignore unknown tags */ while (sap_ptr[0] != 0x0d) { sap_ptr++; if (sap_ptr >= sap_end) return FALSE; } } if (sap_defsong >= sap_songs) return FALSE; switch (sap_type) { case 'B': if (sap_player == 0xffff || sap_init == 0xffff) return FALSE; break; case 'C': if (sap_player == 0xffff || sap_music == 0xffff) return FALSE; break; default: return FALSE; } if (sap_ptr[1] != 0xff) return FALSE; memset(memory, 0, sizeof(memory)); sap_ptr += 2; while (sap_ptr + 5 <= sap_end) { int start_addr = sap_ptr[0] + (sap_ptr[1] << 8); int block_len = sap_ptr[2] + (sap_ptr[3] << 8) + 1 - start_addr; if (block_len <= 0 || sap_ptr + block_len > sap_end) return FALSE; sap_ptr += 4; memcpy(memory + start_addr, sap_ptr, block_len); sap_ptr += block_len; if (sap_ptr == sap_end) return TRUE; if (sap_ptr + 7 <= sap_end && sap_ptr[0] == 0xff && sap_ptr[1] == 0xff) sap_ptr += 2; } return FALSE;}#define EXT(c1, c2, c3) ((c1 + (c2 << 8) + (c3 << 16)) | 0x202020)int ASAP_Load(const char *filename, const unsigned char *module, unsigned int module_len){ const char *p; int ext; for (p = filename; *p != '\0'; p++); ext = 0; for (;;) { if (--p <= filename || *p < ' ') return FALSE; /* no filename extension or invalid character */ if (*p == '.') break; ext = (ext << 8) + (*p & 0xff); } sap_stereo = 0; sap_songs = 1; sap_defsong = 0; sap_fastplay = 312; switch (ext | 0x202020) { case EXT('C', 'M', 'C'): return load_cmc(module, module_len, FALSE); case EXT('C', 'M', 'R'): return load_cmc(module, module_len, TRUE); case EXT('D', 'M', 'C'): sap_fastplay = 156; return load_cmc(module, module_len, FALSE); case EXT('M', 'P', 'D'): sap_fastplay = 156; return load_mpt(module, module_len); case EXT('M', 'P', 'T'): return load_mpt(module, module_len); case EXT('R', 'M', 'T'): return load_rmt(module, module_len); case EXT('S', 'A', 'P'): return load_sap(module, module + module_len); case EXT('T', 'M', '2'): return load_tm2(module, module_len);#ifdef STEREO_SOUND case EXT('T', 'M', '8'): sap_stereo = 1; return load_tmc(module, module_len);#endif case EXT('T', 'M', 'C'): return load_tmc(module, module_len); default: return FALSE; }}unsigned int ASAP_GetChannels(void){ return 1 << sap_stereo;}unsigned int ASAP_GetSongs(void){ return sap_songs;}unsigned int ASAP_GetDefSong(void){ return sap_defsong;}static void call_6502(UWORD addr, int max_scanlines){ regPC = addr; /* put a CIM at 0xd20a and a return address on stack */ dPutByte(0xd20a, 0xd2); dPutByte(0x01fe, 0x09); dPutByte(0x01ff, 0xd2); regS = 0xfd; xpos = 0; GO(max_scanlines * (LINE_C - DMAR));}/* 50 Atari frames for the initialization routine - some SAPs are self-extracting. */#define SCANLINES_FOR_INIT (50 * 312)void ASAP_PlaySong(unsigned int song){ UWORD addr; if (enable_stereo != sap_stereo) { Pokey_sound_init(ASAP_MAIN_CLOCK, (uint16) block_rate, 1 << sap_stereo, sample_16bit ? SND_BIT16 : 0); enable_stereo = sap_stereo; } for (addr = _AUDF1; addr <= _STIMER; addr++) POKEY_PutByte(addr, 0); if (sap_stereo) for (addr = _AUDF1 + _POKEY2; addr <= _STIMER + _POKEY2; addr++) POKEY_PutByte(addr, 0); blockclocks = 0; blockclocks_per_player = 114U * sap_fastplay * block_rate; regP = 0x30; switch (sap_type) { case 'B': regA = (UBYTE) song; regX = 0x00; regY = 0x00; /* 5 frames should be enough */ call_6502(sap_init, SCANLINES_FOR_INIT); break; case 'C': regA = 0x70; regX = (UBYTE) sap_music; regY = (UBYTE) (sap_music >> 8); call_6502((UWORD) (sap_player + 3), SCANLINES_FOR_INIT); regA = 0x00; regX = (UBYTE) song; call_6502((UWORD) (sap_player + 3), SCANLINES_FOR_INIT); break; case 'm': regA = 0x00; regX = (UBYTE) (sap_music >> 8); regY = (UBYTE) sap_music; call_6502(sap_player, SCANLINES_FOR_INIT); regA = 0x02; regX = song_pos[song]; call_6502(sap_player, SCANLINES_FOR_INIT); break; case 'r': regA = song_pos[song]; regX = (UBYTE) sap_music; regY = (UBYTE) (sap_music >> 8); call_6502(sap_player, SCANLINES_FOR_INIT); break; case 't': case 'T': regA = 0x70; regX = (UBYTE) (sap_music >> 8); regY = (UBYTE) sap_music; call_6502(sap_player, SCANLINES_FOR_INIT); regA = 0x00; regX = (UBYTE) song; call_6502(sap_player, SCANLINES_FOR_INIT); tmc_per_frame_counter = 1; break; }}void ASAP_Generate(void *buffer, unsigned int buffer_len){ /* convert number of bytes to number of blocks */ buffer_len >>= sample_16bit + enable_stereo; if (buffer_len == 0U) return; for (;;) { unsigned int blocks = blockclocks / ASAP_MAIN_CLOCK; if (blocks != 0U) { unsigned int samples; if (blocks > buffer_len) blocks = buffer_len; buffer_len -= blocks; samples = blocks << enable_stereo; blockclocks -= blocks * ASAP_MAIN_CLOCK; Pokey_process(buffer, samples); /* swap bytes in non-native words if necessary */ if (sample_format ==#ifdef WORDS_BIGENDIAN AUDIO_FORMAT_S16_LE#else AUDIO_FORMAT_S16_BE#endif ) { unsigned char *p = (unsigned char *) buffer; unsigned int n = samples; do { unsigned char t = p[0]; p[0] = p[1]; p[1] = t; p += 2; } while (--n != 0U); } if (buffer_len == 0U) return; buffer = (void *) ((unsigned char *) buffer + (samples << sample_16bit)); } switch (sap_type) { case 'B': call_6502(sap_player, sap_fastplay); break; case 'C': call_6502((UWORD) (sap_player + 6), sap_fastplay); break; case 'm': case 'r': case 'T': call_6502((UWORD) (sap_player + 3), sap_fastplay); break; case 't': if (--tmc_per_frame_counter <= 0) { tmc_per_frame_counter = tmc_per_frame; call_6502((UWORD) (sap_player + 3), sap_fastplay); } else call_6502((UWORD) (sap_player + 6), sap_fastplay); break; } random_scanline_counter = (random_scanline_counter + LINE_C * sap_fastplay) % ((AUDCTL[0] & POLY9) ? POLY9_SIZE : POLY17_SIZE); blockclocks += blockclocks_per_player; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -