IV. Other related routines
V. Game Startup and Soundlib Activation Sequencing
VI. Conventions
- VII. Implementation and Multi-window support
+ VII. Implementation and Multiple Soundlib Support
I. Sound Trigger Types and Terminology
-There are 4 distinct types of sound triggers used by NetHack.
+There are 4 distinct types of sound sound_triggers used by NetHack.
- SNDCAP_USERSOUNDS User-specified sounds that play based on config
- file entries that identify a regular expression
- to match against message window text, and identify
- an external sound file to load in response.
- The sound interface function pointer used to invoke
- it:
+ SOUND_TRIGGER_USERSOUNDS User-specified sounds that play based
+ on config file entries that identify a
+ regular expression to match against
+ message window text, and identify an
+ external sound file to load in response.
+ The sound interface function pointer
+ used to invoke it:
- void (*sound_play_usersound)(char *filename,
+ void (*sound_play_usersound)(char *filename,
int32_t volume, int32_t idx);
- SNDCAP_HEROMUSIC Invoked by the core when the in-game hero is
- playing a tune on an instrument. The sound
- interface function pointer used to invoke it:
-
- void (*sound_hero_playnotes)(int32_t instrument,
- const char *str, int32_t volume);
-
- SNDCAP_ACHIEVEMENTS Invoked by the core when an in-game achievement
- is reached. The soundlib routines could play
- appropriate theme or mood music in response.
- There would need to be a way to map the
- achievements to external user-specified sounds.
- The sound interface function pointer used to
- invoke it:
-
- void (*sound_achievement)(schar, schar,
+ SOUND_TRIGGER_HEROMUSIC Invoked by the core when the in-game hero,
+ or perhaps another creature, is playing
+ a tune on an instrument. The sound interface
+ function pointer used to invoke it:
+
+ void (*sound_hero_playnotes)
+ (int32_t instrument, const char *str,
+ int32_t volume);
+
+ SOUND_TRIGGER_ACHIEVEMENTS Invoked by the core when an in-game
+ achievement is reached. The soundlib routines
+ could play appropriate theme or mood music in
+ response.
+ There needs to be a way to map each
+ achievement to a specific external
+ sound file or resource. The sound
+ interface function pointer used to
+ invoke it:
+
+ void (*sound_achievement)(schar, schar,
int32_t);
- SNDCAP_SOUNDEFFECTS Invoked by the core when something
- sound-producing happens in the game. The soundlib
- routines could play an appropriate sound effect
- in response. They can be public-domain or
- suitably licensed stock sounds included with the
- game source and made available during the build
- process, or (not-yet-implemented) a way to
- tie particular sound effects to a user-specified
- sound samples in a config file. The sound
- interface function pointer used to invoke it:
-
- void (*sound_soundeffect)(char *desc, int32_t,
- int32_t volume);
-
-The types of sound triggers supported by a particular sound library
-integration are specified in that library's soundlib file, which is
-usually found in sound/<library_name>/<library_name>.c
-(.m in the case of macound), in the sndcap field of the sound_procs struct:
+ SOUND_TRIGGER_SOUNDEFFECTS Invoked by the core when something
+ sound-producing happens in the game. The
+ soundlib routines could play an appropriate
+ sound effect in response. They can be
+ public-domain or suitably licensed stock
+ sounds included with the
+ gamesource. The soundeffect must be made
+ available during the build process, or
+ (not-yet-implemented) a way to tie a
+ particular sound effect to a player-specified
+ sound samples within the player's config
+ file. The sound interface function
+ pointer used to invoke it:
+
+ void (*sound_soundeffect)
+ (char *desc, int32_t, int32_t volume);
+
+The types of sound sound_triggers supported by a particular soundlib
+implementation are specified in that library's soundlib file, which is usually
+found in sound/<library_name>/<library_name>.c (.m in the case of macound), in
+the sound_triggers field of the sound_procs struct:
struct sound_procs {
const char *soundname;
enum soundlib_ids soundlib_id;
- unsigned long sndcap;
+ unsigned long sound_triggers;
void (*sound_init_nhsound)(void);
void (*sound_exit_nhsound)(const char *reason);
void (*sound_achievement)(schar arg1, schar arg2, int32_t avals);
};
A sound library integration support file can implement one, two, three or
-four of the sound trigger types. The more types of sound-triggers the sound
+four of the sound trigger types. The more types of sound_triggers the
soundlib implements, the more full-featured the sound experience will be
during the game.
-The values can be or'd together in the sndcap field initialization.
-SNDCAP_USERSOUNDS | SNDCAP_HEROMUSIC | SNDCAP_ACHIEVEMENTS |SNDCAP_SOUNDEFFECTS
+The values can be or'd together in the sound_triggers field initialization.
+ SOUND_TRIGGER_USERSOUNDS | SOUND_TRIGGER_HEROMUSIC
+ | SOUND_TRIGGER_ACHIEVEMENTS | SOUND_TRIGGER_SOUNDEFFECTS
II. Interface Specification
be capping the number of notes at 5, but it is not
recommended that the soundlib integration support functions
rely on that note count cap as a hard rule.
- -- A soundlib integration support file that has SNDCAP_HEROMUSIC
+ -- A soundlib integration support file that has SOUND_TRIGGER_HEROMUSIC
support is expected to play the sound at the volume specified
by the volume argument (1 - 100, representing percentage of
possible volume levels), if the underlying sound library supports
-- NetHack will call this function when it wants a particular
external sound file played, based on a regular expression match
that the player has defined in their config file.
- -- A soundlib integration support file that has SNDCAP_USERSOUNDS
+ -- A soundlib integration support file that has SOUND_TRIGGER_USERSOUNDS
support is expected to play the sound file specified by the filename
argument.
- -- A soundlib integration support file that has SNDCAP_USERSOUNDS
+ -- A soundlib integration support file that has SOUND_TRIGGER_USERSOUNDS
support is expected to play the sound at the volume specified
by the volume argument (1 - 100, representing percentage of
possible volume levels), if the underlying sound library supports
soundlib support.
-VII. Implementation and Multiple soundlib support
+VII. Implementation and Multiple Soundlib Support
Multiple soundlib routines are supported in the same binary.
struct sound_procs myprefix_procs = {
SOUNDID(myprefix),
- SNDCAP_USERSOUNDS | SNDCAP_HEROMUSIC
- | SNDCAP_ACHIEVEMENTS |SNDCAP_SOUNDEFFECTS,
+ SOUND_TRIGGER_USERSOUNDS | SOUND_TRIGGER_HEROMUSIC
+ | SOUND_TRIGGER_ACHIEVEMENTS |SOUND_TRIGGER_SOUNDEFFECTS,
myprefix_init_nhsound,
myprefix_exit_nhsound,
myprefix_achievement,
The first entry in this structure should be the SOUNDID(myprefix)
where myprefix should be the name of your soundlib port.
- After that, the next entry is the sndcap mask that identifies
- what sound triggers your soundlib will actually react to and
- support. Don't include the sndcap values for functions that are
+ After that, the next entry is the sound_triggers mask that identifies
+ what sound_triggers your soundlib will actually react to and
+ support. Don't include the sound_triggers values for functions that are
empty, so that the NetHack core code won't bother trying to call
them. The other entries are the function addresses.
struct sound_procs sample_procs = {
SOUNDID(sample),
- SNDCAP_USERSOUNDS | SNDCAP_HEROMUSIC
- | SNDCAP_ACHIEVEMENTS |SNDCAP_SOUNDEFFECTS,
+ SOUND_TRIGGER_USERSOUNDS | SOUND_TRIGGER_HEROMUSIC
+ | SOUND_TRIGGER_ACHIEVEMENTS |SOUND_TRIGGER_SOUNDEFFECTS,
sample_init_nhsound,
sample_exit_nhsound,
sample_achievement,
}
-/* fulfill SNDCAP_ACHIEVEMENTS */
+/* fulfill SOUND_TRIGGER_ACHIEVEMENTS */
static void
sample_achievement(schar ach1, schar ach2, int32_t avals)
{
}
-/* fulfill SNDCAP_SOUNDEFFECTS */
+/* fulfill SOUND_TRIGGER_SOUNDEFFECTS */
static void
sample_soundeffect(char *desc, int32_t seid, int volume)
{
}
-/* fulfill SNDCAP_HEROMUSIC */
+/* fulfill SOUND_TRIGGER_HEROMUSIC */
static void sample_hero_playnotes(int32_t instrument, const char *str, int32_t volume)
{
}
-/* fulfill SNDCAP_USERSOUNDS */
+/* fulfill SOUND_TRIGGER_USERSOUNDS */
static void
sample_play_usersound(char *filename, int volume, int usidx)
{
#ifndef SNDPROCS_H
#define SNDPROCS_H
-/*
- *
- * Types of potential sound supports (all are optional):
- *
- * SNDCAP_USERSOUNDS User-specified sounds that play based on config
- * file entries that identify a regular expression
- * to match against message window text, and identify
- * an external sound file to load in response.
- * The sound interface function pointer used to invoke
- * it:
- *
- * void (*sound_play_usersound)(char *filename,
- * int32_t volume, int32_t idx);
- *
- * SNDCAP_HEROMUSIC Invoked by the core when the in-game hero is
- * playing a tune on an instrument. The sound
- * interface function pointer used to invoke it:
- *
- * void (*sound_hero_playnotes)(int32_t instrument,
- * const char *str, int32_t volume);
- *
- * SNDCAP_ACHIEVEMENTS Invoked by the core when an in-game achievement
- * is reached. The soundlib routines could play
- * appropriate theme or mood music in response.
- * There would need to be a way to map the
- * achievements to external user-specified sounds.
- * The sound interface function pointer used to
- * invoke it:
- *
- * void (*sound_achievement)(schar, schar,
- * int32_t);
- *
- * SNDCAP_SOUNDEFFECTS Invoked by the core when something
- * sound-producing happens in the game. The soundlib
- * routines could play an appropriate sound effect
- * in response. They can be public-domain or
- * suitably-licensed stock sounds included with the
- * game source and made available during the build
- * process, or (not-yet-implemented) a way to
- * tie particular sound effects to a user-specified
- * sound samples in a config file. The sound
- * interface function pointer used to invoke it:
- *
- * void (*sound_soundeffect)(char *desc, int32_t,
- * int32_t volume);
- *
- * Development notes:
- * - gc.chosen_soundlib holds the soundlib_id that will be initialized
- * at the appropriate time (startup or after an option change). It
- * is initialized to soundlib_nosound, so that is what will be used if
- * the initial value isn't replaced via an assign_soundlib() call
- * prior to the call to the activate_chosen_soundlib() in
- * moveloop_preamble() at the start of the game.
- * - ga.active_soundlib holds the soundlib_id of the active soundlib.
- * It is initialized to soundlib_unassigned. It will get changed to
- * reflect the activated soundlib_id once activate_chosen_soundlib()
- * has been called.
- *
- */
-
enum soundlib_ids {
soundlib_nosound,
#ifdef SND_LIB_PORTAUDIO
struct sound_procs {
const char *soundname;
enum soundlib_ids soundlib_id;
- unsigned long sndcap; /* capabilities in the port */
+ unsigned long sound_triggers; /* capabilities in the port */
void (*sound_init_nhsound)(void);
void (*sound_exit_nhsound)(const char *);
void (*sound_achievement)(schar, schar, int32_t);
#define SOUNDID(soundname) #soundname, ((enum soundlib_ids) soundlib_##soundname)
/*
- * SOUNDCAP
+ * Types of triggers
*/
-#define SNDCAP_USERSOUNDS 0x0001L
-#define SNDCAP_HEROMUSIC 0x0002L
-#define SNDCAP_ACHIEVEMENTS 0x0004L
-#define SNDCAP_SOUNDEFFECTS 0x0008L
+#define SOUND_TRIGGER_USERSOUNDS 0x0001L
+#define SOUND_TRIGGER_HEROMUSIC 0x0002L
+#define SOUND_TRIGGER_ACHIEVEMENTS 0x0004L
+#define SOUND_TRIGGER_SOUNDEFFECTS 0x0008L
/* 28 free bits */
extern struct sound_procs soundprocs;
#define SND_LIB_INTEGRATED /* shortcut for conditional code in other files */
#define Play_usersound(filename, vol, idx) \
- do { \
- if (!Deaf && soundprocs.sound_play_usersound \
- && ((soundprocs.sndcap & SNDCAP_USERSOUNDS) != 0)) \
- (*soundprocs.sound_play_usersound)((filename), (vol), (idx)); \
+ do { \
+ if (!Deaf && soundprocs.sound_play_usersound \
+ && ((soundprocs.sound_triggers & SOUND_TRIGGER_USERSOUNDS) != 0)) \
+ (*soundprocs.sound_play_usersound)((filename), (vol), (idx)); \
} while(0)
#define Soundeffect(seid, vol) \
- do { \
- if (!Deaf && soundprocs.sound_soundeffect \
- && ((soundprocs.sndcap & SNDCAP_SOUNDEFFECTS) != 0)) \
- (*soundprocs.sound_soundeffect)(emptystr, (seid), (vol)); \
+ do { \
+ if (!Deaf && soundprocs.sound_soundeffect \
+ && ((soundprocs.sound_triggers & SOUND_TRIGGER_SOUNDEFFECTS) != 0)) \
+ (*soundprocs.sound_soundeffect)(emptystr, (seid), (vol)); \
} while(0)
/* Player's perspective, not the hero's; no Deaf suppression */
#define SoundeffectEvenIfDeaf(seid, vol) \
- do { \
- if (!soundprocs.sound_soundeffect \
- && ((soundprocs.sndcap & SNDCAP_SOUNDEFFECTS) != 0)) \
- (*soundprocs.sound_soundeffect)(emptystr, (seid), (vol)); \
+ do { \
+ if (!soundprocs.sound_soundeffect \
+ && ((soundprocs.sound_triggers & SOUND_TRIGGER_SOUNDEFFECTS) != 0)) \
+ (*soundprocs.sound_soundeffect)(emptystr, (seid), (vol)); \
} while(0)
#define Hero_playnotes(instrument, str, vol) \
- do { \
- if (!Deaf && soundprocs.sound_hero_playnotes \
- && ((soundprocs.sndcap & SNDCAP_HEROMUSIC) != 0)) \
- (*soundprocs.sound_hero_playnotes)((instrument), (str), (vol)); \
+ do { \
+ if (!Deaf && soundprocs.sound_hero_playnotes \
+ && ((soundprocs.sound_triggers & SOUND_TRIGGER_HEROMUSIC) != 0)) \
+ (*soundprocs.sound_hero_playnotes)((instrument), (str), (vol)); \
} while(0)
/* void (*sound_achievement)(schar, schar, int32_t); */
/* Player's perspective, not the hero's; no Deaf suppression */
#define SoundAchievement(arg1, arg2, avals) \
- do { \
- if (soundprocs.sound_achievement \
- && ((soundprocs.sndcap & SNDCAP_ACHIEVEMENTS) != 0)) \
- (*soundprocs.sound_achievement)((arg1), (arg2), (avals)); \
+ do { \
+ if (soundprocs.sound_achievement \
+ && ((soundprocs.sound_triggers & SOUND_TRIGGER_ACHIEVEMENTS) != 0)) \
+ (*soundprocs.sound_achievement)((arg1), (arg2), (avals)); \
} while(0)
/* void (*sound_achievement)(schar, schar, int32_t); */
/*
* Sound capabilities that can be enabled:
- * SNDCAP_USERSOUNDS | SNDCAP_HEROMUSIC
- * | SNDCAP_ACHIEVEMENTS |SNDCAP_SOUNDEFFECTS,
+ * SOUND_TRIGGER_USERSOUNDS | SOUND_TRIGGER_HEROMUSIC
+ * | SOUND_TRIGGER_ACHIEVEMENTS | SOUND_TRIGGER_SOUNDEFFECTS,
*/
struct sound_procs macsound_procs = {
SOUNDID(macsound),
- SNDCAP_HEROMUSIC | SNDCAP_SOUNDEFFECTS,
+ SOUND_TRIGGER_HEROMUSIC | SOUND_TRIGGER_SOUNDEFFECTS,
macsound_init_nhsound,
macsound_exit_nhsound,
macsound_achievement,
macsound_play_usersound,
};
-/*
- *
- * Types of potential sound supports (all are optionally implemented):
- *
- * SNDCAP_USERSOUNDS User-specified sounds that play based on config
- * file entries that identify a regular expression
- * to match against message window text, and identify
- * an external sound file to load in response.
- * The sound interface function pointer used to invoke
- * it:
- *
- * void (*sound_play_usersound)(char *filename,
- * int32_t volume, int32_t idx);
- *
- * SNDCAP_HEROMUSIC Invoked by the core when the in-game hero is
- * playing a tune on an instrument. The sound
- * interface function pointer used to invoke it:
- *
- * void (*sound_hero_playnotes)(int32_t instrument,
- * char *str, int32_t volume);
- *
- * SNDCAP_ACHIEVEMENTS Invoked by the core when an in-game achievement
- * is reached. The soundlib routines could play
- * appropriate theme or mood music in response.
- * There would need to be a way to map the
- * achievements to external user-specified sounds.
- * The sound interface function pointer used to
- * invoke it:
- *
- * void (*sound_achievement)(schar, schar,
- * int32_t);
- *
- * SNDCAP_SOUNDEFFECTS Invoked by the core when something
- * sound-producing happens in the game. The soundlib
- * routines could play an appropriate sound effect
- * in response. They can be public-domain or
- * suitably-licensed stock sounds included with the
- * game source and made available during the build
- * process, or (not-yet-implemented) a way to
- * tie particular sound effects to a user-specified
- * sound macsounds in a config file. The sound
- * interface function pointer used to invoke it:
- *
- * void (*sound_soundeffect)(char *desc, int32_t,
- * int32_t volume);
- *
- * The routines below would call into your sound library.
- * to fulfill the functionality.
- */
-
static void
macsound_init_nhsound(void)
{
}
-/* fulfill SNDCAP_ACHIEVEMENTS */
+/* fulfill SOUND_TRIGGER_ACHIEVEMENTS */
static void
macsound_achievement(schar ach1 UNUSED, schar ach2 UNUSED, int32_t repeat UNUSED)
{
static NSString *soundstring[number_of_se_entries + EXTRA_SOUNDS];
static NSSound *seSound[number_of_se_entries + EXTRA_SOUNDS];
-/* fulfill SNDCAP_SOUNDEFFECTS */
+/* fulfill SOUND_TRIGGER_SOUNDEFFECTS */
static void
macsound_soundeffect(char *desc UNUSED, int32_t seid, int volume UNUSED)
{
#define WAVEMUSIC_SOUNDS
-/* fulfill SNDCAP_HEROMUSIC */
+/* fulfill SOUND_TRIGGER_HEROMUSIC */
static void macsound_hero_playnotes(int32_t instrument,
const char *str, int32_t vol UNUSED)
{
#endif
}
-/* fulfill SNDCAP_USERSOUNDS */
+/* fulfill SOUND_TRIGGER_USERSOUNDS */
static void
macsound_play_usersound(char *filename UNUSED, int volume UNUSED, int idx UNUSED)
{
struct sound_procs windsound_procs = {
SOUNDID(windsound),
- SNDCAP_USERSOUNDS | SNDCAP_SOUNDEFFECTS | SNDCAP_HEROMUSIC,
+ SOUND_TRIGGER_USERSOUNDS | SOUND_TRIGGER_SOUNDEFFECTS
+ | SOUND_TRIGGER_HEROMUSIC,
windsound_init_nhsound,
windsound_exit_nhsound,
windsound_achievement,
* theme music or something. We do let the sound interface know
* that it's not the original achievement though.
*/
- if (soundprocs.sound_achievement)
- (*soundprocs.sound_achievement)(achidx, 0, repeat_achievement);
+ SoundAchievement(achidx, 0, repeat_achievement);
if (repeat_achievement)
return; /* already recorded, don't duplicate it */
#if defined(SND_LIB_QTSOUND) && !defined(QT_NO_SOUND)
struct sound_procs qtsound_procs = {
SOUNDID(qtsound),
- SNDCAP_USERSOUNDS,
+ SOUND_TRIGGER_USERSOUNDS,
nethack_qt_::NetHackQtBind::qtsound_init_nhsound,
nethack_qt_::NetHackQtBind::qtsound_exit_nhsound,
nethack_qt_::NetHackQtBind::qtsound_achievement,