Audio player

RFO-BASIC! provides an interface to the Android Media Player. This lets a BASIC program play music, podcasts, and stream audio from the Internet.

The file types you can play depend on your device and the version of Android it runs. Here is a partial summary:
 * Supported file types

 

Files of type .PLS cannot be played by the Media Player, unlike some audio programs. These files are not media but playlists. Files of type .3GP (such as those produced by the BASIC sound recorder, can be played back by the Media Player.

For a current list of supported file types, refer to the Android documentation.

Many BASIC programs use the Android Media Player to play music indefinitely while the device is unattended. The BASIC program must continue running; otherwise, Android releases all the resources it used, including the Media Player, and the music stops. The BASIC program can enter an infinite loop where it PAUSEs and occasionally checks for user input to end the play.
 * Stability issues

The behavior of the Media Player differs between Android versions and between makes of Android device. Once your audio application works correctly, you should test it on other versions of Android, and on other makes of device, especially before publishing it for general use.

The Media Player runs in the background using the Android AsyncTask class. This implementation avoids interruptions and warning dialogs. However, your program may stop playing music:
 * If it is in the foreground but the user switches off the display, such as by pressing a hardware button or closing a flip-phone.
 * If the user presses the HOME button and your program does not handle that event with the ONBACKGROUND: interrupt routine.
 * If it is running on a Samsung device that gets plugged into a recharger.

To avoid being interrupted, a music player program can have an ONBACKGROUND: and ONBACKKEY: interrupt handlers. It can use the timer interrupt with a NOTIFY statement, as the Android core will not stop apps that have an active notification. The user may be instructed to use Android developer's settings to select less active power management.

Audio player
The audio player plays audio files. The files can be of a variety of file types; see the start of this article. The program must load audio files into the audio file table (AFT) using AUDIO.LOAD before it can play the files. Each entry in the AFT has a unique index.

AUDIO.LOAD
Gets an audio file for playing

AUDIO.LOAD , 
 * Synopsis

The AUDIO.LOAD statement specifies an audio source, in , and loads it into the AFT so that it can be played. The statement returns, in , the index into the AFT. This number must be used in a subsequent AUDIO.PLAY statement to identify the audio file.
 * Description

The  can be any of the following:
 * The name of a file, which is assumed to reside in the  directory on the device on which RFO-BASIC! is installed (normally, the SD card).
 * The full URL of a podcast or a streaming audio source on the Internet.

If the file or stream cannot be loaded, AUDIO.LOAD sets  to 0. The BASIC program should test this variable to determine if the audio was loaded. If not, GETERROR$ will return information about the error.

AUDIO.LOAD aft1,"Blue Danube Waltz.mp3"
 * Examples

The above statement would load " /rfo-basic/data/Blue Danube Waltz.mp3".

AUDIO.LOAD aft2,"../../Music/Blue Danube Waltz.mp3"

The above statement loads an MP3 file in the Music directory in the visible root of the device on which RFO-BASIC! is installed. Instead of Music, files in the sibling directories Downloads and Podcasts might also be specified.

AUDIO.LENGTH
Get the length of an audio source

AUDIO.LENGTH , 
 * Synopsis

After AUDIO.LOAD puts an audio source into the AFT, the AUDIO.LENGTH statement obtains the length of that audio. The  parameter specifies an AFT entry and AUDIO.LENGTH sets  to its length, in milliseconds.
 * Description

If the specified AFT refers to an Internet audio stream, it does not have a length.

AUDIO.PLAY
Play an audio source

AUDIO.PLAY 
 * Synopsis

The AUDIO.PLAY statement selects one of the audio sources that the program has loaded into the audio file table (AFT) using AUDIO.LOAD and begins to play it.
 * Description

AUDIO.PLAY produces a run-time error if audio is already playing. To avoid this, AUDIO.PLAY can be preceded by AUDIO.STOP.

If the program has used AUDIO.PAUSE to pause play, then calling AUDIO.PLAY resumes play from the point at which it was paused. In this case,  is ignored.
 * Exception — paused audio

AUDIO.RELEASE
Delete an entry from the audio file table

AUDIO.RELEASE 
 * Synopsis

The AUDIO.RELEASE statement releases the resources used by the AFT entry pointed to by . The file must not be currently playing. The specified entry will no longer be playable.
 * Description

Managing play
The BASIC statements that manage the playing of audio do not refer to the AFT. A BASIC program can play only one sound source, and these statements all implicitly refer to that one activity.

AUDIO.ISDONE
Check whether play is complete

AUDIO.ISDONE <done_lvar>
 * Synopsis

If sound is currently playing, then AUDIO.ISDONE sets <done_lvar> to FALSE (0). If playing is complete, it is set to TRUE (1). If the sound selected for playing is an Internet stream, it might never be done.
 * Description

The BASIC program must continue running to keep sound playing. A typical thing to do is wait in a loop for the playing to end.
 * Example

AUDIO.PLAY aft1 DO AUDIO.ISDONE done IF done THEN D_U.BREAK       % Exit DO loop if playing is done IF KeyPressed THEN D_U.BREAK % Perhaps also test a variable set by interrupt handler PAUSE 1000 UNTIL 0                       % Repeat forever unless BREAK takes effect AUDIO.STOP

Other statements in this article let a BASIC audio player pan between the left and right speakers, adjust the volume, sense the current point in the audio (which it might display on the screen), and use a slider on the screen to let the user jump to any desired point in the audio. These operations would typically also be put inside the loop that waits for the player to be done.

AUDIO.STOP
Stop play

AUDIO.STOP
 * Synopsis

The AUDIO.STOP statement terminates the playing of sound. The statement has no effect if sound was not already playing. It is safest to precede any AUDIO.PLAY command with AUDIO.STOP.
 * Description

AUDIO.PAUSE
Pause play

AUDIO.PAUSE
 * Synopsis

The AUDIO.PAUSE statement pauses play. The immediate effect is the same as AUDIO.STOP. However, a subsequent call to AUDIO.PLAY resumes play from the point at which it was paused.
 * Description

AUDIO.LOOP
Set the current audio to auto-repeat

AUDIO.LOOP
 * Synopsis

The AUDIO.LOOP statement sets a mode in which the current audio source auto-repeats. When it reaches end-of-file, it jumps to the start of the file and plays again. There must be audio playing when AUDIO.LOOP is executed.
 * Description

There is no way to clear this mode for the current audio except to execute AUDIO.STOP and restart the audio. If an Internet stream is playing, AUDIO.LOOP has no effect.

AUDIO.POSITION.CURRENT
Get the current position in the audio

AUDIO.POSITION.CURRENT <pos_nvar>
 * Synopsis

The AUDIO.POSITION.CURRENT statement returns, in <pos_nvar>, the current position (in milliseconds past the start of the audio) of the currently playing audio.
 * Description

AUDIO.POSITION.SEEK
Move to a specified position in the audio

AUDIO.POSITION.SEEK <pos_nexp>
 * Synopsis

The AUDIO.POSITION.SEEK statement moves to the location specified by <pos_nexp> in the currently playing audio.
 * Description

The following code executes a 5-second backward jump in an audio file, without jumping before the start of the file.
 * Example

AUDIO.POSITION.CURRENT p LET p = MAX(p - 5000, 0) AUDIO.POSITION.SEEK p

AUDIO.VOLUME
Adjust the playback volume

AUDIO.VOLUME <left_nexp>, <right_nexp>
 * Synopsis

The AUDIO.VOLUME statement changes the playback volume. The <left_nexp> parameter specifies the new volume of the left channel, and <right_nexp> specifies the new volume of the right channel. There must be a currently playing file when this command is executed.
 * Description

If the Android device has only one speaker, the effect is device-specific. The speaker volume may be only one of the specified values, or it may be the average of the two values.

Valid volume levels range between 0.0 (silence) and 1.0 (loudest). The scale is logarithmic. A BASIC program trying to achieve fade-in or fade-out by repeated additions or subtractions will produce an effect where the sound starts or stops suddenly, because the jump from 0.0 to 0.1 is much more drastic than the jump from 0.9 to 1.0. Instead, it should achieve fade-in and fade-out by repeated multiplications or divisions. Multiplying a volume level by 0.89 reduces the volume by 1 dB. (The human ear perceives each 10 dB increase as twice as loud.)

The following program fades out audio smoothly in no more than four seconds:
 * Example

FN.DEF FadeOut(CurrentVolume) DO AUDIO.VOLUME(CurrentVolume, CurrentVolume) PAUSE 100                   % Wait 0.1 second IF KeyPressed THEN FN.RET CurrentVolume % Perhaps abort if var. set by interrupt handler LET CurrentVolume *= 0.89   % Reduce by 1 decibel (caller's variable doesn't change) UNTIL CurrentVolume < 0.01  % Pretty quiet AUDIO.VOLUME(0, 0)           % End in total silence FN.RTN 0                     % Report success (complete silence without user abort)

A program could pre-compute a table of volume levels to map logarithmic volume levels to a slider on the graphic screen. By touching one of 40 zones on the slider, the user would perceive a smooth change in volume.

DIM Vol[40] a = 1.00 FOR i = 1 to 39 Vol[i] = a         % First setting selects full volume a *= 0.89 NEXT i A[40] = 0.00        % Final setting selects total silence

Sound recorder
Additional BASIC statements let you write your own sound recorder. Recording always uses the device's microphone as the source and a file as the destination.

Your sound recorder program should either be simple or monitor its recording mode, as it is a run-time error to start recording if it is already underway, or stop recording if it is already stopped.

AUDIO.RECORD.START
Start recording sound

AUDIO.RECORD.START <filename_sexp>
 * Synopsis

Private version

In OLI-BASIC, AUDIO.RECORD.START permits additional output file types. The AUDIO.RECORD.START statement takes additional optional parameters that govern the recording. Once recording is complete, an AUDIO.RECORD.PEAK statement returns the peak volume level of the recording. </DIV> The AUDIO.RECORD.START statement begins audio recording. The single parameter is a string expression that specifies the name of the file to contain the audio recording. This file must have the file type (the string must end with). The file is created in the  directory on the device on which RFO-BASIC! was installed (normally, the SD card).
 * Description

While the recording is in progress, the BASIC program can take arbitrary action; it can pass time in a PAUSE statement, but it should periodically monitor for user input, such as a screen touch, that is a command to stop recording.

AUDIO.RECORD.STOP
Stop recording sound

AUDIO.RECORD.STOP
 * Synopsis

The AUDIO.RECORD.STOP statement stops recording that had been started using AUDIO.RECORD.START, and closes the  file.
 * Description