[linux-audio-dev] EDL's ... in process

New Message Reply About this list Date view Thread view Subject view Author view Other groups

Subject: [linux-audio-dev] EDL's ... in process
From: Paul Barton-Davis (pbd_AT_Op.Net)
Date: Wed Oct 18 2000 - 16:57:17 EEST


Well, OK, since nobody else was apparently going to do anything soon
about an EDL implementation, I've stepped up to the plate. I have
ported my original C++ implementation of a super-efficient EDL system
back to C, or more specifically, to glib, which many people seem
comfortable using for its lists and so forth.

Here is what the info at the top of .c file says:

/* This is a set of "objects"/"functions" designed to implement
   extremely efficient editing of arbitarily sized data streams.
   
   There are 3 layers to the model used here:
   
   buffer_t: an abstract representation of some data stream.
             It has 4 "methods" that can be called:
             
             `item_size' will return the number of bytes per item
             `item_count' will return the number of items
             `copy_to' will copy a specified number of items
                  to a memory location provided by the caller
             `copy_from' will copy a specified number of items
                  from a memory location provided by the caller.
                  
              It also has a `private_data' member, for use
              in passing extra data to the functions that
              are used for these `methods'.

              Precisely what the items are, where they come
              from, how they get here: this is all completely
              irrelevant to the API. In addition, it is very
              unlikely that any of these methods will ever
              be used by the user; sequence_read() and
              sequence_write() take care of this.

   piece_t: describes a contiguous region within a buffer_t.

   sequence_t: an ordered list of piece_t's that, taken together,
               describes the current state of the data stream.

   There are operations to insert in, delete and replace any part
   of the data stream. AT NO TIME is the underlying data ever
   modified in any way. Editing operations simply alter the
   list of piece_t's making up a sequence. In fact, even the very
   existence of ANY underlying data only matters when attempting to
   read the data stream via sequence_read() or writing via
   sequence_write().

   A sequence_t also has infinite undo and redo capabilities. Every
   time an editing (insert, delete, replace) operation is performed,
   the state of the sequence_t is saved. The operation may be undone
   with sequence_undo(); each time an operation is undone, it is also
   put on the redo list, and may be redone with sequence_redo.
*/

Enclosed below is the current header file.

The C/glib implementation is at the same stage as the C++ one: a test
program demonstrates it working perfectly and intelligently on arrays
of char.

The next stage of development for this EDL model is to connect it to
GtkWaveForm, specifically, to create a new GTK+ class called
GtkEDLWaveBuffer that can be used to view waveforms described by an
EDL, and initiate editing operations on them.

I don't believe that this will take too long. After that, I intend to
have Ardour's Track objects and tape butler thread become EDL aware,
so that Ardour can play back edited audio streams.

I have embarked down this course because I have serious doubts about
the ability of any existing linux soundfile editor to handle
multichannel editing. It appears to far out of the design space that
its authors were working in, and although I am not certain of this,
the disk i/o management techniques needed to make it work properly are
seem to be missing from every editor i have looked at so far.

GtkWaveForm looks very promising, because of its excellent level of
abstraction.

If anyone has particular interests in seeing the development of a
working, GPL'ed EDL source base (in C) for Linux, please let me know,
and we can both pore over the source I have so far and find ways to
make it even faster and better. BTW, I can't say I really enjoyed
reverting to C, but its the right thing to do if this model is to be
useful to lots of people (which would be nice).

--p

/*
    Copyright (C) 2000 Paul Barton-Davis

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    $Id$
*/

#ifndef __sequence_h__
#define __sequence_h__

#include <glib.h>

typedef struct _buffer {
    guint32 (*item_size) (struct _buffer *self);
    guint32 (*item_count) (struct _buffer *self);

    /* The two copy methods take an index, `start' into the data, and
       a count of how many data items are to be transferred to/from
       `dst' or `src'. Each returns a count of how many items were
       successfully transferred.
    */

    guint32 (*copy_to) (struct _buffer *self, guchar *dst, guint32 start, guint32 cnt);
    guint32 (*copy_from) (struct _buffer *self, guchar *src, guint32 start, guint32 cnt);

    gpointer *private_data;
    
} buffer_t;

buffer_t * buffer_new (guint32 (*isz)(), guint32 (*icnt)(),
                       guint32 (*copyto)(buffer_t*, guchar *, guint32, guint32),
                       guint32 (*copyfrom)(buffer_t*, guchar *, guint32, guint32),
                       gpointer data);

typedef struct _piece
{
    buffer_t *buffer;
    guint32 start;
    guint32 length;
} piece_t;

#define piece_size(p) ((p)->length * (p)->buffer->item_size (p->buffer))

piece_t *piece_new (buffer_t *b, guint32 start, guint32 cnt);

typedef struct _sequence_state {
    GList *pieces;
    guint32 length;
} sequence_state_t;

#define SEQUENCE_UNDO_STACK 0
#define SEQUENCE_REDO_STACK 1

typedef struct _sequence {
    GList *pieces;
    GList *stack[2];
    guint32 length;
} sequence_t;

sequence_t *sequence_new ();

guint32 sequence_read (sequence_t *, guchar *buf, guint32 start, guint32 cnt);
guint32 sequence_write (sequence_t *, guchar *buf, guint32 start, guint32 cnt);

int sequence_insert_sequence (sequence_t *, guint32 where, sequence_t *);
int sequence_insert_piece (sequence_t *, guint32 where, piece_t *);

int sequence_delete (sequence_t *, guint32 start, guint32 length);

int sequence_replace_piece (sequence_t *, guint32 start, piece_t *);
int sequence_replace_sequence (sequence_t *, guint32 start, sequence_t *);

int sequence_undo (sequence_t *);
int sequence_redo (sequence_t *);

#endif /* __sequence_h__ */


New Message Reply About this list Date view Thread view Subject view Author view Other groups

This archive was generated by hypermail 2b28 : Wed Oct 18 2000 - 17:34:27 EEST