1 /* FluidSynth - A Software Synthesizer
2 *
3 * Copyright (C) 2003 Peter Hanappe and others.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License
7 * as published by the Free Software Foundation; either version 2.1 of
8 * the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301, USA
19 */
20
21
22 /*
23 2002 : API design by Peter Hanappe and Antoine Schmitt
24 August 2002 : Implementation by Antoine Schmitt as@gratin.org
25 as part of the infiniteCD author project
26 http://www.infiniteCD.org/
27 Oct4.2002 : AS : corrected bug in heap allocation, that caused a crash during sequencer free.
28 */
29
30
31 #include "fluid_event.h"
32 #include "fluidsynth_priv.h"
33
34 /***************************************************************
35 *
36 * SEQUENCER EVENTS
37 */
38
39 /* Event alloc/free */
40
41 void
fluid_event_clear(fluid_event_t * evt)42 fluid_event_clear(fluid_event_t *evt)
43 {
44 FLUID_MEMSET(evt, 0, sizeof(fluid_event_t));
45
46 // by default, no type
47 evt->dest = -1;
48 evt->src = -1;
49 evt->type = -1;
50 evt->id = -1;
51 }
52
53 /**
54 * Create a new sequencer event structure.
55 * @return New sequencer event structure or NULL if out of memory
56 */
57 fluid_event_t *
new_fluid_event()58 new_fluid_event()
59 {
60 fluid_event_t *evt;
61
62 evt = FLUID_NEW(fluid_event_t);
63
64 if(evt == NULL)
65 {
66 FLUID_LOG(FLUID_PANIC, "event: Out of memory\n");
67 return NULL;
68 }
69
70 fluid_event_clear(evt);
71
72 return(evt);
73 }
74
75 /**
76 * Delete a sequencer event structure.
77 * @param evt Sequencer event structure created by new_fluid_event().
78 */
79 void
delete_fluid_event(fluid_event_t * evt)80 delete_fluid_event(fluid_event_t *evt)
81 {
82 fluid_return_if_fail(evt != NULL);
83
84 FLUID_FREE(evt);
85 }
86
87 /**
88 * Set the time field of a sequencer event.
89 * @internal
90 * @param evt Sequencer event structure
91 * @param time Time value to assign
92 */
93 void
fluid_event_set_time(fluid_event_t * evt,unsigned int time)94 fluid_event_set_time(fluid_event_t *evt, unsigned int time)
95 {
96 evt->time = time;
97 }
98
99 void
fluid_event_set_id(fluid_event_t * evt,fluid_note_id_t id)100 fluid_event_set_id(fluid_event_t *evt, fluid_note_id_t id)
101 {
102 evt->id = id;
103 }
104
105 /**
106 * Set source of a sequencer event. \c src must be a unique sequencer ID or -1 if not set.
107 * @param evt Sequencer event structure
108 * @param src Unique sequencer ID
109 */
110 void
fluid_event_set_source(fluid_event_t * evt,fluid_seq_id_t src)111 fluid_event_set_source(fluid_event_t *evt, fluid_seq_id_t src)
112 {
113 evt->src = src;
114 }
115
116 /**
117 * Set destination of this sequencer event, i.e. the sequencer client this event will be sent to. \c dest must be a unique sequencer ID.
118 * @param evt Sequencer event structure
119 * @param dest The destination unique sequencer ID
120 */
121 void
fluid_event_set_dest(fluid_event_t * evt,fluid_seq_id_t dest)122 fluid_event_set_dest(fluid_event_t *evt, fluid_seq_id_t dest)
123 {
124 evt->dest = dest;
125 }
126
127 /**
128 * Set a sequencer event to be a timer event.
129 * @param evt Sequencer event structure
130 * @param data User supplied data pointer
131 */
132 void
fluid_event_timer(fluid_event_t * evt,void * data)133 fluid_event_timer(fluid_event_t *evt, void *data)
134 {
135 evt->type = FLUID_SEQ_TIMER;
136 evt->data = data;
137 }
138
139 /**
140 * Set a sequencer event to be a note on event.
141 * @param evt Sequencer event structure
142 * @param channel MIDI channel number
143 * @param key MIDI note number (0-127)
144 * @param vel MIDI velocity value (0-127)
145 */
146 void
fluid_event_noteon(fluid_event_t * evt,int channel,short key,short vel)147 fluid_event_noteon(fluid_event_t *evt, int channel, short key, short vel)
148 {
149 evt->type = FLUID_SEQ_NOTEON;
150 evt->channel = channel;
151 evt->key = key;
152 evt->vel = vel;
153 }
154
155 /**
156 * Set a sequencer event to be a note off event.
157 * @param evt Sequencer event structure
158 * @param channel MIDI channel number
159 * @param key MIDI note number (0-127)
160 */
161 void
fluid_event_noteoff(fluid_event_t * evt,int channel,short key)162 fluid_event_noteoff(fluid_event_t *evt, int channel, short key)
163 {
164 evt->type = FLUID_SEQ_NOTEOFF;
165 evt->channel = channel;
166 evt->key = key;
167 }
168
169 /**
170 * Set a sequencer event to be a note duration event.
171 *
172 * Before fluidsynth 2.2.0, this event type was naively implemented when used in conjunction with fluid_sequencer_register_fluidsynth(),
173 * because it simply enqueued a fluid_event_noteon() and fluid_event_noteoff().
174 * A handling for overlapping notes was not implemented. Starting with 2.2.0, this changes: If a fluid_event_note() is already playing,
175 * while another fluid_event_note() arrives on the same @c channel and @c key, the earlier event will be canceled.
176 * @param evt Sequencer event structure
177 * @param channel MIDI channel number
178 * @param key MIDI note number (0-127)
179 * @param vel MIDI velocity value (0-127)
180 * @param duration Duration of note in the time scale used by the sequencer (by default milliseconds)
181 *
182 * @note The application should decide whether to use only Notes with duration, or separate NoteOn and NoteOff events.
183 */
184 void
fluid_event_note(fluid_event_t * evt,int channel,short key,short vel,unsigned int duration)185 fluid_event_note(fluid_event_t *evt, int channel, short key, short vel, unsigned int duration)
186 {
187 evt->type = FLUID_SEQ_NOTE;
188 evt->channel = channel;
189 evt->key = key;
190 evt->vel = vel;
191 evt->duration = duration;
192 }
193
194 /**
195 * Set a sequencer event to be an all sounds off event.
196 * @param evt Sequencer event structure
197 * @param channel MIDI channel number
198 */
199 void
fluid_event_all_sounds_off(fluid_event_t * evt,int channel)200 fluid_event_all_sounds_off(fluid_event_t *evt, int channel)
201 {
202 evt->type = FLUID_SEQ_ALLSOUNDSOFF;
203 evt->channel = channel;
204 }
205
206 /**
207 * Set a sequencer event to be a all notes off event.
208 * @param evt Sequencer event structure
209 * @param channel MIDI channel number
210 */
211 void
fluid_event_all_notes_off(fluid_event_t * evt,int channel)212 fluid_event_all_notes_off(fluid_event_t *evt, int channel)
213 {
214 evt->type = FLUID_SEQ_ALLNOTESOFF;
215 evt->channel = channel;
216 }
217
218 /**
219 * Set a sequencer event to be a bank select event.
220 * @param evt Sequencer event structure
221 * @param channel MIDI channel number
222 * @param bank_num MIDI bank number (0-16383)
223 */
224 void
fluid_event_bank_select(fluid_event_t * evt,int channel,short bank_num)225 fluid_event_bank_select(fluid_event_t *evt, int channel, short bank_num)
226 {
227 evt->type = FLUID_SEQ_BANKSELECT;
228 evt->channel = channel;
229 evt->control = bank_num;
230 }
231
232 /**
233 * Set a sequencer event to be a program change event.
234 * @param evt Sequencer event structure
235 * @param channel MIDI channel number
236 * @param val MIDI program number (0-127)
237 */
238 void
fluid_event_program_change(fluid_event_t * evt,int channel,int val)239 fluid_event_program_change(fluid_event_t *evt, int channel, int val)
240 {
241 evt->type = FLUID_SEQ_PROGRAMCHANGE;
242 evt->channel = channel;
243 evt->value = val;
244 }
245
246 /**
247 * Set a sequencer event to be a program select event.
248 * @param evt Sequencer event structure
249 * @param channel MIDI channel number
250 * @param sfont_id SoundFont ID number
251 * @param bank_num MIDI bank number (0-16383)
252 * @param preset_num MIDI preset number (0-127)
253 */
254 void
fluid_event_program_select(fluid_event_t * evt,int channel,unsigned int sfont_id,short bank_num,short preset_num)255 fluid_event_program_select(fluid_event_t *evt, int channel,
256 unsigned int sfont_id, short bank_num, short preset_num)
257 {
258 evt->type = FLUID_SEQ_PROGRAMSELECT;
259 evt->channel = channel;
260 evt->duration = sfont_id;
261 evt->value = preset_num;
262 evt->control = bank_num;
263 }
264
265 /**
266 * Set a sequencer event to be a pitch bend event.
267 * @param evt Sequencer event structure
268 * @param channel MIDI channel number
269 * @param pitch MIDI pitch bend value (0-16383, 8192 = no bend)
270 */
271 void
fluid_event_pitch_bend(fluid_event_t * evt,int channel,int pitch)272 fluid_event_pitch_bend(fluid_event_t *evt, int channel, int pitch)
273 {
274 evt->type = FLUID_SEQ_PITCHBEND;
275 evt->channel = channel;
276
277 if(pitch < 0)
278 {
279 pitch = 0;
280 }
281
282 if(pitch > 16383)
283 {
284 pitch = 16383;
285 }
286
287 evt->pitch = pitch;
288 }
289
290 /**
291 * Set a sequencer event to be a pitch wheel sensitivity event.
292 * @param evt Sequencer event structure
293 * @param channel MIDI channel number
294 * @param value MIDI pitch wheel sensitivity value in semitones
295 */
296 void
fluid_event_pitch_wheelsens(fluid_event_t * evt,int channel,int value)297 fluid_event_pitch_wheelsens(fluid_event_t *evt, int channel, int value)
298 {
299 evt->type = FLUID_SEQ_PITCHWHEELSENS;
300 evt->channel = channel;
301 evt->value = value;
302 }
303
304 /**
305 * Set a sequencer event to be a modulation event.
306 * @param evt Sequencer event structure
307 * @param channel MIDI channel number
308 * @param val MIDI modulation value (0-127)
309 */
310 void
fluid_event_modulation(fluid_event_t * evt,int channel,int val)311 fluid_event_modulation(fluid_event_t *evt, int channel, int val)
312 {
313 evt->type = FLUID_SEQ_MODULATION;
314 evt->channel = channel;
315
316 if(val < 0)
317 {
318 val = 0;
319 }
320
321 if(val > 127)
322 {
323 val = 127;
324 }
325
326 evt->value = val;
327 }
328
329 /**
330 * Set a sequencer event to be a MIDI sustain event.
331 * @param evt Sequencer event structure
332 * @param channel MIDI channel number
333 * @param val MIDI sustain value (0-127)
334 */
335 void
fluid_event_sustain(fluid_event_t * evt,int channel,int val)336 fluid_event_sustain(fluid_event_t *evt, int channel, int val)
337 {
338 evt->type = FLUID_SEQ_SUSTAIN;
339 evt->channel = channel;
340
341 if(val < 0)
342 {
343 val = 0;
344 }
345
346 if(val > 127)
347 {
348 val = 127;
349 }
350
351 evt->value = val;
352 }
353
354 /**
355 * Set a sequencer event to be a MIDI control change event.
356 * @param evt Sequencer event structure
357 * @param channel MIDI channel number
358 * @param control MIDI control number (0-127)
359 * @param val MIDI control value (0-127)
360 */
361 void
fluid_event_control_change(fluid_event_t * evt,int channel,short control,int val)362 fluid_event_control_change(fluid_event_t *evt, int channel, short control, int val)
363 {
364 evt->type = FLUID_SEQ_CONTROLCHANGE;
365 evt->channel = channel;
366 evt->control = control;
367 evt->value = val;
368 }
369
370 /**
371 * Set a sequencer event to be a stereo pan event.
372 * @param evt Sequencer event structure
373 * @param channel MIDI channel number
374 * @param val MIDI panning value (0-127, 0=left, 64 = middle, 127 = right)
375 */
376 void
fluid_event_pan(fluid_event_t * evt,int channel,int val)377 fluid_event_pan(fluid_event_t *evt, int channel, int val)
378 {
379 evt->type = FLUID_SEQ_PAN;
380 evt->channel = channel;
381
382 if(val < 0)
383 {
384 val = 0;
385 }
386
387 if(val > 127)
388 {
389 val = 127;
390 }
391
392 evt->value = val;
393 }
394
395 /**
396 * Set a sequencer event to be a volume event.
397 * @param evt Sequencer event structure
398 * @param channel MIDI channel number
399 * @param val Volume value (0-127)
400 */
401 void
fluid_event_volume(fluid_event_t * evt,int channel,int val)402 fluid_event_volume(fluid_event_t *evt, int channel, int val)
403 {
404 evt->type = FLUID_SEQ_VOLUME;
405 evt->channel = channel;
406
407 if(val < 0)
408 {
409 val = 0;
410 }
411
412 if(val > 127)
413 {
414 val = 127;
415 }
416
417 evt->value = val;
418 }
419
420 /**
421 * Set a sequencer event to be a reverb send event.
422 * @param evt Sequencer event structure
423 * @param channel MIDI channel number
424 * @param val Reverb amount (0-127)
425 */
426 void
fluid_event_reverb_send(fluid_event_t * evt,int channel,int val)427 fluid_event_reverb_send(fluid_event_t *evt, int channel, int val)
428 {
429 evt->type = FLUID_SEQ_REVERBSEND;
430 evt->channel = channel;
431
432 if(val < 0)
433 {
434 val = 0;
435 }
436
437 if(val > 127)
438 {
439 val = 127;
440 }
441
442 evt->value = val;
443 }
444
445 /**
446 * Set a sequencer event to be a chorus send event.
447 * @param evt Sequencer event structure
448 * @param channel MIDI channel number
449 * @param val Chorus amount (0-127)
450 */
451 void
fluid_event_chorus_send(fluid_event_t * evt,int channel,int val)452 fluid_event_chorus_send(fluid_event_t *evt, int channel, int val)
453 {
454 evt->type = FLUID_SEQ_CHORUSSEND;
455 evt->channel = channel;
456
457 if(val < 0)
458 {
459 val = 0;
460 }
461
462 if(val > 127)
463 {
464 val = 127;
465 }
466
467 evt->value = val;
468 }
469
470
471 /**
472 * Set a sequencer event to be an unregistering event.
473 * @param evt Sequencer event structure
474 * @since 1.1.0
475 */
476 void
fluid_event_unregistering(fluid_event_t * evt)477 fluid_event_unregistering(fluid_event_t *evt)
478 {
479 evt->type = FLUID_SEQ_UNREGISTERING;
480 }
481
482 /**
483 * Set a sequencer event to be a scale change event.
484 * Useful for scheduling tempo changes.
485 * @param evt Sequencer event structure
486 * @param new_scale The new time scale to apply to the sequencer, see fluid_sequencer_set_time_scale()
487 * @since 2.2.0
488 */
489 void
fluid_event_scale(fluid_event_t * evt,double new_scale)490 fluid_event_scale(fluid_event_t *evt, double new_scale)
491 {
492 evt->type = FLUID_SEQ_SCALE;
493 evt->scale = new_scale;
494 }
495
496 /**
497 * Set a sequencer event to be a channel-wide aftertouch event.
498 * @param evt Sequencer event structure
499 * @param channel MIDI channel number
500 * @param val Aftertouch amount (0-127)
501 * @since 1.1.0
502 */
503 void
fluid_event_channel_pressure(fluid_event_t * evt,int channel,int val)504 fluid_event_channel_pressure(fluid_event_t *evt, int channel, int val)
505 {
506 evt->type = FLUID_SEQ_CHANNELPRESSURE;
507 evt->channel = channel;
508
509 if(val < 0)
510 {
511 val = 0;
512 }
513
514 if(val > 127)
515 {
516 val = 127;
517 }
518
519 evt->value = val;
520 }
521
522 /**
523 * Set a sequencer event to be a polyphonic aftertouch event.
524 * @param evt Sequencer event structure
525 * @param channel MIDI channel number
526 * @param key MIDI note number (0-127)
527 * @param val Aftertouch amount (0-127)
528 * @since 2.0.0
529 */
530 void
fluid_event_key_pressure(fluid_event_t * evt,int channel,short key,int val)531 fluid_event_key_pressure(fluid_event_t *evt, int channel, short key, int val)
532 {
533 evt->type = FLUID_SEQ_KEYPRESSURE;
534 evt->channel = channel;
535
536 if(key < 0)
537 {
538 key = 0;
539 }
540
541 if(key > 127)
542 {
543 key = 127;
544 }
545
546 if(val < 0)
547 {
548 val = 0;
549 }
550
551 if(val > 127)
552 {
553 val = 127;
554 }
555
556 evt->key = key;
557 evt->value = val;
558 }
559
560 /**
561 * Set a sequencer event to be a midi system reset event.
562 * @param evt Sequencer event structure
563 * @since 1.1.0
564 */
565 void
fluid_event_system_reset(fluid_event_t * evt)566 fluid_event_system_reset(fluid_event_t *evt)
567 {
568 evt->type = FLUID_SEQ_SYSTEMRESET;
569 }
570
571
572
573 /*
574 * Accessing event data
575 */
576
577 /**
578 * Get the event type (#fluid_seq_event_type) field from a sequencer event structure.
579 * @param evt Sequencer event structure
580 * @return Event type (#fluid_seq_event_type).
581 */
fluid_event_get_type(fluid_event_t * evt)582 int fluid_event_get_type(fluid_event_t *evt)
583 {
584 return evt->type;
585 }
586
587 /**
588 * @internal
589 * Get the time field from a sequencer event structure.
590 * @param evt Sequencer event structure
591 * @return Time value
592 */
fluid_event_get_time(fluid_event_t * evt)593 unsigned int fluid_event_get_time(fluid_event_t *evt)
594 {
595 return evt->time;
596 }
597
598 /**
599 * @internal
600 * Get the time field from a sequencer event structure.
601 * @param evt Sequencer event structure
602 * @return Time value
603 */
fluid_event_get_id(fluid_event_t * evt)604 fluid_note_id_t fluid_event_get_id(fluid_event_t *evt)
605 {
606 return evt->id;
607 }
608
609 /**
610 * Get the source sequencer client from a sequencer event structure.
611 * @param evt Sequencer event structure
612 * @return source field of the sequencer event
613 */
fluid_event_get_source(fluid_event_t * evt)614 fluid_seq_id_t fluid_event_get_source(fluid_event_t *evt)
615 {
616 return evt->src;
617 }
618
619 /**
620 * Get the dest sequencer client from a sequencer event structure.
621 * @param evt Sequencer event structure
622 * @return dest field of the sequencer event
623 */
fluid_event_get_dest(fluid_event_t * evt)624 fluid_seq_id_t fluid_event_get_dest(fluid_event_t *evt)
625 {
626 return evt->dest;
627 }
628
629 /**
630 * Get the MIDI channel field from a sequencer event structure.
631 * @param evt Sequencer event structure
632 * @return MIDI zero-based channel number
633 */
fluid_event_get_channel(fluid_event_t * evt)634 int fluid_event_get_channel(fluid_event_t *evt)
635 {
636 return evt->channel;
637 }
638
639 /**
640 * Get the MIDI note field from a sequencer event structure.
641 * @param evt Sequencer event structure
642 * @return MIDI note number (0-127)
643 */
fluid_event_get_key(fluid_event_t * evt)644 short fluid_event_get_key(fluid_event_t *evt)
645 {
646 return evt->key;
647 }
648
649 /**
650 * Get the MIDI velocity field from a sequencer event structure.
651 * @param evt Sequencer event structure
652 * @return MIDI velocity value (0-127)
653 */
fluid_event_get_velocity(fluid_event_t * evt)654 short fluid_event_get_velocity(fluid_event_t *evt)
655
656 {
657 return evt->vel;
658 }
659
660 /**
661 * Get the MIDI control number field from a sequencer event structure.
662 * @param evt Sequencer event structure
663 * @return MIDI control number (0-127)
664 */
fluid_event_get_control(fluid_event_t * evt)665 short fluid_event_get_control(fluid_event_t *evt)
666 {
667 return evt->control;
668 }
669
670 /**
671 * Get the value field from a sequencer event structure.
672 * @param evt Sequencer event structure
673 * @return Value field of event.
674 *
675 * The Value field is used by the following event types:
676 * #FLUID_SEQ_PROGRAMCHANGE, #FLUID_SEQ_PROGRAMSELECT (preset_num),
677 * #FLUID_SEQ_PITCHWHEELSENS, #FLUID_SEQ_MODULATION, #FLUID_SEQ_SUSTAIN,
678 * #FLUID_SEQ_CONTROLCHANGE, #FLUID_SEQ_PAN, #FLUID_SEQ_VOLUME,
679 * #FLUID_SEQ_REVERBSEND, #FLUID_SEQ_CHORUSSEND.
680 */
fluid_event_get_value(fluid_event_t * evt)681 int fluid_event_get_value(fluid_event_t *evt)
682 {
683 return evt->value;
684 }
685
686 /**
687 * Get the data field from a sequencer event structure.
688 * @param evt Sequencer event structure
689 * @return Data field of event.
690 *
691 * Used by the #FLUID_SEQ_TIMER event type.
692 */
fluid_event_get_data(fluid_event_t * evt)693 void *fluid_event_get_data(fluid_event_t *evt)
694 {
695 return evt->data;
696 }
697
698 /**
699 * Get the duration field from a sequencer event structure.
700 * @param evt Sequencer event structure
701 * @return Note duration value in the time scale used by the sequencer (by default milliseconds)
702 *
703 * Used by the #FLUID_SEQ_NOTE event type.
704 */
fluid_event_get_duration(fluid_event_t * evt)705 unsigned int fluid_event_get_duration(fluid_event_t *evt)
706 {
707 return evt->duration;
708 }
709
710 /**
711 * Get the MIDI bank field from a sequencer event structure.
712 * @param evt Sequencer event structure
713 * @return MIDI bank number (0-16383)
714 *
715 * Used by the #FLUID_SEQ_BANKSELECT and #FLUID_SEQ_PROGRAMSELECT
716 * event types.
717 */
fluid_event_get_bank(fluid_event_t * evt)718 short fluid_event_get_bank(fluid_event_t *evt)
719 {
720 return evt->control;
721 }
722
723 /**
724 * Get the pitch field from a sequencer event structure.
725 * @param evt Sequencer event structure
726 * @return MIDI pitch bend pitch value (0-16383, 8192 = no bend)
727 *
728 * Used by the #FLUID_SEQ_PITCHBEND event type.
729 */
fluid_event_get_pitch(fluid_event_t * evt)730 int fluid_event_get_pitch(fluid_event_t *evt)
731 {
732 return evt->pitch;
733 }
734
735 /**
736 * Get the MIDI program field from a sequencer event structure.
737 * @param evt Sequencer event structure
738 * @return MIDI program number (0-127)
739 *
740 * Used by the #FLUID_SEQ_PROGRAMCHANGE and #FLUID_SEQ_PROGRAMSELECT
741 * event types.
742 */
743 int
fluid_event_get_program(fluid_event_t * evt)744 fluid_event_get_program(fluid_event_t *evt)
745 {
746 return evt->value;
747 }
748
749 /**
750 * Get the SoundFont ID field from a sequencer event structure.
751 * @param evt Sequencer event structure
752 * @return SoundFont identifier value.
753 *
754 * Used by the #FLUID_SEQ_PROGRAMSELECT event type.
755 */
756 unsigned int
fluid_event_get_sfont_id(fluid_event_t * evt)757 fluid_event_get_sfont_id(fluid_event_t *evt)
758 {
759 return evt->duration;
760 }
761
762 /**
763 * Gets time scale field from a sequencer event structure.
764 * @param evt Sequencer event structure
765 * @return SoundFont identifier value.
766 *
767 * Used by the #FLUID_SEQ_SCALE event type.
768 */
fluid_event_get_scale(fluid_event_t * evt)769 double fluid_event_get_scale(fluid_event_t *evt)
770 {
771 return evt->scale;
772 }
773