Files
nethack/sound/macsound/macsound.m
nhmall 5171fcdc1d some macsound instrument play refinements
Also some better core placement of some of the Hero_playnotes calls.
2023-01-24 13:02:29 -05:00

281 lines
9.4 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* macsound.m */
/* Copyright Michael Allison, 2023 */
/* NetHack may be freely redistributed. See license for details. */
#include "hack.h"
#ifdef DEBUG
#undef DEBUG
#endif
/* #import <Foundation/Foundation.h> */
#import <AppKit/AppKit.h>
/*
* Sample sound interface for NetHack
*
* Replace 'macsound' with your soundlib name in this template file.
* Should be placed in ../sound/macsound/.
*/
#define soundlib_macsound soundlib_nosound + 1
static void macsound_init_nhsound(void);
static void macsound_exit_nhsound(const char *);
static void macsound_achievement(schar, schar, int32_t);
static void macsound_soundeffect(char *, int32_t, int32_t);
static void macsound_hero_playnotes(int32_t, const char *, int32_t);
static void macsound_play_usersound(char *, int32_t, int32_t);
static int affiliate(int32_t seid, const char *soundname);
struct sound_procs macsound_procs = {
SOUNDID(macsound),
// SNDCAP_USERSOUNDS | SNDCAP_HEROMUSIC
// | SNDCAP_ACHIEVEMENTS |SNDCAP_SOUNDEFFECTS,
SNDCAP_USERSOUNDS | SNDCAP_HEROMUSIC | SNDCAP_SOUNDEFFECTS,
macsound_init_nhsound,
macsound_exit_nhsound,
macsound_achievement,
macsound_soundeffect,
macsound_hero_playnotes,
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)
{
/* Initialize external sound library */
}
static void
macsound_exit_nhsound(const char *reason UNUSED)
{
/* Close / Terminate external sound library */
}
/* fulfill SNDCAP_ACHIEVEMENTS */
static void
macsound_achievement(schar ach1 UNUSED, schar ach2 UNUSED, int32_t repeat UNUSED)
{
}
/* magic number 40 is the current number of sound_ files to include */
#define EXTRA_SOUNDS 40
static int32_t affiliation[number_of_se_entries + EXTRA_SOUNDS] = { 0 };
static NSString *soundstring[number_of_se_entries + EXTRA_SOUNDS];
static NSSound *seSound[number_of_se_entries + EXTRA_SOUNDS];
/* fulfill SNDCAP_SOUNDEFFECTS */
static void
macsound_soundeffect(char *desc UNUSED, int32_t seid, int volume UNUSED)
{
#ifdef SND_SOUNDEFFECTS_AUTOMAP
/* Supposedly, the following locations are searched in this order:
* 1. the applications main bundle
* 2. ~/Library/Sounds
* 3. /Library/Sounds
* 4. /Network/Library/Sounds
* 5. /System/Library/Sounds
*/
char buf[1024];
const char *soundname;
if (seid <= se_zero_invalid || seid >= number_of_se_entries)
return;
if (!affiliation[seid]) {
soundname = get_sound_effect_filename(seid, buf, sizeof buf, 1);
if (soundname) {
affiliate(seid, soundname);
}
}
if (affiliation[seid]) {
if ([seSound[seid] isPlaying])
[seSound[seid] stop];
[seSound[seid] play];
}
#endif
}
#define WAVEMUSIC_SOUNDS
/* fulfill SNDCAP_HEROMUSIC */
static void macsound_hero_playnotes(int32_t instrument,
const char *str, int32_t vol UNUSED)
{
#ifdef WAVEMUSIC_SOUNDS
uint32_t pseudo_seid, pseudo_seid_base;
boolean has_note_variations = FALSE;
char resourcename[120], *end_of_res = 0;
const char *c = 0;
if (!str)
return;
resourcename[0] = '\0';
switch(instrument) {
case ins_tinkle_bell:
Strcpy(resourcename, "sound_Bell");
pseudo_seid_base = 0;
break;
case ins_taiko_drum: /* DRUM_OF_EARTHQUAKE */
Strcpy(resourcename, "sound_Drum_Of_Earthquake");
pseudo_seid_base = 1;
break;
case ins_baritone_sax: /* FIRE_HORN */
Strcpy(resourcename, "sound_Fire_Horn");
pseudo_seid_base = 2;
break;
case ins_french_horn: /* FROST_HORN */
Strcpy(resourcename, "sound_Frost_Horn");
pseudo_seid_base = 3;
break;
case ins_melodic_tom: /* LEATHER_DRUM */
Strcpy(resourcename, "sound_Leather_Drum");
pseudo_seid_base = 4;
break;
case ins_trumpet: /* BUGLE */
Strcpy(resourcename, "sound_Bugle");
has_note_variations = TRUE;
pseudo_seid_base = 5;
break;
case ins_cello: /* MAGIC_HARP */
Strcpy(resourcename, "sound_Magic_Harp");
has_note_variations = TRUE;
pseudo_seid_base = 12;
case ins_english_horn: /* TOOLED_HORN */
Strcpy(resourcename, "sound_Tooled_Horn");
has_note_variations = TRUE;
pseudo_seid_base = 19;
break;
case ins_flute: /* WOODEN_FLUTE */
Strcpy(resourcename, "sound_Wooden_Flute");
has_note_variations = TRUE;
pseudo_seid_base = 26;
break;
case ins_orchestral_harp: /* WOODEN_HARP */
Strcpy(resourcename, "sound_Wooden_Harp");
has_note_variations = TRUE;
pseudo_seid_base = 33;
break;
case ins_pan_flute: /* MAGIC_FLUTE */
/* wav files for sound_Magic_Flute not added yet */
Strcpy(resourcename, "sound_Wooden_Flute");
has_note_variations = TRUE;
pseudo_seid_base = 26;
break;
}
pseudo_seid_base += number_of_se_entries; /* get past se_ entries */
int i, idx = 0, notecount = strlen(str);
static const char *const note_suffixes[]
= { "_A", "_B", "_C", "_D", "_E", "_F", "_G" };
end_of_res = eos(resourcename);
c = str;
for (i = 0; i < notecount; ++i) {
if (*c >= 'A' && *c <= 'G') {
pseudo_seid = pseudo_seid_base;
if (has_note_variations) {
idx = (*c) - 'A';
pseudo_seid += idx;
if (pseudo_seid >= SIZE(affiliation))
break;
Strcpy(end_of_res, note_suffixes[idx]);
}
if (!affiliation[pseudo_seid]) {
affiliate(pseudo_seid, resourcename);
}
if (affiliation[pseudo_seid]) {
if ([seSound[pseudo_seid] isPlaying])
[seSound[pseudo_seid] stop];
[seSound[pseudo_seid] play];
if (i < notecount - 1) {
/* more notes to follow */
msleep(150);
[seSound[pseudo_seid] stop];
}
}
}
c++;
}
#endif
}
/* fulfill SNDCAP_USERSOUNDS */
static void
macsound_play_usersound(char *filename UNUSED, int volume UNUSED, int idx UNUSED)
{
}
static int
affiliate(int32_t seid, const char *soundname)
{
if (!soundname || seid <= se_zero_invalid || seid >= SIZE(affiliation))
return 0;
if (!affiliation[seid]) {
affiliation[seid] = seid;
soundstring[seid] = [NSString stringWithUTF8String:soundname];
seSound[seid] = [NSSound soundNamed:soundstring[seid]];
}
return 1;
}
/* end of macsound.m */