[xiph-cvs] cvs commit: vorbis-python/test enc.py enc2.py

Andrew Catham Master of Python andrew at xiph.org
Sun Jan 27 03:14:21 PST 2002



andrew      02/01/27 03:14:20

  Modified:    .        ChangeLog README
               src      pyvorbiscodec.c pyvorbisinfo.c
               test     enc.py enc2.py
  Log:
  2001-01-27  Andrew H. Chatham <andrew.chatham at duke.edu>
          * pyvorbiscodec.c (py_dsp_write_wav), (parse_wav_data): Added
          * pyvorbiscodec.c (py_dsp_write): Write 0 if None
  
          * pyvorbisinfo.c: Removed some unused variables
          * pyvorbisinfo.c (py_info_new): Parse the quality option
          * pyvorbisinfo.c (py_vorbis_info_blocksize): Added
  
          * test/enc.py: Updated to do new encode process (with quality setting)
          * test/enc2.py: Updated to do quality setting and use write_wav

Revision  Changes    Path
1.8       +11 -0     vorbis-python/ChangeLog

Index: ChangeLog
===================================================================
RCS file: /usr/local/cvsroot/vorbis-python/ChangeLog,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- ChangeLog	2002/01/22 01:58:17	1.7
+++ ChangeLog	2002/01/27 11:14:19	1.8
@@ -1,3 +1,14 @@
+2001-01-27  Andrew H. Chatham <andrew.chatham at duke.edu>
+	* pyvorbiscodec.c (py_dsp_write_wav), (parse_wav_data): Added
+	* pyvorbiscodec.c (py_dsp_write): Write 0 if None
+	
+	* pyvorbisinfo.c: Removed some unused variables
+	* pyvorbisinfo.c (py_info_new): Parse the quality option
+	* pyvorbisinfo.c (py_vorbis_info_blocksize): Added
+
+	* test/enc.py: Updated to do new encode process (with quality setting)
+	* test/enc2.py: Updated to do quality setting and use write_wav
+
 2001-01-21  Andrew H. Chatham <andrew.chatham at duke.edu>
         * pyvorbisinfo.c: Comment objects now store pointers to the
         comment structures, not the structure itself. Helps with dealloc.

<p><p>1.4       +7 -3      vorbis-python/README

Index: README
===================================================================
RCS file: /usr/local/cvsroot/vorbis-python/README,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- README	2002/01/22 01:58:17	1.3
+++ README	2002/01/27 11:14:19	1.4
@@ -38,15 +38,19 @@
 To encode, you need to feed a VorbisDSPState object PCM data as one
 array of floating point values ranging from -1.0 ... 1.0 per
 channel. You can do this in pure Python, but it almost doubles the
-time it takes to encode (less if you optimize it, I suppose).
+time it takes to encode. The other option is to read data using the
+python "wave" module and write it to the VorbisDSPState directly using
+the x.write_wav(mywave.readframes(n)) call. This will only work with
+16-bit Wave files.
 
 Perhaps you are wondering how much of a performance hit you'll be
 taking using the Python bindings versus straight C. Well, I've tried
 to make things as fast as possible, but of course nothing's
 perfect. Decoding a file, top reports about the same CPU usage for my
 ogg123.py and the C implementation of ogg123. For encoding, it's about
-twice as slow if you're using my test enc.py file. It can probably
-stand some speedup, though.
+twice as slow as oggenc if you're using my test enc.py file (parsing
+the wave file somewhat by hand). If you use the write_wav function,
+it's only about 3% slower than oggenc.
 
 
 

<p><p>1.5       +123 -8    vorbis-python/src/pyvorbiscodec.c

Index: pyvorbiscodec.c
===================================================================
RCS file: /usr/local/cvsroot/vorbis-python/src/pyvorbiscodec.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- pyvorbiscodec.c	2002/01/22 01:57:56	1.4
+++ pyvorbiscodec.c	2002/01/27 11:14:19	1.5
@@ -7,6 +7,8 @@
 #include "pyvorbiscodec.h"
 #include "pyvorbisinfo.h"
 
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+
 /**************************************************************
                          VorbisDSP Object
  **************************************************************/
@@ -18,8 +20,14 @@
 FDEF(vorbis_block_init) "Create a VorbisBlock object for use in encoding {more?!}";
 FDEF(dsp_write) "Write audio data to the dsp device and have it analyzed. \n\
 Each argument must be a string containing the audio data for a\n\
-single channel.";
+single channel.\n
+If None is passed as the only argument, this will signal that no more\n
+data needs to be written.";
+FDEF(dsp_write_wav) "Write audio data to the dsp device and have it analyzed.\n\
+The single argument is the output from the python wave module. Only supports\n\
+16-bit wave data (8-bit waves will produce garbage).";
 FDEF(dsp_close) "Signal that all audio data has been written to the object.";
+FDEF(vorbis_bitrate_flushpacket) "";
 
 static void py_dsp_dealloc(PyObject *);
 static PyObject *py_dsp_getattr(PyObject *, char*);
@@ -64,8 +72,12 @@
    METH_VARARGS, py_vorbis_block_init_doc},
   {"write", py_dsp_write,
    METH_VARARGS, py_dsp_write_doc},
+	{"write_wav", py_dsp_write_wav,
+	 METH_VARARGS, py_dsp_write_wav_doc},
   {"close", py_dsp_close,
    METH_VARARGS, py_dsp_close_doc},
+	{"bitrate_flushpacket", py_vorbis_bitrate_flushpacket,
+	 METH_VARARGS, py_vorbis_bitrate_flushpacket_doc},
   {NULL, NULL}
 };
 
@@ -95,6 +107,7 @@
     return NULL;
   
   ret = (py_dsp *) PyObject_NEW(py_dsp, &py_dsp_type);
+	ret->parent = NULL;
   vi = &py_vi->vi;
   vorbis_synthesis_init(&vd, vi);
   return py_dsp_from_dsp(&vd, (PyObject *) py_vi);
@@ -103,6 +116,7 @@
 static void
 py_dsp_dealloc(PyObject *self)
 {
+	vorbis_dsp_clear(PY_DSP(self));
   Py_XDECREF(((py_dsp *)self)->parent);
   PyMem_DEL(self);
 }
@@ -147,9 +161,6 @@
   PyObject *pyheader_code = NULL;
   PyObject *ret = NULL;
   
-  if (!PyArg_ParseTuple(args, ""))
-    return NULL;
-
   /* Takes a comment object as the argument.
      I'll just give them an empty one if they don't provied one. */
   if (!PyArg_ParseTuple(args, "|O!", &py_vcomment_type, &comm))
@@ -253,6 +264,11 @@
 
   channels = dsp_self->vd.vi->channels;
 
+	if (PyTuple_Size(args) == 1 && PyTuple_GET_ITEM(args, 0) == Py_None) {
+		vorbis_analysis_wrote(&dsp_self->vd, 0);
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
   if (PyTuple_Size(args) != channels) {
     snprintf(err_msg, sizeof(err_msg), 
              "Expected %d strings as arguments; found %d arguments",
@@ -286,13 +302,68 @@
     memcpy(analysis_buffer[k], buffs[k], len);
 
   free(buffs);
-  
   vorbis_analysis_wrote(&dsp_self->vd, samples);
 
   return PyInt_FromLong(samples); /* return the number of samples written */
 }
 
+static void
+parse_wav_data(const char *byte_data, float **buff, 
+							 int channels, int samples)
+{
+	const float adjust = 1/32768.0;
+	int j, k;
+	for (j = 0; j < samples; j++) {
+		for (k = 0; k < channels; k++) {
+			float val = ((byte_data[j * 2 * channels + 2 * k + 1] << 8) | 
+									 (byte_data[j * 2 * channels + 2 * k] & 0xff)) * adjust;
+			buff[k][j] = val;
+		}
+	}
+}
+
 static PyObject *
+py_dsp_write_wav(PyObject *self, PyObject *args) 
+{
+	const char *byte_data;
+	int num_bytes, channels, k;
+	long samples;
+	const int samples_per_it = 1024;
+	py_dsp *dsp = (py_dsp *) self;
+	float **analysis_buffer;
+	int sample_width;
+
+	channels = dsp->vd.vi->channels;
+	sample_width = channels * 2;
+
+	if (!PyArg_ParseTuple(args, "s#", &byte_data, &num_bytes))
+		return NULL;
+
+	if (num_bytes % (channels * 2) != 0) {
+		PyErr_SetString(Py_VorbisError,
+										"Data is not a multiple of (2 * # of channels)");
+		return NULL;
+	}
+	samples = num_bytes / sample_width;
+	
+	for (k = 0; k < samples / samples_per_it; k++) {
+		int to_write = MIN(samples - k * samples_per_it, samples_per_it);
+
+		analysis_buffer = vorbis_analysis_buffer(&dsp->vd, 
+																						 to_write * sizeof(float));
+		/* Parse the wav data directly into the analysis buffer. */
+		parse_wav_data(byte_data, analysis_buffer, channels, to_write);
+
+		/* Skip any data we've already passed by incrementing the pointer */
+		byte_data += to_write * sample_width;
+
+		vorbis_analysis_wrote(&dsp->vd, to_write);
+	}
+	
+	return PyInt_FromLong(samples);
+}
+
+static PyObject *
 py_dsp_close(PyObject *self, PyObject *args)
 {
   py_dsp *dsp_self = (py_dsp *) self;
@@ -301,6 +372,27 @@
   return Py_None;
 }
 
+static PyObject *
+py_vorbis_bitrate_flushpacket(PyObject *self, PyObject *args)
+{
+	ogg_packet op;
+	int ret;
+	
+	if (!PyArg_ParseTuple(args, ""))
+		return NULL;
+
+	ret = vorbis_bitrate_flushpacket(PY_DSP(self), &op);
+	if (ret == 1) 
+		return modinfo->ogg_packet_from_packet(&op);
+	else if (ret == 0) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	} else {
+		PyErr_SetString(Py_VorbisError, "Unknown return code from flushpacket");
+		return NULL;
+	}
+}
+
 /*********************************************************
                         VorbisBlock
  *********************************************************/
@@ -308,6 +400,7 @@
 static PyObject *py_block_getattr(PyObject *, char*);
 
 FDEF(vorbis_analysis) "Output an OggPage.";
+FDEF(vorbis_bitrate_addblock) "?";
 
 char py_block_doc[] = "";
 
@@ -343,6 +436,8 @@
 static PyMethodDef Block_methods[] = {
   {"analysis", py_vorbis_analysis,
    METH_VARARGS, py_vorbis_analysis_doc},
+	{"addblock", py_vorbis_bitrate_addblock,
+	 METH_VARARGS, py_vorbis_bitrate_addblock_doc},
   {NULL, NULL}
 };
 
@@ -363,14 +458,34 @@
 static PyObject*
 py_vorbis_analysis(PyObject *self, PyObject *args)
 {
+	int ret;
   py_block *b_self = (py_block *) self;
-  ogg_packet op;
 
   if (!PyArg_ParseTuple(args, ""))
     return NULL;
+
+  ret = vorbis_analysis(&b_self->vb, NULL);
+	if (ret < 0) {
+		PyErr_SetString(Py_VorbisError, "vorbis_analysis failure");
+		return NULL;
+	}
+	Py_INCREF(Py_None);
+	return Py_None;
+}
 
-  vorbis_analysis(&b_self->vb, &op); /* TODO error code */
-  return modinfo->ogg_packet_from_packet(&op);
+static PyObject *
+py_vorbis_bitrate_addblock(PyObject *self, PyObject *args)
+{
+	int ret;
+	if (!PyArg_ParseTuple(args, ""))
+		return NULL;
+	ret = vorbis_bitrate_addblock(PY_BLOCK(self));
+	if (ret < 0) {
+		PyErr_SetString(Py_VorbisError, "addblock failed");
+		return NULL;
+	}
+	Py_INCREF(Py_None);
+	return Py_None;
 }
 
 PyObject *

<p><p>1.5       +52 -31    vorbis-python/src/pyvorbisinfo.c

Index: pyvorbisinfo.c
===================================================================
RCS file: /usr/local/cvsroot/vorbis-python/src/pyvorbisinfo.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- pyvorbisinfo.c	2002/01/22 01:57:56	1.4
+++ pyvorbisinfo.c	2002/01/27 11:14:19	1.5
@@ -10,13 +10,14 @@
 #include "vcedit.h"
 
 /*  
-   *********************************************************
-                        VorbisInfo Object methods 
-   *********************************************************
+*********************************************************
+VorbisInfo Object methods 
+*********************************************************
 */
 
 FDEF(ov_info_clear) "Clears a VorbisInfo object";
 FDEF(vorbis_analysis_init) "Create a DSP object to start audio analysis.";
+FDEF(vorbis_info_blocksize) "I have NO idea what this does.";
 
 static void py_ov_info_dealloc(PyObject *);
 static PyObject *py_ov_info_getattr(PyObject *, char *name);
@@ -26,6 +27,8 @@
    METH_VARARGS, py_ov_info_clear_doc},
   {"analysis_init", py_vorbis_analysis_init, 
    METH_VARARGS, py_vorbis_analysis_init_doc},
+	{"blocksize", py_vorbis_info_blocksize,
+	 METH_VARARGS, py_vorbis_info_blocksize_doc},
   {NULL, NULL}
 };
 
@@ -74,12 +77,14 @@
 }
 
 static char *py_info_new_kw[] = {"channels", "rate", "max_bitrate",
-																 "nominal_bitrate", "min_bitrate", NULL};
+																 "nominal_bitrate", "min_bitrate", "quality",
+																 NULL};
 
 PyObject *
 py_info_new(PyObject *self, PyObject *args, PyObject *kwdict)
 {
   long channels, rate, max_bitrate, nominal_bitrate, min_bitrate;
+	double quality = -1.0;
   vorbis_info vi; 
   int res;
 
@@ -89,15 +94,19 @@
   nominal_bitrate = 128000;
   min_bitrate = -1;
   if (!PyArg_ParseTupleAndKeywords(args, kwdict, 
-				   "|lllll", py_info_new_kw, 
-				   &channels, &rate, &max_bitrate,
-				   &nominal_bitrate, &min_bitrate))
+																	 "|llllld", py_info_new_kw, 
+																	 &channels, &rate, &max_bitrate,
+																	 &nominal_bitrate, &min_bitrate, &quality))
     return NULL;
   vorbis_info_init(&vi);
 
-  res = vorbis_encode_init(&vi, channels, rate,
-			   max_bitrate, nominal_bitrate,
-			   min_bitrate);
+	if (quality > 0.0) {
+		res = vorbis_encode_init_vbr(&vi, channels, rate, quality);
+	} else {
+		res = vorbis_encode_init(&vi, channels, rate,
+														 max_bitrate, nominal_bitrate,
+														 min_bitrate);
+	}
 
   if (res != 0) {
     vorbis_info_clear(&vi);
@@ -131,6 +140,19 @@
      return PyInt_FromLong(vi->x)
 
 static PyObject *
+py_vorbis_info_blocksize(PyObject *self, PyObject *args)
+{
+  vorbis_info *vi = PY_VINFO(self);
+	int res, zo;
+	
+	if (!PyArg_ParseTuple(args, "l", &zo))
+		return NULL;
+	
+	res = vorbis_info_blocksize(vi, zo);
+	return PyInt_FromLong(res);
+}
+
+static PyObject *
 py_ov_info_getattr(PyObject *self, char *name)
 {
   PyObject *res;
@@ -182,9 +204,9 @@
 }
 
 /*  
-   *********************************************************
-                   VorbisComment Object methods 
-   *********************************************************
+*********************************************************
+VorbisComment Object methods 
+*********************************************************
 */
 
 
@@ -659,32 +681,32 @@
 #endif
 
       if (!item)
-	goto error;
+				goto error;
       
       if (make_caps_key(key, keylen)) { /* overwrites key */
-	Py_DECREF(item);
-	goto error;
+				Py_DECREF(item);
+				goto error;
       }
 
       /* GetItem borrows a reference */
       if ((curlist = PyDict_GetItemString(retdict, key))) {
 
-	/* A list already exists for that key */
-	if (PyList_Append(curlist, item) < 0) {
-	  Py_DECREF(item);
-	  goto error;
-	}
+				/* A list already exists for that key */
+				if (PyList_Append(curlist, item) < 0) {
+					Py_DECREF(item);
+					goto error;
+				}
 
       } else {
 
-	/* Add a new list in that position */
-	curlist = PyList_New(1);
-	PyList_SET_ITEM(curlist, 0, item);
-	Py_INCREF(item);
-
-	/* this does not steal a reference */
-	PyDict_SetItemString(retdict, key, curlist); 
-	Py_DECREF(curlist);
+				/* Add a new list in that position */
+				curlist = PyList_New(1);
+				PyList_SET_ITEM(curlist, 0, item);
+				Py_INCREF(item);
+
+				/* this does not steal a reference */
+				PyDict_SetItemString(retdict, key, curlist); 
+				Py_DECREF(curlist);
       }
       Py_DECREF(item);
     }
@@ -759,7 +781,7 @@
         if (vcedit_write(state, out_file) < 0) {
                 char buff[256];
                 snprintf(buff, sizeof(buff), "Could not write comments to file: %s",
-						vcedit_error(state));
+						 vcedit_error(state));
                 PyErr_SetString(Py_VorbisError, buff);
 
                 vcedit_clear(state);
@@ -787,7 +809,6 @@
 py_comment_append_to(PyObject *self, PyObject *args) 
 {
         vorbis_comment *vc = PY_VCOMMENT(self);
-	PyObject *ret;
         const char *filename;
         if (!PyArg_ParseTuple(args, "s", &filename))
                 return NULL;

<p><p>1.2       +22 -15    vorbis-python/test/enc.py

Index: enc.py
===================================================================
RCS file: /usr/local/cvsroot/vorbis-python/test/enc.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- enc.py	2001/02/06 03:20:48	1.1
+++ enc.py	2002/01/27 11:14:20	1.2
@@ -82,7 +82,7 @@
 
 
 def main():
-    vi = ogg.vorbis.VorbisInfo(nominal_bitrate=150000)
+    vi = ogg.vorbis.VorbisInfo(quality=0.1)
     vc = ogg.vorbis.VorbisComment()
 
     vd = vi.analysis_init()
@@ -106,15 +106,18 @@
     packets = 0
     samples = 0
     
-    while 1:
+    eos = 0
+    while not eos:
         #returns a tuple of strings representing arrays of floats
         channel_data = inwav.read_stereo(2048)
-        if not channel_data: break # didn't read any data
-        apply(vd.write, channel_data) 
+        if not channel_data:
+            print "No data"
+            vd.write(None) # didn't read any data
+        else:
+            apply(vd.write, channel_data) 
 
-        samples = samples + len(channel_data[0]) / 2
+            samples = samples + len(channel_data[0]) / 4
 
-        eos = 0
         vb = vd.blockout()
         while vb:
             packets = packets + 1
@@ -125,15 +128,19 @@
             if packets % 10 == 0: 
                 print "%0.2f" % (100.0 * samples / inwav.samples)
             
-            op = vb.analysis()
-            os.packetin(op)
-        
-            while not eos:
-                og = os.pageout()
-                if not og:
-                    break
-                og.writeout(fout)
-                eos = og.eos()
+            vb.analysis()
+            vb.addblock()
+            
+            op = vd.bitrate_flushpacket()
+            while op:
+                os.packetin(op)
+                while not eos:
+                    og = os.pageout()
+                    if not og:
+                        break
+                    og.writeout(fout)
+                    eos = og.eos()
+                op = vd.bitrate_flushpacket()
             
             vb = vd.blockout()
     

<p><p>1.2       +33 -13    vorbis-python/test/enc2.py

Index: enc2.py
===================================================================
RCS file: /usr/local/cvsroot/vorbis-python/test/enc2.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- enc2.py	2001/02/06 03:20:48	1.1
+++ enc2.py	2002/01/27 11:14:20	1.2
@@ -1,25 +1,45 @@
 #!/usr/bin/env python
-import ogg.vorbis, audiofile
-vd = ogg.vorbis.VorbisInfo(nominal_bitrate=150000).analysis_init()
+'''An example of encoding using the Python wave module'''
+import ogg.vorbis, wave
+
+fout = open('out.ogg', 'w')
+inwav = wave.open('in.wav','r')
+channels = inwav.getnchannels()
+vd = ogg.vorbis.VorbisInfo(channels = channels,
+                           rate = inwav.getframerate(),
+                           quality = 0.2).analysis_init()
 os = ogg.OggStreamState(5)
 map(os.packetin, vd.headerout())
-fout = open('out.ogg', 'w')
-inwav = audiofile.WavReader('in.wav')
 og = os.flush()
 while og:
     og.writeout(fout)
     og = os.flush()
-while 1:
-    channel_data = inwav.read_channels(1024)
-    if not channel_data[0]: break
-    apply(vd.write, channel_data) 
+nsamples = 1024
+
+eos = 0
+total = 0
+while not eos:
+    data = inwav.readframes(nsamples)
+    total = total + nsamples
+    if not data:
+        vd.write(None)
+        break
+    vd.write_wav(data)
+    #print 100.0 * total / inwav.getnframes()
     vb = vd.blockout()
     while vb:
-        os.packetin(vb.analysis())
-        while 1:
-            og = os.pageout()
-            if not og: break
-            og.writeout(fout)
+        vb.analysis()
+        vb.addblock()
+
+        op = vd.bitrate_flushpacket()
+        while op:
+            os.packetin(op)
+            while not eos:
+                og = os.pageout()
+                if not og: break
+                og.writeout(fout)
+                eos = og.eos()
+            op = vd.bitrate_flushpacket()
         vb = vd.blockout()
 
 

<p><p><p>--- >8 ----
List archives:  http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.



More information about the commits mailing list