[FFmpeg-soc] [soc] libavsequencer [PATCH 04/08] Track / pattern handling public API header file.

Vitor Sessak vitor1001 at gmail.com
Tue Jul 13 12:43:02 CEST 2010


On 07/11/2010 10:07 PM, Sebastian Vater wrote:
> Michael Niedermayer a écrit :
>> i guess alot of these #defines could be enums and then the correct types
>> could be used instead of int*_t
>>
>> [...]
>>
>
> Hi Michael! I will change them the next days, this will incorporate a
> lot of changes to player.c also. Anyway, I have updated track.h, so new
> patch attached anyway.

> /*
>  * AVSequencer track and pattern management
>  * Copyright (c) 2010 Sebastian Vater <cdgs.basty at googlemail.com>
>  *
>  * This file is part of FFmpeg.
>  *
>  * FFmpeg is free software; you can redistribute it and/or
>  * modify it under the terms of the GNU Lesser General Public
>  * License as published by the Free Software Foundation; either
>  * version 2.1 of the License, or (at your option) any later version.
>  *
>  * FFmpeg is distributed in the hope that it will be useful,
>  * but WITHOUT ANY WARRANTY; without even the implied warranty of
>  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>  * Lesser General Public License for more details.
>  *
>  * You should have received a copy of the GNU Lesser General Public
>  * License along with FFmpeg; if not, write to the Free Software
>  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>  */
>
> #ifndef AVSEQUENCER_TRACK_H
> #define AVSEQUENCER_TRACK_H
>
> #include "libavformat/avformat.h"
> #include "libavsequencer/avsequencer.h"
>
> /**
>  * Song track data structure, This structure is actually for one row
>  * and therefore actually pointed as an array with the amount of
>  * rows of the whole track.
>  * New fields can be added to the end with minor version bumps.
>  * Removal, reordering and changes to existing fields require a major
>  * version bump.
>  */
> typedef struct AVSequencerTrackData {
>     /** Array of pointers containing all effects used by this
>        track.  */
>     AVSequencerTrack **effects_data;
>
>     /** Which octave the note is played upon, if note is a
>        positive value (defaults to 4).  */
>     uint8_t octave;
> #define AVSEQ_TRACK_DATA_OCTAVE     4
> #define AVSEQ_TRACK_DATA_OCTAVE_MIN 0
> #define AVSEQ_TRACK_DATA_OCTAVE_MAX 9

Those MAX/MIN are characteristics of the player, no? So...

>     /** Note to be played (see defines below, n is octave number).  */
>     int8_t note;
>     /** C-n  */
> #define AVSEQ_TRACK_DATA_NOTE           1
> #define AVSEQ_TRACK_DATA_NOTE_C         1
> #define AVSEQ_TRACK_DATA_NOTE_MIN       AVSEQ_TRACK_DATA_NOTE_MIN
>
>     /** C#n = Dbn  */
> #define AVSEQ_TRACK_DATA_NOTE_C_SHARP   2
>
>     /** D-n  */
> #define AVSEQ_TRACK_DATA_NOTE_D         3
>
>     /** D#n = Ebn  */
> #define AVSEQ_TRACK_DATA_NOTE_D_SHARP   4
>
>     /** E-n  */
> #define AVSEQ_TRACK_DATA_NOTE_E         5
>
>     /** F-n  */
> #define AVSEQ_TRACK_DATA_NOTE_F         6
>
>     /** F#n = Gbn  */
> #define AVSEQ_TRACK_DATA_NOTE_F_SHARP   7
>
>     /** G-n  */
> #define AVSEQ_TRACK_DATA_NOTE_G         8
>
>     /** G#n = Abn  */
> #define AVSEQ_TRACK_DATA_NOTE_G_SHARP   9
>
>     /** A-n  */
> #define AVSEQ_TRACK_DATA_NOTE_A         10
>
>     /** A#n = Bbn  */
> #define AVSEQ_TRACK_DATA_NOTE_A_SHARP   11
>
>     /** B-n = H-n  */
> #define AVSEQ_TRACK_DATA_NOTE_B         12
> #define AVSEQ_TRACK_DATA_NOTE_H         FF_AVSEQ_TRACK_DATA_NOTE_B
> #define AVSEQ_TRACK_DATA_NOTE_MAX       FF_AVSEQ_TRACK_DATA_NOTE_B
>
>     /** --- = first special empty note  */
> #define AVSEQ_TRACK_DATA_NOTE_SPECIAL       0
> #define AVSEQ_TRACK_DATA_NOTE_NONE          FF_AVSEQ_TRACK_DATA_NOTE_SPECIAL
>
>     /** ^^^ = note kill  */
> #define AVSEQ_TRACK_DATA_NOTE_KILL          -1
>
>     /** ^^- = note off  */
> #define AVSEQ_TRACK_DATA_NOTE_OFF           -2
>
>     /** === = keyoff note  */
> #define AVSEQ_TRACK_DATA_NOTE_KEYOFF        -3
>
>     /** -|- = hold delay  */
> #define AVSEQ_TRACK_DATA_NOTE_HOLD_DELAY    -4
>
>     /** -\- = note fade  */
> #define AVSEQ_TRACK_DATA_NOTE_FADE          -5
>
>     /** END = pattern end marker  */
> #define AVSEQ_TRACK_DATA_NOTE_END           -16

>     /** Number of instrument to be played or 0 to take previous one.  */
>     uint16_t instrument;

Why 0 to take previous one? This forces your array to start at 1 and 
IMHO does not simplify any code. In the player you can always do

if (instrument == previous_instrument) {...}

>     /** C-4 = default tone  */
> #define AVSEQ_TRACK_DATA_TONE               ((FF_AVSEQ_TRACK_DATA_OCTAVE << 8) | FF_AVSEQ_TRACK_DATA_NOTE)
>
>     /** Number of effects used by this track.  */
>     uint16_t effects;
> } AVSequencerTrackData;
>
> /**
>  * Song track structure.
>  * New fields can be added to the end with minor version bumps.
>  * Removal, reordering and changes to existing fields require a major
>  * version bump.
>  */
> typedef struct AVSequencerTrack {
>     /** Metadata information: Original track file name, track
>        title, track message, track artist, track album,
>        track begin and finish date of composition and comment.  */
>     AVMetadata *metadata;

>     /** AVSequencerTrackData pointer to array of track data.  */
>     AVSequencerTrackData *data;

This naming bothers me a little. If AVSequencerTrackData contains the 
track data, what does AVSequencerTrack contains?

>     /** Last valid row of track (defaults to 63 = 0x3F) which
>        is the default for most trackers (64 rows per pattern).  */
>     uint16_t last_row;
> #define AVSEQ_TRACK_LAST_ROW    63
> #define AVSEQ_TRACK_LENGTH      ((FF_AVSEQ_TRACK_LAST_ROW) + 1)
> #define AVSEQ_TRACK_LENGTH_MIN  0
> #define AVSEQ_TRACK_LENGTH_MAX  65536
>
>     /** Track global volume (defaults to 255 = no volume scaling).  */
>     uint8_t volume;
> #define AVSEQ_TRACK_VOLUME  255
>
>     /** Sub-volume level for this track. This is basically track
>        global volume divided by 256, but the sub-volume doesn't
>        account into actual mixer output (defaults 0).  */
>     uint8_t sub_volume;
> #define AVSEQ_TRACK_SUB_VOLUME  0
>
>     /** Stereo panning level for this track (defaults to
>        -128 = central stereo panning).  */
>     int8_t panning;
> #define AVSEQ_TRACK_PANNING -128
>
>     /** Stereo track sub-panning level for this channel. This is
>        basically track panning divided by 256, but the sub-panning
>        doesn't account into actual mixer output (defaults 0).  */
>     uint8_t sub_panning;
> #define AVSEQ_TRACK_SUB_PANNING 0
>
>     /** Track transpose. Add this value to octave * 12 + note to
>        get the final octave / note played (defaults to 0).  */
>     int8_t transpose;
> #define AVSEQ_TRACK_TRANSPOSE   0
>
>     /** Compatibility flags for playback. There are rare cases
>        where track handling can not be mapped into internal
>        playback engine and have to be handled specially. For
>        each sub-song which needs this, this will define new
>        flags which tag the player to handle it to that special
>        way.  */
>     uint8_t compat_flags;
> #define AVSEQ_TRACK_COMPAT_FLAG_SAMPLE_OFFSET       0x01 ///< Sample offset beyond end of sample will be ignored (IT compatibility)
> #define AVSEQ_TRACK_COMPAT_FLAG_TONE_PORTA          0x02 ///< Share tone portamento memory with portamentoes and unlock tone portamento samples and adjusts frequency to: new_freq = freq * new_rate / old_rate. If an instrument number is given the envelope will be retriggered (IT compatibility).
> #define AVSEQ_TRACK_COMPAT_FLAG_SLIDES              0x04 ///< Portamentos of same type share the same memory (e.g. porta up/fine porta up)
> #define AVSEQ_TRACK_COMPAT_FLAG_VOLUME_SLIDES       0x08 ///< All except portamento slides share the same memory (e.g. volume/panning slides)
> #define AVSEQ_TRACK_COMPAT_FLAG_OP_SLIDES           0x10 ///< Oppositional portamento directions don't share the same memory (e.g. porta up and porta down)
> #define AVSEQ_TRACK_COMPAT_FLAG_OP_VOLUME_SLIDES    0x20 ///< Oppositional non-portamento slide directions don't share the same memory
> #define AVSEQ_TRACK_COMPAT_FLAG_VOLUME_PITCH        0x40 ///< Volume & pitch slides share same memory (S3M compatibility)
>
>     /** Track playback flags. Some sequencers feature
>        surround panning or allow initial reverse playback,
>        different timing methods which have all to be taken
>        care specially in the internal playback engine.  */
>     uint8_t flags;
> #define AVSEQ_TRACK_FLAG_USE_TIMING             0x01 ///< Use track timing fields
> #define AVSEQ_TRACK_FLAG_SPD_TIMING             0x02 ///< SPD speed timing instead of BpM
> #define AVSEQ_TRACK_FLAG_PANNING                0x04 ///< Use track panning and sub-panning fields
> #define AVSEQ_TRACK_FLAG_SURROUND               0x08 ///< Use track surround panning
> #define AVSEQ_TRACK_FLAG_REVERSE                0x10 ///< Playback of track in backward direction
>
>     /** Initial number of frames per row, i.e. sequencer tempo
>        (defaults to 6 as in most tracker formats).  */
>     uint16_t frames;
> #define AVSEQ_TRACK_FRAMES  6
>
>     /** Initial speed multiplier, i.e. nominator which defaults
>        to disabled = 0.  */
>     uint8_t speed_mul;
> #define AVSEQ_TRACK_SPEED_MUL   0
>
>     /** Initial speed divider, i.e. denominator which defaults
>        to disabled = 0.  */
>     uint8_t speed_div;
> #define AVSEQ_TRACK_SPEED_DIV   0
>
>     /** Initial MED style SPD speed (defaults to 33 as in
>        OctaMED Soundstudio).  */
>     uint16_t spd_speed;
> #define AVSEQ_TRACK_SPD_SPEED   33
>
>     /** Initial number of rows per beat (defaults to 4 rows are a beat).  */
>     uint16_t bpm_tempo;
> #define AVSEQ_TRACK_BPM_TEMPO   4
>
>     /** Initial beats per minute speed (defaults to 50 Hz => 125 BpM).  */
>     uint16_t bpm_speed;
> #define AVSEQ_SONG_BPM_SPEED   125
>
>     /** Array of pointers containing every unknown data field where
>        the last element is indicated by a NULL pointer reference. The
>        first 64-bit of the unknown data contains an unique identifier
>        for this chunk and the second 64-bit data is actual unsigned
>        length of the following raw data. Some formats are chunk based
>        and can store information, which can't be handled by some
>        other, in case of a transition the unknown data is kept as is.
>        Some programs write editor settings for tracks in those chunks,
>        which then won't get lost in that case.  */
>     uint8_t **unknown_data;
> } AVSequencerTrack;
>
> /**
>  * Song track effect structure, This structure is actually for one row
>  * and therefore actually pointed as an array with the amount of
>  * rows of the whole track.
>  * New fields can be added to the end with minor version bumps.
>  * Removal, reordering and changes to existing fields require a major
>  * version bump.
>  */
> typedef struct AVSequencerTrackEffect {

>     /** Unused and reserved for future expansions, leave 0 for now.  */
>     uint8_t reserved;

Can be removed.

>     /** Effect command byte.  */
>     uint8_t command;

>     /** Command types.  */

Doxygen will not parse it as you want. Better just

/* Command types.  */

>     /** Note effects (00-1F).  */
> #define AVSEQ_TRACK_EFFECT_NOTE_MIN          0x00
> #define AVSEQ_TRACK_EFFECT_NOTE_MAX          0x1F
>
>     /** Volume control related effects (20-2F).  */
> #define AVSEQ_TRACK_EFFECT_VOLUME_MIN        0x20
> #define AVSEQ_TRACK_EFFECT_VOLUME_MAX        0x2F
>
>     /** Panning control related effects (30-3F).  */
> #define AVSEQ_TRACK_EFFECT_PANNING_MIN       0x30
> #define AVSEQ_TRACK_EFFECT_PANNING_MAX       0x3F
>
>     /** Track and channel control related effects (40-4F).  */
> #define AVSEQ_TRACK_EFFECT_TRACK_MIN         0x40
> #define AVSEQ_TRACK_EFFECT_TRACK_MAX         0x4F
>
>     /** Instrument, sample and synth control related effects (50-5F).  */
> #define AVSEQ_TRACK_EFFECT_INSTRUMENT_MIN    0x50
> #define AVSEQ_TRACK_EFFECT_INSTRUMENT_MAX    0x5F
>
>     /** Global control related effects (60-7E).  */
> #define AVSEQ_TRACK_EFFECT_GLOBAL_MIN        0x60
> #define AVSEQ_TRACK_EFFECT_GLOBAL_MAX        0x7E

This is ugly and fragile (what would you do if a new format shows up 
with a new volume effect). Why not an array instead?

static const Enum EffectType effect_type[AVSEQ_EFFECTS_NUMBER] = {
    [AVSEQ_TRACK_EFFECT_CMD_ARPEGGIO] = AVSEQ_TRACK_EFFECT_NOTE,
    [AVSEQ_TRACK_EFFECT_CMD_PORTA_UP] = AVSEQ_TRACK_EFFECT_NOTE,
    [...]
};

Note how easy would be change it to a struct to add more information 
about each effect.

BTW, using Arpeggio == 0x00 is specific for some format or some ad-hoc 
choice? If it is ad-hoc, it should not be part of the Doxy comment, it 
is not useful information.

>     /** User customized effect for trigger in demos, etc.  */
> #define AVSEQ_TRACK_EFFECT_USER              0x7F
>
>     /** Note effect commands.
>        0x00 - Arpeggio:
>        Data word consists of two 8-bit pairs named xx and yy
>        where xx is the first halftone and yy the second halftone.
>        Both xx and yy are signed values which means that a
>        negative value is a backward arpeggio.  */
> #define AVSEQ_TRACK_EFFECT_CMD_ARPEGGIO      0x00

[...]

-Vitor


More information about the FFmpeg-soc mailing list