Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/lib/customize/pref.prf b/lib/customize/pref.prf
- index d6e32b2..0c6c082 100644
- --- a/lib/customize/pref.prf
- +++ b/lib/customize/pref.prf
- @@ -349,6 +349,9 @@ keymap-input:1:^C
- # Message colors
- %:message.prf
- +# Message sounds
- +%:sound.prf
- +
- ##### System Specific Subfiles #####
- ?:[EQU $SYS gcu]
- diff --git a/lib/customize/sound.prf b/lib/customize/sound.prf
- new file mode 100644
- index 0000000..3417bb3
- --- /dev/null
- +++ b/lib/customize/sound.prf
- @@ -0,0 +1,513 @@
- +# sound.cfg
- +#
- +# Configuration file for the Angband sound events
- +#
- +# The format is:
- +# <event name>:<sample-names seperated by spaces>
- +#
- +# Example:
- +# hit:hit hit1
- +#
- +
- +#
- +# This is the Dubtrain Angband Sound config list, v.3.1.0 - February 24th, 2009
- +#
- +# Licensed under a Creative Commons non-commercial agreement
- +#
- +# Inspired by the original Craig's Angband Sound Patch.
- +#
- +# But with all new sounds.
- +#
- +# contact angband@dubtrain.com
- +#
- +# download zipped archive at www.dubtrain.com/angband
- +#
- +#
- +
- +
- +#
- +# Ambient sounds
- +#
- +
- +# Town during the day.
- +sound:AMBIENT_DAY:amb_thunder_rain
- +
- +# Town during the night.
- +sound:AMBIENT_NITE:amb_guitar_chord amb_thunder_roll
- +
- +# Dungeon levels 1-20 (50'-1000')
- +sound:AMBIENT_DNG1:amb_door_iron amb_bell_metal1
- +
- +# Dungeon levels 21-40 (1050'-2000')
- +sound:AMBIENT_DNG2:amb_bell_tibet1 amb_bell_metal2 amb_gong_strike
- +
- +# Dungeon levels 41-60 (2050'-3000')
- +sound:AMBIENT_DNG3:amb_bell_tibet2 amb_dungeon_echo amb_pulse_low
- +
- +# Dungeon levels 61-80 (3050'-4000')
- +sound:AMBIENT_DNG4:amb_bell_tibet3 amb_dungeon_echowet amb_gong_undertone
- +
- +# Dungeon levels 81 and beyond (4050'-)
- +sound:AMBIENT_DNG5:amb_door_doom amb_gong_chinese amb_gong_low
- +
- +#
- +# Store sounds
- +#
- +
- +# The shopkeep bought a worthless item.
- +sound:STORE1:sto_man_hey
- +
- +# The shopkeep paid too much for an item.
- +sound:STORE2:id_bad_dang
- +
- +# The shopkeep got away with a good bargain.
- +sound:STORE3:sto_man_haha
- +
- +# The shopkeep got away with a great bargain.
- +sound:STORE4:sto_man_whoohaha
- +
- +# You make a normal transaction (buying or selling).
- +sound:STORE5:sto_coins_countertop sto_bell_register1 sto_bell_register2
- +
- +# You enter a store.
- +sound:STORE_ENTER:sto_bell_desk sto_bell_ding sto_bell_dingaling sto_bell_jingles sto_bell_ringing sto_bell_shop
- +
- +# You enter your home.
- +STORE_HOME:plm_door_entrance
- +
- +# You leave a store.
- +STORE_LEAVE:plm_door_bolt
- +
- +#
- +# Player sounds - combat
- +#
- +
- +# You succeed in a melee attack against a monster.
- +sound:HIT:plc_hit_hay plc_hit_body
- +
- +# It was a good hit!
- +MDG_HIT_GOOD:plc_hit_anvil
- +
- +# It was a great hit!
- +sound:HIT_GREAT:plc_hit_groan
- +
- +# It was a superb hit!
- +sound:HIT_SUPERB:plc_hit_grunt
- +
- +# It was a *GREAT* hit!
- +sound:HIT_HI_GREAT:plc_hit_grunt2
- +
- +# It was a *SUPERB* hit!
- +sound:HIT_HI_SUPERB:plc_hit_anvil2
- +
- +# You miss a melee attack against a monster.
- +sound:MISS:plc_miss_arrow2
- +
- +# You fire a missile.
- +sound:SHOOT:plc_miss_arrow
- +
- +# You hit something with a missile.
- +sound:SHOOT_HIT:plc_hit_arrow
- +
- +# You receive a hitpoint warning.
- +sound:HITPOINT_WARN:plc_bell_warn
- +
- +# You die.
- +sound:DEATH:plc_die_laugh
- +
- +#
- +# Player sounds - status changes
- +#
- +
- +# You become blind.
- +sound:BLIND:pls_tone_conk
- +
- +# You become confused.
- +sound:CONFUSED:pls_man_ugh
- +
- +# You become poisoned.
- +sound:POISONED:pls_tone_guiro
- +
- +# You become afraid.
- +sound:AFRAID:pls_man_yell
- +
- +# You become paralyzed.
- +sound:PARALYZED:pls_man_gulp_new
- +
- +# You feel drugged (chaos effects).
- +sound:DRUGGED:pls_breathe_in
- +
- +# You become slower.
- +sound:SLOW:pls_man_sigh
- +
- +# You become stunned.
- +sound:STUN:pls_bell_mute
- +
- +# You suffer a cut.
- +sound:CUT:pls_man_argoh
- +
- +# A stat is drained
- +sound:DRAIN_STAT:pls_tone_headstock
- +
- +# You recover from a condition (blind, confused, etc.)
- +sound:RECOVER:pls_bell_chime_new
- +
- +# You become faster.
- +sound:SPEED:pls_bell_sustain
- +
- +# You attain a mystic shield.
- +sound:SHIELD:pls_bell_bowl
- +
- +# You become blessed.
- +sound:BLESSED:sum_angel_song
- +
- +# You feel heroic.
- +sound:HERO:pls_tone_goblet
- +
- +# You are bold.
- +sound:BOLD:pls_bell_hibell_soft
- +
- +# You become berserk.
- +sound:BERSERK:pls_man_scream2
- +
- +# You feel protected from evil.
- +sound:PROT_EVIL:pls_bell_glass
- +
- +# You feel invulnerable. (does any item/spell do this anymore?)
- +sound:INVULN:pls_tone_blurk
- +
- +# You can see invisible things.
- +sound:SEE_INVIS:pls_tone_clave6
- +
- +# You can see the infrared spectrum
- +sound:INFRARED:pls_tone_clavelo8
- +
- +# You become resistant to acid.
- +sound:RES_ACID:pls_man_sniff
- +
- +# You become resistant to electricity.
- +sound:RES_ELEC:pls_tone_elec
- +
- +# You become resistant to fire.
- +sound:RES_FIRE:pls_tone_scrape
- +
- +# You become resistant to cold.
- +sound:RES_COLD:pls_tone_stick
- +
- +# You become resistant to poison.
- +sound:RES_POIS:pls_man_spit
- +
- +# You become hungry.
- +sound:HUNGRY:pls_man_sob
- +
- +#
- +# Player sounds - misc.
- +#
- +
- +# You pick up money worth less than 200 au.
- +sound:MONEY1:plm_coins_light plm_coins_shake
- +
- +# You pick up money worth between 200 and 600 au.
- +sound:MONEY2:plm_chain_light plm_coins_pour
- +
- +# You pick up money worth 600 au or more.
- +sound:MONEY3:plm_coins_dump
- +
- +# You (or a monster) drop something on the ground.
- +sound:DROP:plm_drop_boot
- +
- +# You gain (or regain) a level.
- +sound:LEVEL:plm_levelup
- +
- +# You successfully study a spell or prayer.
- +sound:STUDY:plm_book_pageturn
- +
- +# You teleport or phase door.
- +sound:TELEPORT:plm_chimes_jangle
- +
- +# You quaff a potion.
- +sound:QUAFF:plm_bottle_clinks plm_cork_pop plm_cork_squeak
- +
- +# You zap a rod.
- +sound:ZAP_ROD:plm_zap_rod
- +
- +# You take a step. (unimplemented)
- +# walk:
- +
- +# You teleport someone else away.
- +sound:TPOTHER:plm_chimes_jangle
- +
- +# You bump into a wall or door.
- +sound:HITWALL:plm_wood_thud
- +
- +# You eat something.
- +sound:EAT:plm_eat_bite
- +
- +# You successfully dig through something.
- +sound:DIG:plm_metal_clank
- +
- +# You open a door.
- +sound:OPENDOOR:plm_door_bolt plm_door_creak plm_door_dungeon plm_door_entrance plm_door_open plm_door_opening plm_door_rusty plm_door_squeaky
- +
- +# You shut a door.
- +sound:SHUTDOOR:plm_bang_dumpster plm_cabinet_shut plm_close_hatch plm_door_creakshut plm_door_latch plm_door_shut plm_door_slam
- +
- +# You teleport from a level (including via recall).
- +sound:TPLEVEL:sum_bell_crystal
- +
- +# Default "bell" sound for system messages.
- +sound:BELL:plm_jar_ding
- +
- +# You try to open something that's not a door.
- +sound:NOTHING_TO_OPEN:plm_click_switch2 plm_door_knob
- +
- +# You fail to pick a lock.
- +sound:LOCKPICK_FAIL:plm_click_dry plm_click_switch plm_click_wood plm_door_echolock plm_door_wooden
- +
- +# You pick a lock.
- +sound:LOCKPICK:plm_break_wood plm_cabinet_open plm_chest_unlatch plm_lock_case plm_lock_distant plm_open_case
- +
- +# You disarm a trap.
- +sound:DISARM:plm_bang_ceramic plm_chest_latch plm_click_switch3
- +
- +# You go up stairs.
- +sound:STAIRS_UP:plm_floor_creak2
- +
- +# You go down stairs.
- +sound:STAIRS_DOWN:plm_floor_creak
- +
- +# You activate an artifact.
- +sound:ACT_ARTIFACT:plm_aim_wand
- +
- +# You use a staff.
- +sound:USE_STAFF:plm_use_staff
- +
- +# An object is destroyed.
- +sound:DESTROY:plm_bang_metal plm_break_canister plm_break_glass plm_break_glass2 plm_break_plates plm_break_shatter plm_break_smash plm_glass_breaking plm_glass_break plm_glass_smashing
- +
- +# You wield or take off something.
- +sound:WIELD:plm_metal_sharpen
- +
- +# You take something in or out of your quiver.
- +sound:QUIVER:plc_miss_swish
- +
- +# You wield a cursed item.
- +sound:CURSED:pls_man_oooh
- +
- +# You notice something (generic notice)
- +sound:NOTICE:id_bad_hmm
- +
- +# You notice something about your equipment or inventory.
- +sound:PSEUDOID:id_good_hmm
- +
- +# You successfully cast a spell.
- +sound:SPELL:plm_spell1 plm_spell2 plm_spell3
- +
- +# You successfully pray a prayer.
- +sound:PRAYER:sum_angel_song
- +
- +#
- +# Monster Sounds - combat
- +#
- +
- +# A monster flees in terror.
- +sound:FLEE:mco_creature_yelp
- +
- +# A monster is killed.
- +sound:KILL:mco_howl_croak mco_howl_deep mco_howl_distressed mco_howl_high mco_howl_long
- +
- +# A unique is killed.
- +sound:KILL_UNIQUE:sum_ghost_wail
- +
- +# Morgoth, Lord of Darkness is killed.
- +sound:KILL_KING:amb_guitar_chord
- +
- +# Attack - hit
- +sound:MON_HIT:mco_hit_whip
- +
- +# Attack - touch
- +sound:MON_TOUCH:mco_click_vibra
- +
- +# Attack - punch
- +sound:MON_PUNCH:mco_squish_snap
- +
- +# Attack - kick
- +sound:MON_KICK:mco_rubber_thud
- +
- +# Attack - claw
- +sound:MON_CLAW:mco_ceramic_trill mco_scurry_dry
- +
- +# Attack - bite
- +sound:MON_BITE:mco_snarl_short mco_bite_soft mco_bite_munch mco_bite_long mco_bite_short mco_bite_gnash mco_bite_chomp mco_bite_regular mco_bite_small mco_bite_dainty mco_bite_hard mco_bite_chew
- +
- +# Attack - sting
- +sound:MON_STING:mco_castanet_trill mco_tube_hit
- +
- +# Attack - butt
- +sound:MON_BUTT:mco_cuica_rubbing mco_thud_crash
- +
- +# Attack - crush
- +sound:MON_CRUSH:mco_dino_low mco_squish_hit
- +
- +# Attack - engulf
- +sound:MON_ENGULF:mco_dino_talk mco_dino_yawn
- +
- +# Attack - crawl
- +sound:MON_CRAWL:mco_card_shuffle mco_shake_roll
- +
- +# Attack - drool
- +sound:MON_DROOL:mco_creature_choking mco_liquid_squirt
- +
- +# Attack - spit
- +sound:MON_SPIT:mco_attack_spray
- +
- +# Attack - gaze
- +sound:MON_GAZE:mco_thoing_backwards
- +
- +# Attack - wail
- +sound:MON_WAIL:mco_dino_low
- +
- +# Attack - release spores
- +sound:MON_SPORE:mco_dub_wobble mco_spray_long
- +
- +# Attack - beg for money
- +sound:MON_BEG:mco_man_mumble
- +
- +# Attack - insult
- +sound:MON_INSULT:mco_strange_thwoink
- +
- +# Attack - moan
- +sound:MON_MOAN:mco_strange_music
- +
- +# Attack - shriek
- +sound:SHRIEK:mco_mouse_squeaks
- +
- +# Spell - create traps
- +sound:CREATE_TRAP:mco_thoing_deep
- +
- +# Spell - cause fear
- +sound:CAST_FEAR:mco_creature_groan mco_dino_slur
- +
- +# Multiply (breed explosively)
- +sound:MULTIPLY:mco_frog_trill
- +
- +#
- +# Summons
- +#
- +
- +# Summon one or more monsters.
- +sound:SUM_MONSTER:sum_chime_jangle
- +
- +# Summon angels.
- +sound:SUM_AINU:sum_angel_song
- +
- +# Summon undead.
- +sound:SUM_UNDEAD:sum_ghost_oooo
- +
- +# Summon animals.
- +sound:SUM_ANIMAL:sum_lion_growl
- +
- +# Summon spiders.
- +sound:SUM_SPIDER:sum_piano_scrape
- +
- +# Summon hounds.
- +sound:SUM_HOUND:sum_lion_growl
- +
- +# Summon hydras.
- +sound:SUM_HYDRA:sum_piano_scrape
- +
- +# Summon demons.
- +sound:SUM_DEMON:sum_ghost_wail sum_laugh_evil2
- +
- +# Summon dragon.
- +sound:SUM_DRAGON:sum_piano_scrape
- +
- +# Summon greater undead.
- +sound:SUM_HI_UNDEAD:sum_ghost_moan
- +
- +# Summon greater dragons.
- +sound:SUM_HI_DRAGON:sum_gong_temple
- +
- +# Summon greater demons.
- +sound:SUM_HI_DEMON:sum_ghost_moan
- +
- +# Summon Ringwraiths.
- +sound:SUM_WRAITH:sum_bell_hand
- +
- +# Summon uniques.
- +sound:SUM_UNIQUE:sum_bell_tone
- +
- +#
- +# Breath weapons
- +#
- +
- +# Breathe frost.
- +sound:BR_FROST:mco_attack_breath
- +
- +# Breathe electricity.
- +MST_BR_ELEC:mco_attack_breath
- +
- +# Breathe acid.
- +sound:BR_ACID:mco_attack_breath
- +
- +# Breathe gas.
- +sound:BR_GAS:mco_attack_breath
- +
- +# Breathe fire.
- +sound:BR_FIRE:mco_attack_breath
- +
- +# Breathe disenchantment.
- +sound:BR_DISEN:mco_attack_breath
- +
- +# Breathe chaos.
- +sound:BR_CHAOS:mco_attack_breath
- +
- +# Breathe shards.
- +sound:BR_SHARDS:mco_attack_breath
- +
- +# Breathe sound.
- +sound:BR_SOUND:mco_attack_breath
- +
- +# Breathe light.
- +sound:BR_LIGHT:mco_attack_breath
- +
- +# Breathe darkness.
- +sound:BR_DARK:mco_attack_breath
- +
- +# Breathe nether.
- +sound:BR_NETHER:mco_attack_breath
- +
- +# Breathe nexus.
- +sound:BR_NEXUS:mco_attack_breath
- +
- +# Breathe time.
- +sound:BR_TIME:mco_attack_breath
- +
- +# Breathe inertia.
- +sound:BR_INERTIA:mco_attack_breath
- +
- +# Breathe gravity.
- +sound:BR_GRAVITY:mco_attack_breath
- +
- +# Breathe plasma.
- +sound:BR_PLASMA:mco_attack_breath
- +
- +# Breathe force.
- +sound:BR_FORCE:mco_attack_breath
- +
- +# Breathe the elements (power dragon scale mail).
- +sound:BR_ELEMENTS:mco_attack_breath
- +
- +#
- +# Identifying Items
- +#
- +
- +# Identify a bad item (including bad ego items and artifacts).
- +sound:IDENT_BAD:id_bad_aww id_bad_dang id_bad_hmm id_bad_hmph id_bad_ohh
- +
- +# Identify a good ego item.
- +sound:IDENT_EGO:id_ego_whoa id_ego_woohoo id_ego_yeah id_ego_yeah2 id_ego_yes
- +
- +# Identify a good artifact.
- +sound:IDENT_ART:id_good_hey id_good_hey2 id_good_hmm id_good_huh id_good_ooh id_good_ooo id_good_wow
- +
- diff --git a/src/Makefile.src b/src/Makefile.src
- index 5d4a738..c4296f9 100644
- --- a/src/Makefile.src
- +++ b/src/Makefile.src
- @@ -158,6 +158,7 @@ ANGFILES = \
- score.o \
- save.o \
- savefile.o \
- + sound-core.o \
- store.o \
- target.o \
- trap.o \
- diff --git a/src/avltree.h b/src/avltree.h
- new file mode 100644
- index 0000000..f3c5977
- --- /dev/null
- +++ b/src/avltree.h
- @@ -0,0 +1,212 @@
- +/* tree.h -- AVL trees (in the spirit of BSD's 'queue.h') -*- C -*- */
- +
- +/* Copyright (c) 2005 Ian Piumarta
- + *
- + * All rights reserved.
- + *
- + * Permission is hereby granted, free of charge, to any person obtaining a copy
- + * of this software and associated documentation files (the 'Software'), to deal
- + * in the Software without restriction, including without limitation the rights
- + * to use, copy, modify, merge, publish, distribute, and/or sell copies of the
- + * Software, and to permit persons to whom the Software is furnished to do so,
- + * provided that the above copyright notice(s) and this permission notice appear
- + * in all copies of the Software and that both the above copyright notice(s) and
- + * this permission notice appear in supporting documentation.
- + *
- + * THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
- + */
- +
- +/* This file defines an AVL balanced binary tree [Georgii M. Adelson-Velskii and
- + * Evgenii M. Landis, 'An algorithm for the organization of information',
- + * Doklady Akademii Nauk SSSR, 146:263-266, 1962 (Russian). Also in Myron
- + * J. Ricci (trans.), Soviet Math, 3:1259-1263, 1962 (English)].
- + *
- + * An AVL tree is headed by pointers to the root node and to a function defining
- + * the ordering relation between nodes. Each node contains an arbitrary payload
- + * plus three fields per tree entry: the depth of the subtree for which it forms
- + * the root and two pointers to child nodes (singly-linked for minimum space, at
- + * the expense of direct access to the parent node given a pointer to one of the
- + * children). The tree is rebalanced after every insertion or removal. The
- + * tree may be traversed in two directions: forward (in-order left-to-right) and
- + * reverse (in-order, right-to-left).
- + *
- + * Because of the recursive nature of many of the operations on trees it is
- + * necessary to define a number of helper functions for each type of tree node.
- + * The macro TREE_DEFINE(node_tag, entry_name) defines these functions with
- + * unique names according to the node_tag. This macro should be invoked,
- + * thereby defining the necessary functions, once per node tag in the program.
- + *
- + * For details on the use of these macros, see the tree(3) manual page.
- + */
- +
- +#ifndef __tree_h
- +#define __tree_h
- +
- +
- +#define TREE_DELTA_MAX 1
- +
- +#define TREE_ENTRY(type) \
- + struct { \
- + struct type *avl_left; \
- + struct type *avl_right; \
- + int avl_height; \
- + }
- +
- +#define TREE_HEAD(name, type) \
- + struct name { \
- + struct type *th_root; \
- + int (*th_cmp)(struct type *lhs, struct type *rhs); \
- + }
- +
- +#define TREE_INITIALIZER(cmp) { 0, cmp }
- +
- +#define TREE_DELTA(self, field) \
- + (( (((self)->field.avl_left) ? (self)->field.avl_left->field.avl_height : 0)) \
- + - (((self)->field.avl_right) ? (self)->field.avl_right->field.avl_height : 0))
- +
- +/* Recursion prevents the following from being defined as macros. */
- +
- +#define TREE_DEFINE(node, field) \
- + \
- + struct node *TREE_BALANCE_##node##_##field(struct node *); \
- + \
- + struct node *TREE_ROTL_##node##_##field(struct node *self) \
- + { \
- + struct node *r= self->field.avl_right; \
- + self->field.avl_right= r->field.avl_left; \
- + r->field.avl_left= TREE_BALANCE_##node##_##field(self); \
- + return TREE_BALANCE_##node##_##field(r); \
- + } \
- + \
- + struct node *TREE_ROTR_##node##_##field(struct node *self) \
- + { \
- + struct node *l= self->field.avl_left; \
- + self->field.avl_left= l->field.avl_right; \
- + l->field.avl_right= TREE_BALANCE_##node##_##field(self); \
- + return TREE_BALANCE_##node##_##field(l); \
- + } \
- + \
- + struct node *TREE_BALANCE_##node##_##field(struct node *self) \
- + { \
- + int delta= TREE_DELTA(self, field); \
- + \
- + if (delta < -TREE_DELTA_MAX) \
- + { \
- + if (TREE_DELTA(self->field.avl_right, field) > 0) \
- + self->field.avl_right= TREE_ROTR_##node##_##field(self->field.avl_right); \
- + return TREE_ROTL_##node##_##field(self); \
- + } \
- + else if (delta > TREE_DELTA_MAX) \
- + { \
- + if (TREE_DELTA(self->field.avl_left, field) < 0) \
- + self->field.avl_left= TREE_ROTL_##node##_##field(self->field.avl_left); \
- + return TREE_ROTR_##node##_##field(self); \
- + } \
- + self->field.avl_height= 0; \
- + if (self->field.avl_left && (self->field.avl_left->field.avl_height > self->field.avl_height)) \
- + self->field.avl_height= self->field.avl_left->field.avl_height; \
- + if (self->field.avl_right && (self->field.avl_right->field.avl_height > self->field.avl_height)) \
- + self->field.avl_height= self->field.avl_right->field.avl_height; \
- + self->field.avl_height += 1; \
- + return self; \
- + } \
- + \
- + struct node *TREE_INSERT_##node##_##field \
- + (struct node *self, struct node *elm, int (*compare)(struct node *lhs, struct node *rhs)) \
- + { \
- + if (!self) \
- + return elm; \
- + if (compare(elm, self) < 0) \
- + self->field.avl_left= TREE_INSERT_##node##_##field(self->field.avl_left, elm, compare); \
- + else \
- + self->field.avl_right= TREE_INSERT_##node##_##field(self->field.avl_right, elm, compare); \
- + return TREE_BALANCE_##node##_##field(self); \
- + } \
- + \
- + struct node *TREE_FIND_##node##_##field \
- + (struct node *self, struct node *elm, int (*compare)(struct node *lhs, struct node *rhs)) \
- + { \
- + if (!self) \
- + return 0; \
- + if (compare(elm, self) == 0) \
- + return self; \
- + if (compare(elm, self) < 0) \
- + return TREE_FIND_##node##_##field(self->field.avl_left, elm, compare); \
- + else \
- + return TREE_FIND_##node##_##field(self->field.avl_right, elm, compare); \
- + } \
- + \
- + struct node *TREE_MOVE_RIGHT_##node##_##field(struct node *self, struct node *rhs) \
- + { \
- + if (!self) \
- + return rhs; \
- + self->field.avl_right= TREE_MOVE_RIGHT_##node##_##field(self->field.avl_right, rhs); \
- + return TREE_BALANCE_##node##_##field(self); \
- + } \
- + \
- + struct node *TREE_REMOVE_##node##_##field \
- + (struct node *self, struct node *elm, int (*compare)(struct node *lhs, struct node *rhs)) \
- + { \
- + if (!self) return 0; \
- + \
- + if (compare(elm, self) == 0) \
- + { \
- + struct node *tmp= TREE_MOVE_RIGHT_##node##_##field(self->field.avl_left, self->field.avl_right); \
- + self->field.avl_left= 0; \
- + self->field.avl_right= 0; \
- + return tmp; \
- + } \
- + if (compare(elm, self) < 0) \
- + self->field.avl_left= TREE_REMOVE_##node##_##field(self->field.avl_left, elm, compare); \
- + else \
- + self->field.avl_right= TREE_REMOVE_##node##_##field(self->field.avl_right, elm, compare); \
- + return TREE_BALANCE_##node##_##field(self); \
- + } \
- + \
- + void TREE_FORWARD_APPLY_ALL_##node##_##field \
- + (struct node *self, void (*function)(struct node *node, void *data), void *data) \
- + { \
- + if (self) \
- + { \
- + TREE_FORWARD_APPLY_ALL_##node##_##field(self->field.avl_left, function, data); \
- + function(self, data); \
- + TREE_FORWARD_APPLY_ALL_##node##_##field(self->field.avl_right, function, data); \
- + } \
- + } \
- + \
- + void TREE_REVERSE_APPLY_ALL_##node##_##field \
- + (struct node *self, void (*function)(struct node *node, void *data), void *data) \
- + { \
- + if (self) \
- + { \
- + TREE_REVERSE_APPLY_ALL_##node##_##field(self->field.avl_right, function, data); \
- + function(self, data); \
- + TREE_REVERSE_APPLY_ALL_##node##_##field(self->field.avl_left, function, data); \
- + } \
- + }
- +
- +#define TREE_INSERT(head, node, field, elm) \
- + ((head)->th_root= TREE_INSERT_##node##_##field((head)->th_root, (elm), (head)->th_cmp))
- +
- +#define TREE_FIND(head, node, field, elm) \
- + (TREE_FIND_##node##_##field((head)->th_root, (elm), (head)->th_cmp))
- +
- +#define TREE_REMOVE(head, node, field, elm) \
- + ((head)->th_root= TREE_REMOVE_##node##_##field((head)->th_root, (elm), (head)->th_cmp))
- +
- +#define TREE_DEPTH(head, field) \
- + ((head)->th_root->field.avl_height)
- +
- +#define TREE_FORWARD_APPLY(head, node, field, function, data) \
- + TREE_FORWARD_APPLY_ALL_##node##_##field((head)->th_root, function, data)
- +
- +#define TREE_REVERSE_APPLY(head, node, field, function, data) \
- + TREE_REVERSE_APPLY_ALL_##node##_##field((head)->th_root, function, data)
- +
- +#define TREE_INIT(head, cmp) do { \
- + (head)->th_root= 0; \
- + (head)->th_cmp= (cmp); \
- + } while (0)
- +
- +
- +#endif /* __tree_h */
- diff --git a/src/main.c b/src/main.c
- index 6717e0e..3392129 100644
- --- a/src/main.c
- +++ b/src/main.c
- @@ -43,6 +43,8 @@
- #include "main.h"
- +#include "sound.h"
- +
- /**
- * List of the available modules in the order they are tried.
- */
- @@ -69,22 +71,6 @@ static const struct module modules[] =
- #endif /* USE_STATS */
- };
- -static int init_sound_dummy(int argc, char *argv[]) {
- - return 0;
- -}
- -
- -/**
- - * List of sound modules in the order they should be tried.
- - */
- -static const struct module sound_modules[] =
- -{
- -#ifdef SOUND_SDL
- - { "sdl", "SDL_mixer sound module", init_sound_sdl },
- -#endif /* SOUND_SDL */
- -
- - { "none", "No sound", init_sound_dummy },
- -};
- -
- /**
- * A hook for "quit()".
- *
- @@ -467,9 +453,7 @@ int main(int argc, char *argv[])
- }
- puts(" Multiple -d options are allowed.");
- puts(" -s<mod> Use sound module <sys>:");
- - for (i = 0; i < (int)N_ELEMENTS(sound_modules); i++)
- - printf(" %s %s\n", sound_modules[i].name,
- - sound_modules[i].help);
- + print_sound_help();
- puts(" -m<sys> Use module <sys>, where <sys> can be:");
- /* Print the name and help for each available module */
- @@ -532,12 +516,6 @@ int main(int argc, char *argv[])
- #endif /* UNIX */
- - /* Try the modules in the order specified by sound_modules[] */
- - for (i = 0; i < (int)N_ELEMENTS(sound_modules); i++)
- - if (!soundstr || streq(soundstr, sound_modules[i].name))
- - if (0 == sound_modules[i].init(argc, argv))
- - break;
- -
- /* Catch nasty signals */
- signals_init();
- @@ -549,6 +527,16 @@ int main(int argc, char *argv[])
- init_angband();
- textui_init();
- + /*
- + * We needed to wait until the prefs files where loaded before we
- + * initialise the sound sub-system because some fool moved the
- + * sound config from a random 'config' file to a properly formatted
- + * 'pref' file and stuck it in the 'customize' directory so it could
- + * be chain-loaded from pref.prf
- + */
- + if (0 != init_sound(soundstr, argc, argv))
- + plog("Failed to initialize sound!"); /* Non-fatal */
- +
- /* Wait for response */
- pause_line(Term);
- diff --git a/src/main.h b/src/main.h
- index 70c11e0..39d442b 100644
- --- a/src/main.h
- +++ b/src/main.h
- @@ -23,9 +23,6 @@
- #include "angband.h"
- #include "ui-term.h"
- -extern errr init_sound_sdl(int argc, char **argv);
- -
- -
- extern errr init_lfb(int argc, char **argv);
- extern errr init_x11(int argc, char **argv);
- extern errr init_xpj(int argc, char **argv);
- diff --git a/src/message.h b/src/message.h
- index d08a8e6..1474fa3 100644
- --- a/src/message.h
- +++ b/src/message.h
- @@ -34,7 +34,7 @@ enum {
- /* Functions */
- void messages_init(void);
- void messages_free(void);
- -u16b messages_num(void);
- +u16b messages_num(void);
- void message_add(const char *str, u16b type);
- const char *message_str(u16b age);
- u16b message_count(u16b age);
- diff --git a/src/snd-sdl.c b/src/snd-sdl.c
- index afce53f..75b0ca8 100644
- --- a/src/snd-sdl.c
- +++ b/src/snd-sdl.c
- @@ -19,86 +19,52 @@
- */
- #include "angband.h"
- #include "init.h"
- -
- +#include "sound.h"
- +
- #ifdef SOUND_SDL
- #include "SDL.h"
- #include "SDL_mixer.h"
- -
- -/**
- - * Don't cache audio
- - */
- -static bool no_cache_audio = false;
- -
- -/**
- - * Using mp3s
- - */
- -static bool use_mp3 = false;
- -
- -/**
- - * Arbitary limit on number of samples per event
- - */
- -#define MAX_SAMPLES 16
- +typedef enum sdl_sample_type {
- + SDL_CHUNK,
- + SDL_MUSIC,
- + SDL_NULL
- +} sdl_sample_type;
- /**
- * Struct representing all data about an event sample
- */
- typedef struct
- {
- - int num; /* Number of samples for this event */
- - Mix_Chunk *wavs[MAX_SAMPLES]; /* Sample array */
- - Mix_Music *mp3s[MAX_SAMPLES]; /* Sample array */
- - char *paths[MAX_SAMPLES]; /* Relative pathnames for samples */
- -} sample_list;
- -
- -
- -/**
- - * Just need an array of SampInfos
- - */
- -static sample_list samples[MSG_MAX];
- -
- -
- -/**
- - * Shut down the sound system and free resources.
- - */
- -static void close_audio(void)
- -{
- - size_t i;
- - int j;
- -
- - /* Free all the sample data*/
- - for (i = 0; i < MSG_MAX; i++) {
- - sample_list *smp = &samples[i];
- -
- - /* Nuke all samples */
- - for (j = 0; j < smp->num; j++) {
- - if (use_mp3)
- - Mix_FreeMusic(smp->mp3s[j]);
- - else
- - Mix_FreeChunk(smp->wavs[j]);
- - string_free(smp->paths[j]);
- - }
- - }
- -
- - /* Close the audio */
- - Mix_CloseAudio();
- -
- - /* XXX This may conflict with the SDL port */
- - SDL_Quit();
- -}
- -
- -
- + union {
- + Mix_Chunk *chunk; /* Sample in WAVE format */
- + Mix_Music *music; /* Sample in MP3 format */
- + };
- +
- + sdl_sample_type sample_type;
- + char *path; /* Relative pathnames for samples */
- +} sdl_sample;
- +
- +typedef struct sdl_file_type {
- + const char *extension;
- + sdl_sample_type type;
- +} sdl_file_type_t;
- +
- +/* List of supported file types */
- +static const sdl_file_type_t supported_file_types[] = { {".mp3", SDL_MUSIC},
- + {".ogg", SDL_CHUNK},
- + {"", SDL_NULL} };
- /**
- * Initialise SDL and open the mixer
- */
- -static bool open_audio(void)
- +static bool open_audio_sdl(int argc, char **argv)
- {
- int audio_rate;
- Uint16 audio_format;
- int audio_channels;
- -
- +
- /* Initialize variables */
- audio_rate = 22050;
- audio_format = AUDIO_S16;
- @@ -106,13 +72,13 @@ static bool open_audio(void)
- /* Initialize the SDL library */
- if (SDL_Init(SDL_INIT_AUDIO) < 0) {
- - plog_fmt("Couldn't initialize SDL: %s", SDL_GetError());
- + plog_fmt("SDL: Couldn't initialize SDL: %s", SDL_GetError());
- return false;
- }
- /* Try to open the audio */
- if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, 4096) < 0) {
- - plog_fmt("Couldn't open mixer: %s", SDL_GetError());
- + plog_fmt("SDL: Couldn't open mixer: %s", SDL_GetError());
- return false;
- }
- @@ -120,228 +86,191 @@ static bool open_audio(void)
- return true;
- }
- -
- -
- -/**
- - * Read sound.cfg and map events to sounds; then load all the sounds into
- - * memory to avoid I/O latency later.
- - */
- -static bool sound_sdl_init(bool no_cache)
- +static bool load_sample_sdl(sdl_sample *sample)
- {
- - char path[2048];
- - char buffer[2048];
- - ang_file *fff;
- + switch (sample->sample_type) {
- + case SDL_CHUNK:
- + sample->chunk = Mix_LoadWAV(sample->path);
- +
- + if (!sample->chunk) {
- + plog_fmt("SDL: Failed to load %s (%s: %s)", sample->path, SDL_GetError(), strerror(errno));
- + }
- + else {
- + plog_fmt("SDL: Successfully loaded %s", sample->path);
- + return true;
- + }
- + break;
- - /* Initialise the mixer */
- - if (!open_audio())
- - return false;
- + case SDL_MUSIC:
- + sample->music = Mix_LoadMUS(sample->path);
- + if (!sample->music) {
- + plog_fmt("SDL: Failed to load %s (%s: %s)", sample->path, SDL_GetError(), strerror(errno));
- + } else {
- + plog_fmt("SDL: Successfully loaded %s", sample->path);
- + return true;
- + }
- - /* Find and open the config file */
- - path_build(path, sizeof(path), ANGBAND_DIR_SOUNDS, "sound.cfg");
- - fff = file_open(path, MODE_READ, -1);
- + break;
- - /* Handle errors */
- - if (!fff) {
- - plog_fmt("Failed to open sound config (%s):\n %s",
- - path, strerror(errno));
- - return false;
- + default:
- + plog_fmt("SDL: Oops - Unsupported file type");
- + break;
- }
- - /* Parse the file */
- - /* Lines are always of the form "name = sample [sample ...]" */
- - while (file_getl(fff, buffer, sizeof(buffer))) {
- - char *msg_name;
- - char *sample_list;
- - char *search;
- - char *cur_token;
- - char *next_token;
- - int event;
- -
- - /* Skip anything not beginning with an alphabetic character */
- - if (!buffer[0] || !isalpha((unsigned char)buffer[0])) continue;
- -
- - /* Split the line into two: message name, and the rest */
- - search = strchr(buffer, ' ');
- - sample_list = strchr(search + 1, ' ');
- - if (!search) continue;
- - if (!sample_list) continue;
- -
- - /* Set the message name, and terminate at first space */
- - msg_name = buffer;
- - search[0] = '\0';
- -
- -
- - /* Make sure this is a valid event name */
- - event = message_lookup_by_sound_name(msg_name);
- - if (event < 0) continue;
- -
- - /* Advance the sample list pointer so it's at the beginning of text */
- - sample_list++;
- - if (!sample_list[0]) continue;
- -
- - /* Terminate the current token */
- - cur_token = sample_list;
- - search = strchr(cur_token, ' ');
- - if (search) {
- - search[0] = '\0';
- - next_token = search + 1;
- - } else {
- - next_token = NULL;
- - }
- + return false;
- +}
- - /*
- - * Now we find all the sample names and add them one by one
- - */
- - while (cur_token) {
- - int num = samples[event].num;
- - bool got_file_type = false;
- -
- - /* Don't allow too many samples */
- - if (num >= MAX_SAMPLES) break;
- -
- - /* Build the path to the sample */
- - path_build(path, sizeof(path), ANGBAND_DIR_SOUNDS, cur_token);
- - if (!file_exists(path)) goto next_token;
- -
- - if (!got_file_type) {
- - if (streq(path + strlen(path) - 3, "mp3")) {
- - use_mp3 = true;
- - got_file_type = true;
- - }
- - }
- +static bool load_sound_sdl(const char *sound_name, void *data)
- +{
- + char path[2048];
- + char *filename_buf;
- + size_t filename_buf_size;
- + sdl_sample *sample = NULL;
- + int i = 0;
- + bool loaded = false;
- +
- + /* Build the path to the sample */
- + path_build(path, sizeof(path), ANGBAND_DIR_SOUNDS, sound_name);
- +
- + /*
- + * Create a buffer to store the filename plus three character
- + * extension (5 = '.' + 3 character extension + '\0'
- + */
- + filename_buf_size = strlen(path) + 5;
- + filename_buf = mem_alloc(filename_buf_size);
- +
- + while ((SDL_NULL != supported_file_types[i].type) && (!loaded)) {
- + my_strcpy(filename_buf, path, filename_buf_size);
- + filename_buf = string_append(filename_buf,
- + supported_file_types[i].extension);
- +
- + if (file_exists(filename_buf)) {
- + if (!sample)
- + sample = mem_zalloc(sizeof(*sample));
- +
- + if (sample) {
- + sample->sample_type = supported_file_types[i].type;
- + sample->path = string_make(filename_buf);
- +
- + /* Try and load the sample file */
- + if (!load_sample_sdl(sample))
- + mem_free(sample->path);
- + else
- + loaded = true;
- - /* Don't load now if we're not caching */
- - if (no_cache) {
- - /* Just save the path for later */
- - samples[event].paths[num] = string_make(path);
- } else {
- - /* Load the file now */
- - if (use_mp3) {
- - samples[event].mp3s[num] = Mix_LoadMUS(path);
- - if (!samples[event].mp3s[num]) {
- - plog_fmt("%s: %s", SDL_GetError(), strerror(errno));
- - goto next_token;
- - }
- - } else {
- - samples[event].wavs[num] = Mix_LoadWAV(path);
- - if (!samples[event].wavs[num]) {
- - plog_fmt("%s: %s", SDL_GetError(), strerror(errno));
- - goto next_token;
- - }
- - }
- - }
- -
- - /* Imcrement the sample count */
- - samples[event].num++;
- -
- - next_token:
- -
- - /* Figure out next token */
- - cur_token = next_token;
- - if (next_token) {
- - /* Try to find a space */
- - search = strchr(cur_token, ' ');
- -
- - /* If we can find one, terminate, and set new "next" */
- - if (search) {
- - search[0] = '\0';
- - next_token = search + 1;
- - } else {
- - /* Otherwise prevent infinite looping */
- - next_token = NULL;
- - }
- + /* Out of memory */
- + mem_free(filename_buf);
- + data = NULL;
- + return false;
- }
- + } else {
- + i++;
- }
- }
- - /* Close the file */
- - file_close(fff);
- + mem_free(filename_buf);
- + if (!loaded) {
- + mem_free(sample);
- + sample = NULL;
- + }
- - /* Success */
- - return true;
- + data = (void *)sample;
- +
- + return (NULL != sample);
- }
- /**
- * Play a sound of type "event".
- */
- -static void play_sound(game_event_type type, game_event_data *data, void *user)
- +static bool play_sound_sdl(void *data)
- {
- - Mix_Chunk *wave = NULL;
- - Mix_Music *mp3 = NULL;
- - int s;
- -
- - int event = data->message.type;
- -
- - /* Paranoia */
- - if (event < 0 || event >= MSG_MAX) return;
- -
- - /* Check there are samples for this event */
- - if (!samples[event].num) return;
- -
- - /* Choose a random event */
- - s = randint0(samples[event].num);
- - if (use_mp3)
- - mp3 = samples[event].mp3s[s];
- - else
- - wave = samples[event].wavs[s];
- -
- - /* Try loading it, if it's not cached */
- - if (!(wave || mp3)) {
- - /* Verify it exists */
- - const char *filename = samples[event].paths[s];
- - if (!file_exists(filename)) return;
- -
- - /* Load */
- - if (use_mp3)
- - mp3 = Mix_LoadMUS(filename);
- - else
- - wave = Mix_LoadWAV(filename);
- + sdl_sample *sample = (sdl_sample *)data;
- +
- + if (sample) {
- + switch (sample->sample_type) {
- + case SDL_CHUNK:
- + if (sample->chunk)
- + return (0 == Mix_PlayChannel(-1, sample->chunk, 0));
- + break;
- +
- + case SDL_MUSIC:
- + if (sample->music)
- + return (0 == Mix_PlayMusic(sample->music, 1));
- + break;
- +
- + default:
- + break;
- + }
- }
- - /* Check to see if we have a sound again */
- - if (!(wave || mp3)) {
- - plog("SDL sound load failed.");
- - return;
- + return false;
- +}
- +
- +static bool unload_sound_sdl(void *data)
- +{
- + sdl_sample *sample = (sdl_sample *)data;
- +
- + if (sample) {
- + switch (sample->sample_type) {
- + case SDL_CHUNK:
- + if (sample->chunk)
- + Mix_FreeChunk(sample->chunk);
- +
- + break;
- +
- + case SDL_MUSIC:
- + if (sample->music)
- + Mix_FreeMusic(sample->music);
- +
- + break;
- +
- + default:
- + break;
- + }
- +
- + if (sample->path)
- + mem_free(sample->path);
- +
- + mem_free(sample);
- }
- - /* Actually play the thing */
- - if (use_mp3)
- - Mix_PlayMusic(mp3, 1);
- - else
- - Mix_PlayChannel(-1, wave, 0);
- + return true;
- }
- -
- /**
- - * Init the SDL sound "module".
- + * Shut down the sound system and free resources.
- */
- -errr init_sound_sdl(int argc, char **argv)
- +static bool close_audio_sdl(void)
- {
- - int i;
- -
- - /* Parse args */
- - for (i = 1; i < argc; i++) {
- - if (prefix(argv[i], "-c")) {
- - no_cache_audio = true;
- - plog("Audio cache disabled.");
- - continue;
- - }
- - }
- + /*
- + * Close the audio.
- + *
- + * NOTE: All samples will have been free'd by the sound subsystem
- + * calling unload_sound_sdl() for every sample that was loaded.
- + */
- + Mix_CloseAudio();
- - /* Load sound preferences if requested */
- - if (!sound_sdl_init(no_cache_audio)) {
- - plog("Failed to load sound config");
- + /* XXX This may conflict with the SDL port */
- + SDL_Quit();
- - /* Failure */
- - return (1);
- - }
- + return true;
- +}
- +
- +/**
- + * Init the SDL sound "module".
- + */
- +errr init_sound_sdl(struct sound_hooks *hooks, int argc, char **argv)
- +{
- + hooks->open_audio_hook = open_audio_sdl;
- + hooks->close_audio_hook = close_audio_sdl;
- - /* Enable sound */
- - event_add_handler(EVENT_SOUND, play_sound, NULL);
- - atexit(close_audio);
- + hooks->load_sound_hook = load_sound_sdl;
- + hooks->unload_sound_hook = unload_sound_sdl;
- + hooks->play_sound_hook = play_sound_sdl;
- /* Success */
- return (0);
- diff --git a/src/sound-core.c b/src/sound-core.c
- new file mode 100644
- index 0000000..d43b8e5
- --- /dev/null
- +++ b/src/sound-core.c
- @@ -0,0 +1,388 @@
- +/**
- + * \file sound-core.c
- + * \brief core sound support
- + *
- + * Copyright (c) 2004 Brendon Oliver <brendon.oliver@gmail.com>
- + * Copyright (c) 2007 Andi Sidwell <andi@takkaria.org>
- + * A large chunk of this file was taken and modified from main-ros.
- + *
- + * This work is free software; you can redistribute it and/or modify it
- + * under the terms of either:
- + *
- + * a) the GNU General Public License as published by the Free Software
- + * Foundation, version 2, or
- + *
- + * b) the "Angband licence":
- + * This software may be copied and distributed for educational, research,
- + * and not for profit purposes provided that this copyright and statement
- + * are included in all such copies. Other copyrights may also apply.
- + */
- +#include "angband.h"
- +#include "init.h"
- +#include "sound.h"
- +#include "avltree.h"
- +#include "main.h"
- +
- +/**
- + * SDL needs a look-in
- + */
- +#ifdef SOUND_SDL
- +# include "SDL.h"
- +
- +/* HACK */
- +errr init_sound_sdl(struct sound_hooks *hooks, int argc, char **argv);
- +#endif
- +
- +static int init_sound_dummy(struct sound_hooks *hooks, int argc, char *argv[]) {
- + return 0;
- +}
- +
- +/**
- + * List of sound modules in the order they should be tried.
- + */
- +const struct sound_module sound_modules[] =
- +{
- +#ifdef SOUND_SDL
- + { "sdl", "SDL_mixer sound module", init_sound_sdl },
- +#endif /* SOUND_SDL */
- +
- + { "none", "No sound", init_sound_dummy },
- +};
- +
- +/*
- + * We will need two trees:
- + * - A mapping of 'sound names' to 'sound ids' - this is only used during
- + * the initial parsing of the sound configuration file to ensure we don't
- + * load the same sounds multiple times (if a sound is mapped to more than
- + * one message)
- + * - A mapping of 'message ids' to 'sound ids' - In the past, we have used a
- + * static array of size [MAX_MESSAGES][MAX_SOUND_PER_MESSAGE] which results
- + * in a horrendous waste of memory
- + */
- +
- +
- +/*****************************************************************************
- + * Structures to map sound names to ids
- + *****************************************************************************/
- +typedef struct _sound_node sound_node;
- +
- +struct _sound_node
- +{
- + char *sound_name;
- + u16b sound_id;
- +
- + TREE_ENTRY(_sound_node) sound_tree;
- +};
- +
- +static sound_node *sound_node_new(char *sound_name, u16b sound_id)
- +{
- + sound_node *self = mem_alloc(sizeof *self);
- +
- + self->sound_name = string_make(sound_name);
- + self->sound_id = sound_id;
- + return self;
- +}
- +
- +static int sound_node_compare(sound_node *lhs, sound_node *rhs)
- +{
- + return (int)strcmp(lhs->sound_name, rhs->sound_name);
- +}
- +
- +typedef TREE_HEAD(_sound_tree, _sound_node) tree_sound;
- +
- +TREE_DEFINE(_sound_node, sound_tree)
- +
- +static tree_sound sounds = TREE_INITIALIZER(sound_node_compare);
- +
- +static u16b next_sound_id;
- +/*****************************************************************************/
- +
- +/*****************************************************************************
- + * Structures to map message ids to sound ids
- + *****************************************************************************/
- +typedef struct _msg_sound msg_sound;
- +
- +struct _msg_sound
- +{
- + int sound_id;
- + msg_sound *next;
- +};
- +
- +typedef struct _message_node message_node;
- +
- +struct _message_node
- +{
- + u16b message_id;
- + int num_sounds;
- + msg_sound *first;
- +
- + TREE_ENTRY(_message_node) message_tree;
- +};
- +
- +static message_node *message_node_new(u16b message_id)
- +{
- + message_node *self = mem_alloc(sizeof *self);
- +
- + self->message_id = message_id;
- +
- + return self;
- +}
- +
- +static int message_node_compare(message_node *lhs, message_node *rhs)
- +{
- + return (rhs->message_id - lhs->message_id);
- +}
- +
- +typedef TREE_HEAD(_message_tree, _message_node) tree_message;
- +
- +TREE_DEFINE(_message_node, message_tree)
- +
- +static tree_message messages = TREE_INITIALIZER(message_node_compare);
- +/*****************************************************************************/
- +
- +///*
- +// * HACK: Structure to allow the platform's sound module to store platform
- +// * specific data for each sound. Typically 'plat_data' will be a structure
- +// * containing information such as the format of the sound (wav, mp3, ogg, etc)
- +// * and the actual sound data. plat_data is created when we call
- +// * load_sound_hook() and passed to unload_sound_hook() in order for the
- +// * platform's sound module to safely de-allocate resources
- +// */
- +//typedef struct {
- +// void *plat_data;
- +//} sound_plat_data;
- +
- +/*
- + * After processing the preference files, the 'sounds' AVL Tree will contain
- + * next_sound_id nodes - each representing a sound that needs to be loaded.
- + * We create the sound_data array once we know this information, and then
- + * populate it by calling load_sound_hook() for each node in the tree
- + */
- +static void **sound_data;
- +
- +static struct sound_hooks hooks;
- +
- +void message_sound_define(u16b message_id, const char *sounds_str)
- +{
- + char *search;
- + char *str;
- + char *cur_token;
- + char *next_token;
- +
- + sound_node sound_search_node;
- + sound_node *existing_sound;
- + sound_node *new_sound;
- + u16b sound_id;
- +
- + message_node message_search_node;
- + message_node *message_map;
- + msg_sound *new_message_sound;
- +
- + str = cur_token = string_make(sounds_str);
- +
- + search = strchr(cur_token, ' ');
- + if (search) {
- + search[0] = '\0';
- + next_token = search++;
- + } else {
- + next_token = NULL;
- + }
- +
- + if (cur_token) {
- + /* Do we already have a message->sounds mapping? */
- + message_search_node.message_id = message_id;
- +
- + message_map = TREE_FIND(&messages, _message_node, message_tree, &message_search_node);
- +
- + if (!message_map) {
- + message_map = message_node_new(message_id);
- + TREE_INSERT(&messages, _message_node, message_tree, message_map);
- + }
- + }
- +
- + /* Find all the sample names and add them one by one */
- + while (cur_token) {
- + /* Have we already processed this sound name? */
- + sound_search_node.sound_name = cur_token;
- +
- + existing_sound = TREE_FIND(&sounds, _sound_node, sound_tree, &sound_search_node);
- +
- + if (existing_sound) {
- + /* Yep - Just need to get the ID */
- + sound_id = existing_sound->sound_id;
- + } else {
- + /* Nope - Create a new node to store this sound's ID */
- + sound_id = next_sound_id;
- + new_sound = sound_node_new(cur_token, sound_id);
- + TREE_INSERT(&sounds, _sound_node, sound_tree, new_sound);
- +
- + next_sound_id++;
- + }
- +
- + /* Add this sound (by id) to the message->sounds map */
- + new_message_sound = mem_alloc(sizeof *new_message_sound);
- + new_message_sound->sound_id = sound_id;
- + new_message_sound->next = message_map->first;
- + message_map->first = new_message_sound;
- + message_map->num_sounds++;
- +
- + /* Figure out next token */
- + cur_token = next_token;
- +
- + if (next_token) {
- + /* Try to find a space */
- + search = strchr(cur_token, ' ');
- +
- + /* If we can find one, terminate, and set new "next" */
- + if (search) {
- + search[0] = '\0';
- + next_token = search + 1;
- + } else {
- + /* Otherwise prevent infinite looping */
- + next_token = NULL;
- + }
- + }
- + }
- +
- + string_free(str);
- +}
- +
- +/**
- + * Play a sound of type "event".
- + */
- +static void play_sound(game_event_type type, game_event_data *data, void *user)
- +{
- + int s, i, sound_id;
- + message_node message_search_node;
- + message_node *message_map;
- + msg_sound *message_sound;
- +
- + int event = data->message.type;
- +
- + /* Paranoia */
- + assert(event >= 0);
- +
- + message_search_node.message_id = (u16b)event;
- +
- + message_map = TREE_FIND(&messages, _message_node, message_tree, &message_search_node);
- +
- + if (!message_map)
- + return; /* No sounds for this message */
- +
- +
- + /* Choose a random event */
- + message_sound = message_map->first;
- +
- + if (!message_sound)
- + return; /* Oops */
- +
- + s = randint0(message_map->num_sounds);
- +
- + /*
- + * Walk the list - possibly inefficient if you define LOTS of sounds
- + * for LOTS of messages. Not worth using a more 'efficient' data
- + * structure
- + */
- + for (i = 0; i < s; i++)
- + if (message_sound->next)
- + message_sound = message_sound->next;
- +
- + sound_id = message_sound->sound_id;
- +
- +
- + assert((sound_id >= 0) && (sound_id < next_sound_id));
- +
- + hooks.play_sound_hook(sound_data[sound_id]);
- +}
- +
- +static void load_sound(sound_node *self, void *ignore)
- +{
- + void *plat_data;
- +
- + if (hooks.load_sound_hook) {
- + if(!hooks.load_sound_hook(self->sound_name, &plat_data))
- + plog_fmt("Failed to load sound: %s", self->sound_name);
- + else
- + sound_data[self->sound_id] = plat_data;
- + }
- +}
- +
- +/*
- + * Shut down the sound system and free resources.
- + */
- +static void close_audio(void)
- +{
- + int i;
- +
- + if (0 == next_sound_id)
- + return; /* Never opened */
- +
- + /*
- + * Ask the platforms sound module to free resources for each
- + * sound
- + */
- + if (hooks.unload_sound_hook)
- + for (i = 0; i < next_sound_id; i++)
- + hooks.unload_sound_hook(sound_data[i]);
- +
- + mem_free(sound_data);
- +
- + /* TODO: Kill the trees */
- +
- + /* Close the platform's sound module */
- + if (hooks.close_audio_hook)
- + hooks.close_audio_hook();
- +}
- +
- +
- +/**
- + * Init the sound "module".
- + */
- +errr init_sound(const char *soundstr, int argc, char **argv)
- +{
- + int i;
- + bool done;
- +
- + /* Only initialise the sound sub-system if we have sounds to play */
- + if (0 == next_sound_id)
- + return 0; /* It's not a fail if no sounds defined */
- +
- + /* Try the modules in the order specified by sound_modules[] */
- + for (i = 0; i < (int)N_ELEMENTS(sound_modules); i++)
- + if (!soundstr || streq(soundstr, sound_modules[i].name))
- + if (0 == sound_modules[i].init(&hooks, argc, argv)) {
- + done = true;
- + break;
- + }
- +
- + /* Check that we have a sound module to use */
- + if (!done)
- + return 1;
- +
- + /* Open the platform specific sound system */
- + if (!hooks.open_audio_hook)
- + return 1;
- +
- + if (!hooks.open_audio_hook(argc, argv))
- + return 1;
- +
- + sound_data = mem_zalloc(sizeof(void *) * next_sound_id);
- +
- + TREE_FORWARD_APPLY(&sounds, _sound_node, sound_tree, load_sound, NULL);
- +
- + /* Enable sound */
- + event_add_handler(EVENT_SOUND, play_sound, NULL);
- + atexit(close_audio);
- +
- + /* Success */
- + return (0);
- +}
- +
- +void print_sound_help(void)
- +{
- + int i;
- +
- + for (i = 0; i < (int)N_ELEMENTS(sound_modules); i++)
- + printf(" %s %s\n", sound_modules[i].name,
- + sound_modules[i].help);
- +}
- diff --git a/src/sound.h b/src/sound.h
- new file mode 100644
- index 0000000..4b73c4d
- --- /dev/null
- +++ b/src/sound.h
- @@ -0,0 +1,45 @@
- +/**
- + * \file sound.h
- + * \brief Sound handling
- + *
- + * Copyright (c) 2016 Graeme Russ
- + *
- + * Redistribution and use in source and binary forms, with or without
- + * modification, are permitted provided that the following conditions are met:
- + *
- + * * Redistributions of source code must retain the above copyright notice,
- + * this list of conditions and the following disclaimer.
- + *
- + * * Redistributions in binary form must reproduce the above copyright notice,
- + * this list of conditions and the following disclaimer in the documentation
- + * and/or other materials provided with the distribution.
- + */
- +
- +#ifndef INCLUDED_Z_SOUND_H
- +#define INCLUDED_Z_SOUND_H
- +
- +struct sound_hooks
- +{
- + bool (*open_audio_hook)(int argc, char **argv);
- + bool (*close_audio_hook)(void);
- +
- + /* 'data' is a sound module specific struct */
- + bool (*load_sound_hook)(const char *sound_name, void *data);
- + bool (*unload_sound_hook)(void *data);
- + bool (*play_sound_hook)(void *data);
- +};
- +
- +struct sound_module
- +{
- + const char *name;
- + const char *help;
- + errr (*init)(struct sound_hooks *hooks, int argc, char **argv);
- +};
- +
- +errr init_sound(const char *soundstr, int argc, char **argv);
- +
- +void message_sound_define(u16b type, const char *sounds);
- +
- +void print_sound_help(void);
- +
- +#endif /* !INCLUDED_Z_SOUND_H */
- diff --git a/src/ui-prefs.c b/src/ui-prefs.c
- index cff07cf..e32ba72 100644
- --- a/src/ui-prefs.c
- +++ b/src/ui-prefs.c
- @@ -34,6 +34,7 @@
- #include "ui-keymap.h"
- #include "ui-prefs.h"
- #include "ui-term.h"
- +#include "sound.h"
- int arg_graphics; /* Command arg -- Request graphics mode */
- bool arg_graphics_nice; /* Command arg -- Request nice graphics mode */
- @@ -1047,6 +1048,29 @@ static enum parser_error parse_prefs_window(struct parser *p)
- return PARSE_ERROR_NONE;
- }
- +static enum parser_error parse_prefs_sound(struct parser *p)
- +{
- + int msg_index;
- + const char *type;
- + const char *sounds;
- +
- + struct prefs_data *d = parser_priv(p);
- + assert(d != NULL);
- + if (d->bypass) return PARSE_ERROR_NONE;
- +
- + type = parser_getsym(p, "type");
- + sounds = parser_getstr(p, "sounds");
- +
- + msg_index = message_lookup_by_name(type);
- +
- + if (msg_index < 0)
- + return PARSE_ERROR_INVALID_MESSAGE;
- +
- + message_sound_define(msg_index, sounds);
- +
- + return PARSE_ERROR_NONE;
- +}
- +
- static struct parser *init_parse_prefs(bool user)
- {
- struct parser *p = parser_new();
- @@ -1074,6 +1098,7 @@ static struct parser *init_parse_prefs(bool user)
- parser_reg(p, "message sym type sym attr", parse_prefs_message);
- parser_reg(p, "color uint idx int k int r int g int b", parse_prefs_color);
- parser_reg(p, "window int window uint flag uint value", parse_prefs_window);
- + parser_reg(p, "sound sym type str sounds", parse_prefs_sound);
- return p;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement