Nasal FAQ

From FlightGear wiki
Jump to navigation Jump to search


This is meant to provide a place for frequently asked questions related to Nasal and related to using Nasal in FlightGear, it's largely inspired by several related discussions on both, the FlightGear forums as well as the FlightGear mailing lists.

What are the major features of Nasal?

(Based on [1] and [2])

Design

  • Designed as an extension language, well suited for embedded applications
  • Nasal can be instructed to run for only a certain number of "cycles" before returning. Later calls will automatically pick up the interpreter state where it left off.
  • Small Interpreter, written in ANSI C, even smaller than lua
  • Nasal's VM uses internally a stack machine model
  • Nasal does not depend on any third party libraries other than the standard C library.
  • Nasal provides optional bindings for libraries such as for example gtk, cairo, regex, readline, sqlite or unix
  • Nasal does not depend on third party tools like (f)lex and yacc/bison.
  • Nasal builds simply and easily, supports a reasonably simple extension API and cohabitates well with other code
  • Nasal is threadsafe
  • Nasal does not use a global interpreter lock (i.e. GIL in Python or Lua)
  • Nasal is stackless for interpreted code
  • Nasal has complete programmatic control over the runtime namespace for any piece of code, making "modules" a question of script coding and allowing a bunch of neat metaprogramming tricks
  • Unicode Support
  • Support for multiple execution contexts and subcontexts

Language

  • Supported Types: Vectors, Hashes and Scalars
  • Literal numbers can be decimal, exponential, or hex constants. All numbers are stored internally as IEEE double-precision values.
  • Nasal supports exception handling as a first-class language feature, with built-in runtime-inspectable stack trace
  • Standard OOP syntax (obj.field) using Hashes
  • Nasal is a true functional language with recursion, lexical scoping, runtime binding, anonymous lambda expressions and true closures.
  • Nasal has a true garbage collector.
  • Nasal's data model matches what you are used to from perl, python and javascript.
  • Nasal has syntax (e.g. based on concepts borrowed from ECMAScript/JavaScript) that makes sense in the modern world and to programmers exposed to other languages like Javascript.

How to play sounds using Nasal script?

This works via property-fgcommands as per $FG_ROOT/Docs/README.commands:

var sound = { 
path : DIRECTORYPATH, 
file : FILENAME , 
volume : VOLUME,
queue : "instant"};# Other optional choices, do not include queue for default, or user defined queue name

fgcommand("play-audio-sample", props.Node.new(sound) );

You'll want to adjust the capital variables with your own path/file name and volume, e.g. using a helper class :

var Sound = { 
# static
default_path: getprop("/sim/fg-root") ~ '/Sounds', 
# constructor
new: func(filename, volume=0.5, path=nil) {
 var m = Props.Node.new({
   path : path or default_path, 
   file : filename , 
   volume : volume 
 });
 return m;
 },# new()
}; # Sound class

fgcommand("play-audio-sample", Sound.new(filename: 'blade_vortex.wav', volume: 0.8) );
# you could put your sound file in the same folder and load it from there, if you aren't using an existing sound:
fgcommand("play-audio-sample", Sound.new(filename: 'mySoundFile.wav', volume: 0.8, path: getprop("/sim/fg-root") ~ '/Aircraft/Foo/Sounds' ) );

The same way one would do animations using Nasal:The current sound model is property-driven. You can create a new sound event (see the *-sound.xml files under Aircraft for examples) and drive it from a given set of properties. You can then set those properties from Nasal.

Adjust properties in Nasal (they may be "private" properties in your own subtree of the property list, say /tmp/<aircraft>) and let the sound configuration file act on those properties. (from flightgear-devel).

If your sounds are aircraft-specific, then the mechanism of putting it into the -sound.xml file is probably exactly what you want. Things like playing sounds from the UI are more problematic from the current interface.

Start with a single beep.wav with an XML definition like:

<sim>
...
<fx>
 ...
 <beep>
  <name>engstart</name>
  <path>Sounds/beep.wav</path>
  <property>/tmp/somewhere/beep</property>
 </beep>

Now you can trigger the beep by toggling the property from false to true. With a little work with settimer(), you can get it to beep with different patterns and frequencies, etc...

For additional information, you'll want to check out $FG_ROOT/Docs/README.xmlsound

Using cmdarg()

cmdarg() returns the listened-to property as props.Node object, so you can use it with all its methods (see $FG_ROOT/Nasal/props.nas), for example:

 print(cmdarg().getPath(), " has been changed to ", cmdarg().getValue())