Free Hero Mesh

Check-in [45529d48c7]
Login
This is a mirror of the main repository for Free Hero Mesh. New tickets and changes will not be accepted at this mirror.
Overview
Comment:Some more fixes of sound effect including a few of documentation
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 45529d48c7e771e717cd9cf80cb8108afd763977
User & Date: user on 2022-01-16 03:11:51
Other Links: manifest | tags
Context
2022-01-20
06:37
Explain the "Attempt to use a nonexistent object" error when attempting to move a Sliding Door after one side has been destroyed. check-in: 1977494fc3 user: user tags: trunk
2022-01-16
03:11
Some more fixes of sound effect including a few of documentation check-in: 45529d48c7 user: user tags: trunk
2022-01-15
05:59
Implement the user sounds (uncompressed) and MML sounds; does not work in the game yet, and built-in sounds are not yet implemented. check-in: 5c902e7a3f user: user tags: trunk
Changes

Modified class.doc from [d18040badb] to [e20d997f8f].

2717
2718
2719
2720
2721
2722
2723
















































treated as signed or unsigned according to the column type.

* The stack contains one or more items, of which the first (bottom) one is
a string: Concatenates all of them together, which can be strings, numbers
(treated as unsigned), or classes. All formatting codes of strings will be
stripped, so that the result will be a unformatted string.
























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
treated as signed or unsigned according to the column type.

* The stack contains one or more items, of which the first (bottom) one is
a string: Concatenates all of them together, which can be strings, numbers
(treated as unsigned), or classes. All formatting codes of strings will be
stripped, so that the result will be a unformatted string.


=== MML sound effects ===

The MML sound effects are similar to ZZT and MegaZeux. It is a string
consisting of the commands listed below (case-insensitive):

A B C D E F G
  Play a note of the current length and octave; notes outside of the range
  of a 88-key piano are not valid, but the quarter tones are possible. It
  can be followed by zero or more of the following signs:
  ! flat
  , half flat
  ' half sharp
  # sharp

X
  Play a silenced rest of the current note length.

W H Q I S T Z
  Set the note length to one of the predefined note lengths, where W means
  a whole note, the other letters are successively half until Z which means
  a sixty-fourth note, which is the shortest possible note.

.
  Multiply note length by 3/2.

0 1 2 3 4 5 6 7
  Set the octave to a specified number. Note that notes lower than A are
  not valid for octave zero.

-
  Low octave.

+
  High octave.

L
  Set note length to a following number of sixty-fourth notes.

N
  Play a note with the following note number, and the current length. The
  note number 0 is the lowest piano note, and then each next key on the
  piano is 2 more than the previous one (odd numbers are used for quarter
  tones that are not on a standard piano). Numbers 190 and higher are used
  for overtone notes; subtract 188 for the overtone number (although note
  that overtone numbers 0 and 1 are not usable).

(Note that this is not the same as standard MML.)

Modified config.doc from [8852ef9b47] to [6c9a4775e5].

26
27
28
29
30
31
32
33

34
35
36

37
38
39
40
41
42
43
  work at all, this value must be set.

.audio.mmlTempo
  Define the number of quarter notes per minute. The default is 120.

.audio.mmlTuning
  The MML tuning of the A4 note, in Hz. The default is 440 Hz, but some
  people do not like that tuning, so you can change it.


.audio.mmlVolume
  MML volume, from 0 to 1; fractions are allowed. The default value is 1.


.audio.rate
  Sample rate to use for audio, in hertz. In order for audio to work at
  all, this value must be set.

.audio.waveVolume
  Wave volume, from 0 to 1; fractions are allowed. The default value is 1.







|
>


|
>







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
  work at all, this value must be set.

.audio.mmlTempo
  Define the number of quarter notes per minute. The default is 120.

.audio.mmlTuning
  The MML tuning of the A4 note, in Hz. The default is 440 Hz, but some
  people do not like that tuning, so you can change it. This setting only
  affects 24-TET sounds, and not overtone-based sounds.

.audio.mmlVolume
  MML volume, from 0 to 1; fractions are allowed. The default value is
  approximately one third.

.audio.rate
  Sample rate to use for audio, in hertz. In order for audio to work at
  all, this value must be set.

.audio.waveVolume
  Wave volume, from 0 to 1; fractions are allowed. The default value is 1.

Modified puzzleset.doc from [33868fdaba] to [3c2ca8d4bf].

39
40
41
42
43
44
45
46

47
48
49
50
51
52
53
picture; the loader will select one based on the user's criteria.

The DEP lumps are dependent pictures; each one references one or more IMG
lumps, and specifies how to modify them to produce the new picture (e.g.
by rotating, mirroring, changing colours, etc).

The WAV lumps are sound effects. Each is a RIFF WAVE file; it must be of
a type which can be loaded by SDL. (This is currently not used.)


The PICEDIT.CFG lump stores the configuration for the picture editor. It
can safely be deleted.


=== Class definition file ===








|
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
picture; the loader will select one based on the user's criteria.

The DEP lumps are dependent pictures; each one references one or more IMG
lumps, and specifies how to modify them to produce the new picture (e.g.
by rotating, mirroring, changing colours, etc).

The WAV lumps are sound effects. Each is a RIFF WAVE file; it must be of
a type which can be loaded by SDL. Lumps can also be WZV if it is a
compressed audio file, but compressed audio is not currently implemented.

The PICEDIT.CFG lump stores the configuration for the picture editor. It
can safely be deleted.


=== Class definition file ===

Modified sound.c from [045a5b4883] to [c480308e9b].

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

typedef struct {
  Uint8*data;
  Uint32 len; // length in bytes
} WaveSound;

static Uint8 sound_on;
static Sint16 mmlvolume=9001;
static SDL_AudioSpec spec;
static WaveSound*standardsounds;
static Uint16 nstandardsounds;
static WaveSound*usersounds;
static Uint16 nusersounds;
static Uint8**user_sound_names;
static FILE*l_fp;







|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

typedef struct {
  Uint8*data;
  Uint32 len; // length in bytes
} WaveSound;

static Uint8 sound_on;
static Sint16 mmlvolume=10000;
static SDL_AudioSpec spec;
static WaveSound*standardsounds;
static Uint16 nstandardsounds;
static WaveSound*usersounds;
static Uint16 nusersounds;
static Uint8**user_sound_names;
static FILE*l_fp;
257
258
259
260
261
262
263
264

265
266
267
268
269
270
271
  }
  if(mmlvolume) {
    mmltuning=malloc(256*sizeof(Uint32));
    if(!mmltuning) fatal("Allocation failed\n");
    optionquery[2]=Q_mmlTuning;
    if(v=xrm_get_resource(resourcedb,optionquery,optionquery,3)) f=strtod(v,0); else f=440.0;
    f*=0x80000000U/(double)spec.freq;
    for(i=0;i<256;i++) mmltuning[i]=f*pow(2.0,(i-96)/24.0);

    optionquery[2]=Q_mmlTempo;
    if(v=xrm_get_resource(resourcedb,optionquery,optionquery,3)) i=strtol(v,0,10); else i=120;
    // Convert quarter notes per minute to samples per sixty-fourth note
    mmltempo=(spec.freq*60)/(i*16);
  }
  fprintf(stderr,"Done.\n");
  wavesound=0;







|
>







257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
  }
  if(mmlvolume) {
    mmltuning=malloc(256*sizeof(Uint32));
    if(!mmltuning) fatal("Allocation failed\n");
    optionquery[2]=Q_mmlTuning;
    if(v=xrm_get_resource(resourcedb,optionquery,optionquery,3)) f=strtod(v,0); else f=440.0;
    f*=0x80000000U/(double)spec.freq;
    for(i=0;i<190;i++) mmltuning[i]=f*pow(2.0,(i-96)/24.0);
    for(i=0;i<64;i++) mmltuning[i+190]=(((long long)(i+2))<<37)/spec.freq;
    optionquery[2]=Q_mmlTempo;
    if(v=xrm_get_resource(resourcedb,optionquery,optionquery,3)) i=strtol(v,0,10); else i=120;
    // Convert quarter notes per minute to samples per sixty-fourth note
    mmltempo=(spec.freq*60)/(i*16);
  }
  fprintf(stderr,"Done.\n");
  wavesound=0;
319
320
321
322
323
324
325
326
327
328
329
330




331
332
333
334
335
336
337
  if(!m) return;
  if(m<511) mmlsound[m+1]=0;
  mmlpos=1;
  mmltime=mmlsound[1]*mmltempo;
}

void set_sound_effect(Value v1,Value v2) {
  static const unsigned char*const builtin[4]={
    "s.g",
    "scdefgab+c-bagfedc-c",
    "i1c+c+c+c+c+c+c",
    "-cc'c#d,dd'd#ee'ff'f#",




  };
  const unsigned char*s;
  if(!sound_on) return;
  if(!v2.t && !v2.u && (mmlpos || wavesound)) return;
  SDL_LockAudio();
  wavesound=0;
  mmlpos=0;







|


|

>
>
>
>







320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
  if(!m) return;
  if(m<511) mmlsound[m+1]=0;
  mmlpos=1;
  mmltime=mmlsound[1]*mmltempo;
}

void set_sound_effect(Value v1,Value v2) {
  static const unsigned char*const builtin[8]={
    "s.g",
    "scdefgab+c-bagfedc-c",
    "i1c+c+c+c+c+c+cx",
    "-cc'c#d,dd'd#ee'ff'f#",
    "sn190n191n192n193n194n195n196n197n198n199n200n201n202n203n204n205n206n207n208n209n210",
    "z+c-gec-gec",
    "t+c-gec",
    "tc-c+d-d+e-e+f-f+g-g",
  };
  const unsigned char*s;
  if(!sound_on) return;
  if(!v2.t && !v2.u && (mmlpos || wavesound)) return;
  SDL_LockAudio();
  wavesound=0;
  mmlpos=0;
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
    case TY_STRING: case TY_LEVELSTRING:
      if(!mmlvolume) break;
      if(s=value_string_ptr(v1)) set_mml(s);
      break;
    case TY_FOR:
      // (only used for the sound test)
      if(!mmlvolume) break;
      set_mml(builtin[v1.u&3]);
      break;
  }
  SDL_UnlockAudio();
}

Uint16 find_user_sound(const char*name) {
  int i;







|







356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
    case TY_STRING: case TY_LEVELSTRING:
      if(!mmlvolume) break;
      if(s=value_string_ptr(v1)) set_mml(s);
      break;
    case TY_FOR:
      // (only used for the sound test)
      if(!mmlvolume) break;
      set_mml(builtin[v1.u&7]);
      break;
  }
  SDL_UnlockAudio();
}

Uint16 find_user_sound(const char*name) {
  int i;
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
  char buf[256];
  if(main_options['T'] && main_options['v']) {
    if(mmltuning) printf("mmltempo=%d; mmlvolume=%d; mmltuning[96]=%d\n",(int)mmltempo,(int)mmlvolume,(int)mmltuning[96]);
    for(i=0;i<nusersounds;i++) printf("%d: %s (ptr=%p, len=%d bytes)\n",i,user_sound_names[i],usersounds[i].data,usersounds[i].len);
    fflush(stdout);
  }
  if(!screen) return;
  nitems=nusersounds+4;
  columns=(screen->w-16)/240?:1;
  scrmax=(nitems+columns-1)/columns;
  set_cursor(XC_arrow);
  redraw:
  SDL_FillRect(screen,0,0x02);
  r.x=r.y=0;
  r.w=screen->w;







|







390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
  char buf[256];
  if(main_options['T'] && main_options['v']) {
    if(mmltuning) printf("mmltempo=%d; mmlvolume=%d; mmltuning[96]=%d\n",(int)mmltempo,(int)mmlvolume,(int)mmltuning[96]);
    for(i=0;i<nusersounds;i++) printf("%d: %s (ptr=%p, len=%d bytes)\n",i,user_sound_names[i],usersounds[i].data,usersounds[i].len);
    fflush(stdout);
  }
  if(!screen) return;
  nitems=nusersounds+8;
  columns=(screen->w-16)/240?:1;
  scrmax=(nitems+columns-1)/columns;
  set_cursor(XC_arrow);
  redraw:
  SDL_FillRect(screen,0,0x02);
  r.x=r.y=0;
  r.w=screen->w;