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

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

Subject: RE: [linux-audio-dev] EDL's ... in process
From: MOULET Xavier FTRD/DMR/ISS (xavier.moulet_AT_rd.francetelecom.fr)
Date: Wed Oct 18 2000 - 20:04:42 EEST


I actually implemented a EDL thing (i didn't know this had that cool name.
wow.) in python for a synthesis/editing program, non destructive.

I used python highly-oo features to define such a thing, and I must agree we
came down to almost the same conclusions.

The idea was to create an object signal, which had several overloaded
methods, such as len(), compute(), ID().

The idea is that a signal has a set of properties, for an audio signal, this
can be sampling frequency, number of channels, ... Other kind of signals may
be control signals of frequency domain signal.

The idea is that you can evaluate an object with a kind of parameters,
example : wave(fs=200,nchannels=12,len=31). The the object will ask
compute() to compute this. UNLESS the signal is cached by the sigbnal inner
circuitry. The compute function will try to do its best to serve the signal
(ie an array of samples, calculated with a fast array library specialized in
number crunching, pynum), and the signal object will try to do its best to
adapt the value to what has been asked. Some parameters may be undefined(ex
: 'i don't care how many channels, give me what you have'), and then compute
will provide what it needs. The idea is that you can ask for a preview, 8
bits, 16kHz and you won't have to convert your poor quality 8bits samples to
16 bits and then back to 8 bits if you don't need to. Except if a plugin
doens't support 8 bits computation.

Another idea is that to represent a plugin on screen, you really need to
sample it at a 100hz sampling freq ..., or at least calculate an envelope
from a signal less than 96 khz to compute the mean value over 10000 samples
... just make envelope(sigin = mysignal(fs=10000), samplingfreq =
100).makepng('mysignal.png') (it works ! )

The ID is a string which contains the signal definition, and I intend to put
some python code in it.

To cut a sample, in fact, you just create a new signal Cut, which is a
subclass of Signal, and define your parameters : begin , end, and input
sample.

Then you add some simple functions to make compatible a sample to another
one ("coerce") : coerce takes a pair of signals and gives back a pair of
sampling frequency and sample width compatible samples. That's part of a
definition of a 'wave' signal protocol. you may not have this for other
types of signals.

And I added some utility functions to add two signals and multiply one by a
constant, make a ramping signal...

Then, to apply a sine envelope to a wave and write it back to disk, you
write (it works NOW):

(
  wave(filename= 'coolsound.wav')
  * lfo(waveform='sine',freq='12.2',amplitude="1",mean='0.5')
).save('supercoolsound.wav')

And that's processed and saved with the minimum needed quality. or you can
write

mylfo = lfo(.....)
mysig = wave(filename='coolsound.wav')*mylfo
print mylfo.ID() and it takes 0.002 sec. to display (Unless you really want
to hear it).

mul(wave('coolsound.wav'), lfo(....))

I had some other ideas (in the UI point of view) to make what I would not
dare to call The Gimp of sound : everything in plugins (python, interpreted
yet fast because using smart caching and minimum quality evaluation ), and
everything customizable (parameters functions are signals and modular from a
UI point of view (and may be added , they are plugins, too)).

It might take quite a time before something is playable with (this ought to
be a COOL TOY tm), but I clearly intend to make that happen. Borrowing from
python and pynum, python numeric library cut down the development time, and
I think performance savings has to be made from the _algorithms_ point of
view, since i'm editing offline. maybe code some algorithms in C, use sox,
and of course ladspa plugins. It will be easy to do adapter functions.
remember this is a toy.

I don't think this has overlap from what you intend to do, because I want to
use python (such an efficient and elegant language !), and you are coding in
an compiled language. I want people to make 'plugins' in python and simples
! (i created a semi UI description data structure with python advanced use
of lists and so on, this HAS to be portable).

Of course everything here is pure hype and I have a semi working library ,
but I WILL make this happen.

But we may benefit of each others' ideas, don't you think ?

(PS : what do you think of this project ? please be critic, I am confident
this will be constructive criticisms).

Thank you for reading,

xavier

PS : could you develop on GtkWaveForm ? I _AM_ interested.

> -----Message d'origine-----
> De : Paul Barton-Davis [mailto:pbd_AT_Op.Net]
> Envoyé : mercredi 18 octobre 2000 15:57
> À : linux-audio-dev_AT_ginette.musique.umontreal.ca
> Objet : [linux-audio-dev] EDL's ... in process
>
>
> 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 - 20:48:20 EEST