void scir_unlock_resource(resource_mgr_t *mgr, resource_t *res, int resnum, int restype) { if (!res) { sciprintf("Resmgr: Warning: Attempt to unlock non-existant" " resource %s.%03d!\n", sci_resource_types[restype], resnum); return; } if (res->status != SCI_STATUS_LOCKED) { sciprintf("Resmgr: Warning: Attempt to unlock unlocked" " resource %s.%03d\n", sci_resource_types[res->type], res->number); return; } if (!--res->lockers) { /* No more lockers? */ res->status = SCI_STATUS_ALLOCATED; mgr->memory_locked -= res->size; _scir_add_to_lru(mgr, res); } _scir_free_old_resources(mgr, 0); }
static void print_map_mem(int sci, int ins, int rhythm, char *mt32) { #ifdef DEBUG_MT32_TO_GM char name[11]; strncpy(name, mt32, 10); name[10] = 0; if (ins == SFX_UNMAPPED || (ins == SFX_MAPPED_TO_RHYTHM && rhythm == SFX_UNMAPPED)) { sciprintf("[MT32-to-GM] No mapping available for [%i] `%s'\n", sci, name); return; } if (ins == SFX_MAPPED_TO_RHYTHM) { sciprintf("[MT32-to-GM] Mapping [%i] `%s' to `%s' [R] (%i)\n", sci, name, GM_Percussion_Names[rhythm], rhythm); return; } sciprintf("[MT32-to-GM] Mapping [%i] `%s' to `%s' (%i)\n", sci, name, GM_Instrument_Names[ins], ins); #endif }
resource_t * scir_find_resource(resource_mgr_t *mgr, int type, int number, int lock) { resource_t *retval; if (number >= sci_max_resource_nr[mgr->sci_version]) { int modded_number = number % sci_max_resource_nr[mgr->sci_version]; sciprintf("[resmgr] Requested invalid resource %s.%d, mapped to %s.%d\n", sci_resource_types[type], number, sci_resource_types[type], modded_number); number = modded_number; } retval = scir_test_resource(mgr, type, number); if (!retval) return NULL; if (!retval->status) _scir_load_resource(mgr, retval, 0); else if (retval->status == SCI_STATUS_ENQUEUED) _scir_remove_from_lru(mgr, retval); /* Unless an error occured, the resource is now either ** locked or allocated, but never queued or freed. */ if (lock) { if (retval->status == SCI_STATUS_ALLOCATED) { retval->status = SCI_STATUS_LOCKED; retval->lockers = 0; mgr->memory_locked += retval->size; } ++retval->lockers; } else if (retval->status != SCI_STATUS_LOCKED) { /* Don't lock it */ if (retval->status == SCI_STATUS_ALLOCATED) _scir_add_to_lru(mgr, retval); } _scir_free_old_resources(mgr, retval->status == SCI_STATUS_ALLOCATED); if (retval->data) return retval; else { sciprintf("Resmgr: Failed to read %s.%03d\n", sci_resource_types[retval->type], retval->number); return NULL; } }
static void _scir_add_to_lru(resource_mgr_t *mgr, resource_t *res) { if (res->status != SCI_STATUS_ALLOCATED) { sciprintf("Resmgr: Oops: trying to enqueue resource with state" " %d\n", res->status); return; } res->prev = NULL; res->next = mgr->lru_first; mgr->lru_first = res; if (!mgr->lru_last) mgr->lru_last = res; if (res->next) res->next->prev = res; mgr->memory_lru += res->size; #if (SCI_VERBOSE_RESMGR > 1) fprintf(stderr, "Adding %s.%03d (%d bytes) to lru control: %d bytes total\n", sci_resource_types[res->type], res->number, res->size, mgr->memory_lru); #endif res->status = SCI_STATUS_ENQUEUED; }
static int fluidsynth_init(sfx_softseq_t *self, byte *data_ptr, int data_length, byte *data2_ptr, int data2_length) { int sfont_id; double min, max; if (0) { sciprintf("FluidSynth ERROR: Mono sound output not supported.\n"); return SFX_ERROR; } gmseq = sfx_find_sequencer("General MIDI"); if (!gmseq) { sciprintf("FluidSynth ERROR: Unable to find General MIDI sequencer.\n"); return SFX_ERROR; } settings = new_fluid_settings(); fluid_settings_getnum_range(settings, "synth.sample-rate", &min, &max); if (SAMPLE_RATE < min || SAMPLE_RATE > max) { sciprintf("FluidSynth ERROR: Sample rate '%i' not supported. Valid " "range is (%i-%i).\n", SAMPLE_RATE, (int) min, (int) max); delete_fluid_settings(settings); return SFX_ERROR; } fluid_settings_setnum(settings, "synth.sample-rate", SAMPLE_RATE); fluid_settings_setnum(settings, "synth.gain", 0.5f); synth = new_fluid_synth(settings); if ((sfont_id = fluid_synth_sfload(synth, soundfont, 1)) < 0) { delete_fluid_synth(synth); delete_fluid_settings(settings); return SFX_ERROR; } gmseq->open(data_length, data_ptr, data2_length, data2_ptr, &midi_writer_fluidsynth); return SFX_OK; }
static void print_map_rhythm_mem(int sci, int rhythm, char *mt32) { #ifdef DEBUG_MT32_TO_GM char name[11]; strncpy(name, mt32, 10); name[10] = 0; if (rhythm == SFX_UNMAPPED) { sciprintf("[MT32-to-GM] No mapping available for [%i] `%s'\n", sci, name); return; } sciprintf("[MT32-to-GM] Mapping [%i] `%s' to `%s' (%i)\n", sci, name, GM_Percussion_Names[rhythm], rhythm); #endif }
static void print_map_rhythm(int sci, int ins, int rhythm, int mt32) { #ifdef DEBUG_MT32_TO_GM if (ins == SFX_UNMAPPED || (ins == SFX_MAPPED_TO_RHYTHM && rhythm == SFX_UNMAPPED)) { sciprintf("[MT32-to-GM] No mapping available for [%i] `%s' [R] (%i)\n", sci, MT32_RhythmTimbreMaps[mt32].name, mt32); return; } if (ins == SFX_MAPPED_TO_RHYTHM) { sciprintf("[MT32-to-GM] Mapping [%i] `%s' [R] (%i) to `%s' [R] (%i)\n", sci, MT32_RhythmTimbreMaps[mt32].name, mt32, GM_Percussion_Names[rhythm], rhythm); return; } sciprintf("[MT32-to-GM] Mapping [%i] `%s' [R] (%i) to `%s' (%i)\n", sci, MT32_RhythmTimbreMaps[mt32].name, mt32, GM_Instrument_Names[ins], ins); #endif }
static void pcmout_sdl_exit(sfx_pcm_device_t *self) { SDL_PauseAudio (1); SDL_CloseAudio(); sfx_audbuf_free(&audio_buffer); SDL_QuitSubSystem(SDL_INIT_AUDIO); if (!SDL_WasInit(SDL_INIT_EVERYTHING)) { sciprintf("[SND:SDL] No active SDL subsystems found.. shutting down SDL\n"); SDL_Quit(); } }
static void pcmout_alsa_exit(sfx_pcm_device_t *self) { int err; run_thread = 0; sciprintf("[SND:ALSA] Waiting for PCM thread to exit... "); if (!pthread_join(thread, NULL)) sciprintf("OK\n"); else sciprintf("Failed\n"); pthread_mutex_destroy(&mutex); if ((err = snd_pcm_drop(handle)) < 0) { sciprintf("[SND:ALSA] Can't stop PCM device: %s\n", snd_strerror(err)); } if ((err = snd_pcm_close(handle)) < 0) { sciprintf("[SND:ALSA] Can't close PCM device: %s\n", snd_strerror(err)); } sfx_audbuf_free(&audio_buffer); }
static void _scir_load_from_patch_file(int fh, resource_t *res, char *filename) { int really_read; res->data = (unsigned char*)sci_malloc(res->size); really_read = read(fh, res->data, res->size); if (really_read < res->size) { sciprintf("Error: Read %d bytes from %s but expected %d!\n", really_read, filename, res->size); exit(1); } res->status = SCI_STATUS_ALLOCATED; }
int version_parse(char *vn, sci_version_t *result) { char *endptr[3]; int major = strtol(vn, &endptr[0], 10); int minor = strtol(vn + 2, &endptr[1], 10); int patchlevel = strtol(vn + 6, &endptr[2], 10); if (endptr[0] != vn + 1 || endptr[1] != vn + 5 || *endptr[2] != '\0') { sciprintf("Warning: Failed to parse version string '%s'\n", vn); return 1; } *result = SCI_VERSION(major, minor, patchlevel); return 0; }
static int mix_init(sfx_pcm_mixer_t *self, sfx_pcm_device_t *device) { self->dev = device; self->private_bits /* = P */ = sci_malloc(sizeof(struct mixer_private)); P->outbuf = P->writebuf = NULL; P->lastbuf_len = 0; P->compbuf_l = (gint32*)sci_malloc(sizeof(gint32) * device->buf_size); P->compbuf_r = (gint32*)sci_malloc(sizeof(gint32) * device->buf_size); P->played_this_second = 0; P->paused = 0; #ifdef DEBUG sciprintf("[soft-mixer] Initialised device %s v%s (%d Hz, %d/%x)\n", device->name, device->version, device->conf.rate, device->conf.stereo, device->conf.format); #endif return SFX_OK; }
void version_require_later_than(state_t *s, sci_version_t version) { if (s->version_lock_flag) return; if (version > s->max_version) { sciprintf("Version autodetect conflict: More than %d.%03d.%03d was requested, but less than" "%d.%03d.%03d is required ATM\n", SCI_VERSION_MAJOR(version), SCI_VERSION_MINOR(version), SCI_VERSION_PATCHLEVEL(version), SCI_VERSION_MAJOR(s->max_version), SCI_VERSION_MINOR(s->max_version), SCI_VERSION_PATCHLEVEL(s->max_version)); return; } else if (version > s->min_version) { s->min_version = version; if (s->min_version > s->version) s->version = s->min_version; } }
void version_require_earlier_than(state_t *s, sci_version_t version) { if (s->version_lock_flag) return; if (version <= s->min_version) { sciprintf("Version autodetect conflict: Less than %d.%03d.%03d was requested, but " "%d.%03d.%03d is the current minimum\n", SCI_VERSION_MAJOR(version), SCI_VERSION_MINOR(version), SCI_VERSION_PATCHLEVEL(version), SCI_VERSION_MAJOR(s->min_version), SCI_VERSION_MINOR(s->min_version), SCI_VERSION_PATCHLEVEL(s->min_version)); return; } else if (version < s->max_version) { s->max_version = version -1; if (s->max_version < s->version) s->version = s->max_version; } }
static void _scir_remove_from_lru(resource_mgr_t *mgr, resource_t *res) { if (res->status != SCI_STATUS_ENQUEUED) { sciprintf("Resmgr: Oops: trying to remove resource that isn't" " enqueued\n"); return; } if (res->next) res->next->prev = res->prev; if (res->prev) res->prev->next = res->next; if (mgr->lru_first == res) mgr->lru_first = res->next; if (mgr->lru_last == res) mgr->lru_last = res->prev; mgr->memory_lru -= res->size; res->status = SCI_STATUS_ALLOCATED; }
static void _scir_free_old_resources(resource_mgr_t *mgr, int last_invulnerable) { while (mgr->max_memory < mgr->memory_lru && (!last_invulnerable || mgr->lru_first != mgr->lru_last)) { resource_t *goner = mgr->lru_last; if (!goner) { fprintf(stderr,"Internal error: mgr->lru_last is NULL!\n"); fprintf(stderr,"LRU-mem= %d\n", mgr->memory_lru); fprintf(stderr,"lru_first = %p\n", (void *)mgr->lru_first); _scir_print_lru_list(mgr); } _scir_remove_from_lru(mgr, goner); _scir_unalloc(goner); #ifdef SCI_VERBOSE_RESMGR sciprintf("Resmgr-debug: LRU: Freeing %s.%03d (%d bytes)\n", sci_resource_types[goner->type], goner->number, goner->size); #endif } }
static void _mix_unsubscribe(sfx_pcm_mixer_t *self, sfx_pcm_feed_t *feed) { int i; #ifdef DEBUG sciprintf("[soft-mixer] Unsubscribing %s-%x\n", feed->debug_name, feed->debug_nr); #endif for (i = 0; i < self->feeds_nr; i++) { sfx_pcm_feed_state_t *fs = self->feeds + i; if (fs->feed == feed) { feed->destroy(feed); if (fs->buf) sci_free(fs->buf); self->feeds_nr--; /* Copy topmost into deleted so that we don't have any holes */ if (i != self->feeds_nr) self->feeds[i] = self->feeds[self->feeds_nr]; if (self->feeds_allocd > 8 && self->feeds_allocd > (self->feeds_nr << 1)) { /* Limit memory waste */ self->feeds_allocd >>= 1; self->feeds = (sfx_pcm_feed_state_t*)sci_realloc(self->feeds, sizeof(sfx_pcm_feed_state_t) * self->feeds_allocd); } for (i = 0; i < self->feeds_nr; i++) fprintf(stderr, " Feed #%d: %s-%x\n", i, self->feeds[i].feed->debug_name, self->feeds[i].feed->debug_nr); return; }
reg_t kGetEvent(state_t *s, int funct_nr, int argc, reg_t *argv) { int mask = UKPV(0); reg_t obj = argv[1]; sci_event_t e; int oldx, oldy; int modifier_mask = SCI_VERSION_MAJOR(s->version)==0 ? SCI_EVM_ALL : SCI_EVM_NO_FOOLOCK; if (s->kernel_opt_flags & KERNEL_OPT_FLAG_GOT_2NDEVENT) { /* Penalty time- too many requests to this function without ** waiting! */ int delay = s->script_000->locals_block->locals[SCI_VARIABLE_GAME_SPEED].offset; gfxop_usleep(s->gfx_state, (1000000 * delay) / 60); } /*If there's a simkey pending, and the game wants a keyboard event, use the *simkey instead of a normal event*/ if (_kdebug_cheap_event_hack && (mask & SCI_EVT_KEYBOARD)) { PUT_SEL32V(obj, type, SCI_EVT_KEYBOARD); /*Keyboard event*/ PUT_SEL32V(obj, message, _kdebug_cheap_event_hack); PUT_SEL32V(obj, modifiers, SCI_EVM_NUMLOCK); /*Numlock on*/ PUT_SEL32V(obj, x, s->gfx_state->pointer_pos.x); PUT_SEL32V(obj, y, s->gfx_state->pointer_pos.y); _kdebug_cheap_event_hack = 0; return make_reg(0, 1); } oldx = s->gfx_state->pointer_pos.x; oldy = s->gfx_state->pointer_pos.y; e = gfxop_get_event(s->gfx_state, mask); s->parser_event = NULL_REG; /* Invalidate parser event */ PUT_SEL32V(obj, x, s->gfx_state->pointer_pos.x); PUT_SEL32V(obj, y, s->gfx_state->pointer_pos.y); /* gfxop_set_pointer_position(s->gfx_state, gfx_point(s->gfx_state->pointer_pos.x, s->gfx_state->pointer_pos.y)); */ if (e.type) s->kernel_opt_flags &= ~(KERNEL_OPT_FLAG_GOT_EVENT | KERNEL_OPT_FLAG_GOT_2NDEVENT); else { if (s->kernel_opt_flags & KERNEL_OPT_FLAG_GOT_EVENT) s->kernel_opt_flags |= KERNEL_OPT_FLAG_GOT_2NDEVENT; else s->kernel_opt_flags |= KERNEL_OPT_FLAG_GOT_EVENT; } switch(e.type) { case SCI_EVT_QUIT: quit_vm(); break; case SCI_EVT_KEYBOARD: { if ((e.buckybits & SCI_EVM_LSHIFT) && (e.buckybits & SCI_EVM_RSHIFT) && (e.data == '-')) { sciprintf("Debug mode activated\n"); script_debug_flag = 1; /* Enter debug mode */ _debug_seeking = _debug_step_running = 0; s->onscreen_console = 0; } else if ((e.buckybits & SCI_EVM_CTRL) && (e.data == '`')) { script_debug_flag = 1; /* Enter debug mode */ _debug_seeking = _debug_step_running = 0; s->onscreen_console = 1; } else if ((e.buckybits & SCI_EVM_CTRL) && (e.data == '1')) { if (s->visual) s->visual->print(GFXW(s->visual), 0); } else { PUT_SEL32V(obj, type, SCI_EVT_KEYBOARD); /*Keyboard event*/ s->r_acc=make_reg(0, 1); PUT_SEL32V(obj, message, e.character); /* We only care about the translated ** character */ PUT_SEL32V(obj, modifiers, e.buckybits&modifier_mask); } } break; case SCI_EVT_MOUSE_RELEASE: case SCI_EVT_MOUSE_PRESS: { int extra_bits=0; if(mask & e.type) { switch(e.data) { case 2: extra_bits=SCI_EVM_LSHIFT|SCI_EVM_RSHIFT; break; case 3: extra_bits=SCI_EVM_CTRL; default:break; } PUT_SEL32V(obj, type, e.type); PUT_SEL32V(obj, message, 1); PUT_SEL32V(obj, modifiers, (e.buckybits|extra_bits)&modifier_mask); s->r_acc = make_reg(0, 1); } } break; default: { s->r_acc = NULL_REG; /* Unknown or no event */ } } if ((s->r_acc.offset) && (stop_on_event)) { stop_on_event = 0; script_debug_flag = 1; } return s->r_acc; }
static void timer_sdl_internal_callback(void *userdata, byte *dest, int len) { sci_gettime(&last_callback_secs, &last_callback_usecs); last_callback_len = len; if (sdl_sfx_timer_callback) sdl_sfx_timer_callback(sdl_sfx_timer_data); #if 0 if (!sfx_audbuf_read_timestamp(&audio_buffer, &ts)) { int delta = (buf_size - len) / frame_size; sfx_timestamp_t real_ts; long deltatime; long sec2, usec2; sci_gettime(&sec2, &usec2); real_ts = sfx_timestamp_add(sfx_new_timestamp(sec, usec, rate), delta); deltatime = sfx_timestamp_usecs_diff(ts, real_ts); fprintf(stderr, "[SDL] Frames requested: %d Playing %ld too late. Needed %ldus for computations.\n", len / frame_size, deltatime, (usec2-usec) + (sec2-sec)*1000000); if (abs(deltatime) > DELTA_TIME_LIMIT) sciprintf("[SND:SDL] Very high delta time for PCM playback: %ld too late (%d frames in the future)\n", deltatime, sfx_timestamp_frame_diff(sfx_new_timestamp(sec, usec, rate), ts)); #if 0 if (deltatime < 0) { /* Read and discard frames, explicitly underrunning */ int max_read = len / frame_size; int frames_to_kill = sfx_timestamp_frame_diff(real_ts, ts); while (frames_to_kill) { int d = frames_to_kill > max_read? max_read : frames_to_kill; sfx_audbuf_read(&audio_buffer, dest, d); frames_to_kill -= d; } } #endif } #endif sfx_audbuf_read(&audio_buffer, dest, len / frame_size); #if 0 if (!fil) { fil = fopen("/tmp/sdl.log", "w"); } { int i; int end = len / frame_size; gint16 *d = dest; fprintf(fil, "Writing %d/%d\n", len, frame_size); for (i = 0; i < end; i++) { fprintf(fil, "\t%d\t%d\n", d[0], d[1]); d += 2; } } #endif }
static int fluidsynth_midi_write(struct _midi_writer *self, unsigned char *buf, int len) { if (buf[0] == 0xf0) sciprintf("FluidSynth: Skipping sysex message.\n"); else if (len == 2) { guint8 command, channel; command = buf[0] & 0xf0; channel = buf[0] & 0x0f; switch(command) { case 0xc0: fluid_synth_program_change(synth, channel, buf[1]); break; default: printf("FluidSynth: MIDI command [%02x %02x] not supported\n", buf[0], buf[1]); } } else if (len == 3) { guint8 command, channel; command = buf[0] & 0xf0; channel = buf[0] & 0x0f; switch(command) { case 0x80: fluid_synth_noteoff(synth, channel, buf[1]); break; case 0x90: fluid_synth_noteon(synth, channel, buf[1], buf[2]); break; case 0xb0: switch (buf[1]) { case 0x06: /* Data Entry Slider - course */ if (rpn[channel] == 0) fluid_synth_pitch_wheel_sens(synth, channel, buf[2]); else sciprintf("FluidSynth: RPN %i not supported\n", rpn[channel]); case 0x64: /* Registered Parameter Number (RPN) - fine */ rpn[channel] &= ~0x7f; rpn[channel] |= buf[2] & 0x7f; break; case 0x65: /* Registered Parameter Number (RPN) - course */ rpn[channel] &= ~0x3f80; rpn[channel] |= (buf[2] & 0x7f) << 7; break; default: fluid_synth_cc(synth, channel, buf[1], buf[2]); } break; case 0xe0: fluid_synth_pitch_bend(synth, channel, (buf[2] << 7) | buf[1]); break; default: sciprintf("FluidSynth: MIDI command [%02x %02x %02x] not supported\n", buf[0], buf[1], buf[2]); } } else sciprintf("FluidSynth: Skipping invalid message of %i bytes.\n", len); return SFX_OK; }
const char * /* Original version by Solomon Peachy */ version_guess_from_hashcode(sci_version_t *result, int *res_version, guint32 *code) { int i; int fd = -1; int left = VERSION_DETECT_HASH_SIZE; guint32 hash_code; guint8 buf[VERSION_DETECT_BUF_SIZE]; if (IS_VALID_FD(fd = sci_open("resource.001", O_RDONLY|O_BINARY))) { hash_code = HASHCODE_MAGIC_RESOURCE_001; } else if (IS_VALID_FD(fd = sci_open("resource.000", O_RDONLY|O_BINARY))) { hash_code = HASHCODE_MAGIC_RESOURCE_000; } else { sciprintf("Warning: Could not find RESOURCE.000 or RESOURCE.001, cannot determine hash code\n"); *code = 0; /* complete and utter failure */ return NULL; } while (left > 0) { int len = read(fd, buf, left < VERSION_DETECT_BUF_SIZE ? left : VERSION_DETECT_BUF_SIZE); if (len == -1) { sciprintf("Warning: read error while computing hash code for resource file\n"); *code = 0; return NULL; } if (len == 0) /* EOF */ break; for (i = 0; i < len; i++) hash_code = (hash_code * 19) + *(buf + i); /* This is the string hashing algorithm used by Objective Caml 3.08; the general idea ** of multiplying the previous hash code with a prime number between 5 and 23 appears ** to be generally considered to be a "good" approach to exhausting the entire 32 bit ** number space in a somewhat equal distribution. For large chunks of data, such as ** SCI resource files, this should both perform well and yield a good distribution, ** or at least that's what standard library designers have been assuming for quite a ** while. */ left -= len; } close(fd); *code = hash_code; for (i = 0 ; sci_games[i].name ; i++) { if (sci_games[i].id == hash_code) { *result = sci_games[i].version; *res_version = sci_games[i].res_version; return sci_games[i].name; } } return NULL; /* Failed to find matching game */ }
sfx_instrument_map_t * sfx_instrument_map_mt32_to_gm(byte *data, size_t size) { int memtimbres, patches; guint8 group, number, keyshift, finetune, bender_range; guint8 *patchpointer; guint32 pos; sfx_instrument_map_t * map; int i; int type; map = sfx_instrument_map_new(0); for (i = 0; i < SFX_INSTRUMENTS_NR; i++) { map->patch_map[i].patch = MT32_PresetTimbreMaps[i].gm_instr; map->patch_key_shift[i] = 0; map->patch_volume_adjust[i] = 0; map->patch_bend_range[i] = 12; map->velocity_map_index[i] = SFX_NO_VELOCITY_MAP; } map->percussion_volume_adjust = 0; map->percussion_velocity_map_index = SFX_NO_VELOCITY_MAP; for (i = 0; i < SFX_RHYTHM_NR; i++) { map->percussion_map[i] = MT32_PresetRhythmKeymap[i]; map->percussion_velocity_scale[i] = SFX_MAX_VELOCITY; } if (!data) { sciprintf("[MT32-to-GM] No MT-32 patch data supplied, using default mapping\n"); return map; } type = sfx_instrument_map_detect(data, size); if (type == SFX_MAP_UNKNOWN) { sciprintf("[MT32-to-GM] Patch data format unknown, using default mapping\n"); return map; } if (type == SFX_MAP_MT32_GM) { sciprintf("[MT32-to-GM] Patch data format not supported, using default mapping\n"); return map; } memtimbres = *(data + 0x1EB); pos = 0x1EC + memtimbres * 0xF6; if (size > pos && ((0x100 * *(data + pos) + *(data +pos + 1)) == 0xABCD)) { patches = 96; pos += 2 + 8 * 48; } else patches = 48; sciprintf("[MT32-to-GM] %d MT-32 Patches detected\n", patches); sciprintf("[MT32-to-GM] %d MT-32 Memory Timbres\n", memtimbres); sciprintf("[MT32-to-GM] Mapping patches..\n"); for (i = 0; i < patches; i++) { char *name; if (i < 48) patchpointer = data + 0x6B + 8 * i; else patchpointer = data + 0x1EC + 8 * (i - 48) + memtimbres * 0xF6 + 2; group = *patchpointer; number = *(patchpointer + 1); keyshift = *(patchpointer + 2); finetune = *(patchpointer + 3); bender_range = *(patchpointer + 4); switch (group) { case 0: map->patch_map[i].patch = MT32_PresetTimbreMaps[number].gm_instr; map->patch_map[i].rhythm = MT32_PresetTimbreMaps[number].gm_rhythm_key; print_map(i, map->patch_map[i].patch, map->patch_map[i].rhythm, number); break; case 1: map->patch_map[i].patch = MT32_PresetTimbreMaps[number + 64].gm_instr; map->patch_map[i].rhythm = MT32_PresetTimbreMaps[number + 64].gm_rhythm_key; print_map(i, map->patch_map[i].patch, map->patch_map[i].rhythm, number + 64); break; case 2: name = (char *) data + 0x1EC + number * 0xF6; map->patch_map[i].patch = lookup_instrument(name); map->patch_map[i].rhythm = SFX_UNMAPPED; print_map_mem(i, map->patch_map[i].patch, map->patch_map[i].rhythm, name); break; case 3: map->patch_map[i].patch = MT32_RhythmTimbreMaps[number].gm_instr; map->patch_map[i].rhythm = SFX_UNMAPPED; print_map_rhythm(i, map->patch_map[i].patch, map->patch_map[i].rhythm, number); break; default: break; } /* map->patch_key_shift[i] = (int) (keyshift & 0x3F) - 24; */ map->patch_bend_range[i] = bender_range & 0x1F; } if (size > pos && ((0x100 * *(data + pos) + *(data + pos + 1)) == 0xDCBA)) { sciprintf("[MT32-to-GM] Mapping percussion..\n"); for (i = 0; i < 64 ; i++) { number = *(data + pos + 4 * i + 2); if (number < 64) { char *name = (char *) data + 0x1EC + number * 0xF6; map->percussion_map[i + 23] = lookup_rhythm_key(name); print_map_rhythm_mem(i, map->percussion_map[i + 23], name); } else { if (number < 94) { map->percussion_map[i + 23] = MT32_RhythmTimbreMaps[number - 64].gm_rhythmkey; print_map_rhythm(i, SFX_MAPPED_TO_RHYTHM, map->percussion_map[i + 23], number - 64); } else map->percussion_map[i + 23] = SFX_UNMAPPED; } map->percussion_velocity_scale[i + 23] = *(data + pos + 4 * i + 3) * SFX_MAX_VELOCITY / 100; } } return map; }
static int pcmout_alsa_init(sfx_pcm_device_t *self) { unsigned int rrate; int err, dir; snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; pthread_attr_t attr; snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0); if (err < 0) { sciprintf("[SND:ALSA] Playback open error: %s\n", snd_strerror(err)); return SFX_ERROR; } err = snd_pcm_hw_params_any(handle, hwparams); if (err < 0) { sciprintf("[SND:ALSA] Broken configuration for playback: no configurations available: %s\n", snd_strerror(err)); return SFX_ERROR; } err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { sciprintf("[SND:ALSA] Access type not available for playback: %s\n", snd_strerror(err)); return SFX_ERROR; } err = snd_pcm_hw_params_set_format(handle, hwparams, format); if (err < 0) { sciprintf("[SND:ALSA] Sample format not available for playback: %s\n", snd_strerror(err)); return SFX_ERROR; } err = snd_pcm_hw_params_set_channels(handle, hwparams, channels); if (err < 0) { sciprintf("[SND:ALSA] Channels count (%i) not available for playback: %s\n", channels, snd_strerror(err)); return SFX_ERROR; } rrate = rate; err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rrate, 0); if (err < 0) { sciprintf("[SND:ALSA] Rate %iHz not available for playback: %s\n", rate, snd_strerror(err)); return SFX_ERROR; } if (rrate != rate) { sciprintf("[SND:ALSA] Rate doesn't match (requested %iHz, get %iHz)\n", rate, err); return SFX_ERROR; } err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir); if (err < 0) { sciprintf("[SND:ALSA] Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err)); return SFX_ERROR; } err = snd_pcm_hw_params_get_buffer_size(hwparams, (snd_pcm_uframes_t*)&buffer_size); if (err < 0) { sciprintf("[SND:ALSA] Unable to get buffer size for playback: %s\n", snd_strerror(err)); return SFX_ERROR; } err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir); if (err < 0) { sciprintf("[SND:ALSA] Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err)); return SFX_ERROR; } err = snd_pcm_hw_params_get_period_size(hwparams, (snd_pcm_uframes_t*)&period_size, &dir); if (err < 0) { sciprintf("[SND:ALSA] Unable to get period size for playback: %s\n", snd_strerror(err)); return SFX_ERROR; } if (period_size >= buffer_size) { sciprintf("[SND:ALSA] Period size %i matches or exceeds buffer size %i\n", period_size, buffer_size); return SFX_ERROR; } err = snd_pcm_hw_params(handle, hwparams); if (err < 0) { sciprintf("[SND:ALSA] Unable to set hw params for playback: %s\n", snd_strerror(err)); return SFX_ERROR; } err = snd_pcm_sw_params_current(handle, swparams); if (err < 0) { sciprintf("[SND:ALSA] Unable to determine current swparams for playback: %s\n", snd_strerror(err)); return SFX_ERROR; } err = snd_pcm_sw_params_set_start_threshold(handle, swparams, buffer_size); if (err < 0) { sciprintf("[SND:ALSA] Unable to set start threshold mode for playback: %s\n", snd_strerror(err)); return SFX_ERROR; } err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_size); if (err < 0) { sciprintf("[SND:ALSA] Unable to set avail min for playback: %s\n", snd_strerror(err)); return SFX_ERROR; } err = snd_pcm_sw_params_set_xfer_align(handle, swparams, 1); if (err < 0) { sciprintf("[SND:ALSA] Unable to set transfer align for playback: %s\n", snd_strerror(err)); return SFX_ERROR; } err = snd_pcm_sw_params(handle, swparams); if (err < 0) { sciprintf("[SND:ALSA] Unable to set sw params for playback: %s\n", snd_strerror(err)); return SFX_ERROR; } self->buf_size = buffer_size; self->conf.rate = rate; self->conf.stereo = channels > 1; self->conf.format = SFX_PCM_FORMAT_S16_NATIVE; frame_size = SFX_PCM_FRAME_SIZE(self->conf); sfx_audbuf_init(&audio_buffer, self->conf); if (pthread_mutex_init(&mutex, NULL) != 0) { sciprintf("[SND:ALSA] Failed to create mutex\n"); return SFX_ERROR; } run_thread = 1; if (pthread_create(&thread, NULL, alsa_thread, self) != 0) { sciprintf("[SND:ALSA] Failed to create thread\n"); return SFX_ERROR; } return SFX_OK; }
static void mix_subscribe(sfx_pcm_mixer_t *self, sfx_pcm_feed_t *feed) { sfx_pcm_feed_state_t *fs; ACQUIRE_LOCK(); if (!self->feeds) { self->feeds_allocd = 2; self->feeds = (sfx_pcm_feed_state_t*)sci_malloc(sizeof(sfx_pcm_feed_state_t) * self->feeds_allocd); } else if (self->feeds_allocd == self->feeds_nr) { self->feeds_allocd += 2; self->feeds = (sfx_pcm_feed_state_t*)sci_realloc(self->feeds, sizeof(sfx_pcm_feed_state_t) * self->feeds_allocd); } fs = self->feeds + self->feeds_nr++; fs->feed = feed; feed->frame_size = SFX_PCM_FRAME_SIZE(feed->conf); /* fs->buf_size = (self->dev->buf_size * (feed->conf.rate + self->dev->conf.rate - 1)) / self->dev->conf.rate; */ /* For the sake of people without 64 bit CPUs: */ fs->buf_size = 2 + /* Additional safety */ (self->dev->buf_size * (1 + (feed->conf.rate / self->dev->conf.rate))); fprintf(stderr, " ---> %d/%d/%d/%d = %d\n", self->dev->buf_size, feed->conf.rate, self->dev->conf.rate, feed->frame_size, fs->buf_size); fs->buf = (byte*)sci_malloc(fs->buf_size * feed->frame_size); fprintf(stderr, " ---> --> %d for %p at %p\n", fs->buf_size * feed->frame_size, (void *)fs, (void *)fs->buf); {int i; for (i = 0; i < fs->buf_size * feed->frame_size; i++) fs->buf[i] = 0xa5; } fs->scount = urat(0, 1); fs->spd = urat(feed->conf.rate, self->dev->conf.rate); fs->scount.den = fs->spd.den; fs->ch_old.left = 0; fs->ch_old.right = 0; fs->ch_new.left = 0; fs->ch_new.right = 0; fs->mode = SFX_PCM_FEED_MODE_ALIVE; /* If the feed can't provide us with timestamps, we don't need to wait for it to do so */ fs->pending_review = (feed->get_timestamp)? 1 : 0; fs->frame_bufstart = 0; #ifdef DEBUG sciprintf("[soft-mixer] Subscribed %s-%x (%d Hz, %d/%x) at %d+%d/%d, buffer size %d\n", feed->debug_name, feed->debug_nr, feed->conf.rate, feed->conf.stereo, feed->conf.format, fs->spd.val, fs->spd.nom, fs->spd.den, fs->buf_size); #endif RELEASE_LOCK(); }
static void _scir_load_resource(resource_mgr_t *mgr, resource_t *res, int protect) { char *cwd = sci_getcwd(); char filename[14]; int fh; resource_t backup; memcpy(&backup, res, sizeof(resource_t)); /* Enter resource directory */ chdir(mgr->resource_path); /* First try lower-case name */ if (res->file == SCI_RESOURCE_FILE_PATCH) { if (!patch_sprintfers[mgr->sci_version]) { sciprintf("Resource manager's SCI version (%d) has no patch file name printers -> internal error!\n", mgr->sci_version); exit(1); } /* Get patch file name */ patch_sprintfers[mgr->sci_version](filename, res); } else sprintf(filename, "resource.%03i", res->file); fh = open(filename, O_RDONLY | O_BINARY); if (!IS_VALID_FD(fh)) { char *raiser = filename; while (*raiser) { *raiser = toupper(*raiser); /* Uppercasify */ ++raiser; } fh = sci_open(filename, O_RDONLY|O_BINARY); } /* Try case-insensitively name */ if (!IS_VALID_FD(fh)) { sciprintf("Failed to open %s/%s!\n", mgr->resource_path, filename); res->data = NULL; res->status = SCI_STATUS_NOMALLOC; res->size = 0; chdir(cwd); free(cwd); return; } lseek(fh, res->file_offset, SEEK_SET); if (res->file == SCI_RESOURCE_FILE_PATCH) _scir_load_from_patch_file(fh, res, filename); else if (!decompressors[mgr->sci_version]) { /* Check whether we support this at all */ sciprintf("Resource manager's SCI version (%d) is invalid!\n", mgr->sci_version); exit(1); } else { int error = /* Decompress from regular resource file */ decompressors[mgr->sci_version](res, fh, mgr->sci_version); if (error) { sciprintf("Error %d occured while reading %s.%03d" " from resource file: %s\n", error, sci_resource_types[res->type], res->number, sci_error_types[error]); if (protect) memcpy(res, &backup, sizeof(resource_t)); res->data = NULL; res->status = SCI_STATUS_NOMALLOC; res->size = 0; chdir(cwd); free(cwd); return; } } close(fh); chdir(cwd); free(cwd); }
resource_mgr_t * scir_new_resource_manager(char *dir, int version, char allow_patches, int max_memory) { int resource_error = 0; resource_mgr_t *mgr = (resource_mgr_t*)sci_malloc(sizeof(resource_mgr_t)); char *caller_cwd = sci_getcwd(); int resmap_version = version; if (chdir(dir)) { sciprintf("Resmgr: Directory '%s' is invalid!\n", dir); free(caller_cwd); return NULL; } mgr->max_memory = max_memory; mgr->memory_locked = 0; mgr->memory_lru = 0; mgr->resource_path = dir; mgr->resources = NULL; if (version <= SCI_VERSION_01_VGA_ODD /* || version == SCI_VERSION_AUTODETECT -- subsumed by the above line */) { resource_error = sci0_read_resource_map(dir, &mgr->resources, &mgr->resources_nr, &resmap_version); if (resource_error >= SCI_ERROR_CRITICAL) { sciprintf("Resmgr: Error while loading resource map: %s\n", sci_error_types[resource_error]); if (resource_error == SCI_ERROR_RESMAP_NOT_FOUND) sciprintf("Running SCI games without a resource map is not supported ATM\n"); sci_free(mgr); chdir(caller_cwd); free(caller_cwd); return NULL; } if (resource_error == SCI_ERROR_RESMAP_NOT_FOUND) { /* fixme: Try reading w/o resource.map */ resource_error = SCI_ERROR_NO_RESOURCE_FILES_FOUND; } if (resource_error == SCI_ERROR_NO_RESOURCE_FILES_FOUND) { /* Initialize empty resource manager */ _scir_init_trivial(mgr); resource_error = 0; } } if ((version == SCI_VERSION_1_EARLY)|| (version == SCI_VERSION_1_LATE)|| (version == SCI_VERSION_1_1)|| ((resmap_version == SCI_VERSION_AUTODETECT)&&(version == SCI_VERSION_AUTODETECT))) { resource_error = sci1_read_resource_map(dir, &mgr->resources, &mgr->resources_nr, &resmap_version); if (resource_error >= SCI_ERROR_CRITICAL) { sciprintf("Resmgr: Error while loading resource map: %s\n", sci_error_types[resource_error]); if (resource_error == SCI_ERROR_RESMAP_NOT_FOUND) sciprintf("Running SCI games without a resource map is not supported ATM\n"); sci_free(mgr); chdir(caller_cwd); free(caller_cwd); return NULL; } if (resource_error == SCI_ERROR_RESMAP_NOT_FOUND) { /* fixme: Try reading w/o resource.map */ resource_error = SCI_ERROR_NO_RESOURCE_FILES_FOUND; } if (resource_error == SCI_ERROR_NO_RESOURCE_FILES_FOUND) { /* Initialize empty resource manager */ _scir_init_trivial(mgr); resource_error = 0; } resmap_version = SCI_VERSION_1; } if (!mgr->resources || !mgr->resources_nr) { if (mgr->resources) { free(mgr->resources); mgr->resources = NULL; } sciprintf("Resmgr: Could not retreive a resource list!\n"); sci_free(mgr); chdir(caller_cwd); free(caller_cwd); return NULL; } mgr->lru_first = NULL; mgr->lru_last = NULL; mgr->allow_patches = allow_patches; qsort(mgr->resources, mgr->resources_nr, sizeof(resource_t), resourcecmp); /* Sort resources */ if (version == SCI_VERSION_AUTODETECT) switch (resmap_version) { case SCI_VERSION_0: if (scir_test_resource(mgr, sci_vocab, VOCAB_RESOURCE_SCI0_MAIN_VOCAB)) { version = sci_test_view_type(mgr); if (version == SCI_VERSION_01_VGA) { sciprintf("Resmgr: Detected KQ5 or similar\n"); } else { sciprintf("Resmgr: Detected SCI0\n"); version = SCI_VERSION_0; } } else if (scir_test_resource(mgr, sci_vocab, VOCAB_RESOURCE_SCI1_MAIN_VOCAB)) { version = sci_test_view_type(mgr); if (version == SCI_VERSION_01_VGA) { sciprintf("Resmgr: Detected KQ5 or similar\n"); } else { if (scir_test_resource(mgr, sci_vocab, 912)) { sciprintf("Resmgr: Running KQ1 or similar, using SCI0 resource encoding\n"); version = SCI_VERSION_0; } else { version = SCI_VERSION_01; sciprintf("Resmgr: Detected SCI01\n"); } } } else { version = sci_test_view_type(mgr); if (version == SCI_VERSION_01_VGA) { sciprintf("Resmgr: Detected KQ5 or similar\n"); } else { sciprintf("Resmgr: Warning: Could not find vocabulary; assuming SCI0 w/o parser\n"); version = SCI_VERSION_0; } } break; case SCI_VERSION_01_VGA_ODD: version = resmap_version; sciprintf("Resmgr: Detected Jones/CD or similar\n"); break; case SCI_VERSION_1: { resource_t *res = scir_test_resource(mgr, sci_script, 0); mgr->sci_version = version = SCI_VERSION_1_EARLY; _scir_load_resource(mgr, res, 1); if (res->status == SCI_STATUS_NOMALLOC) mgr->sci_version = version = SCI_VERSION_1_LATE; /* No need to handle SCI 1.1 here - it was done in resource_map.c */ break; } default: sciprintf("Resmgr: Warning: While autodetecting: Couldn't" " determine SCI version!\n"); } if (!resource_error) { if (version <= SCI_VERSION_01) sci0_read_resource_patches(dir, &mgr->resources, &mgr->resources_nr); else sci1_read_resource_patches(dir, &mgr->resources, &mgr->resources_nr); qsort(mgr->resources, mgr->resources_nr, sizeof(resource_t), resourcecmp); /* Sort resources */ } mgr->sci_version = version; chdir(caller_cwd); free(caller_cwd); return mgr; }