Re: how to interpret tell_off, and the right way to use sox_seek

Jan Stary <[email protected]>
Newsgroups gmane.comp.audio.sox
Message-ID <[email protected]>
On Nov 06 12:14:59, [email protected] wrote:
> On Mon, Nov 6, 2017 at 11:06 AM, Jan Stary <[email protected]> wrote:
> >> I do take your message to imply that SoX will read no more samples
> >> than the number of in a file total, so that, e.g., if you read the
> >> same 10 blocks of samples and sox_seek() to the beginning of them
> >> repeatedly, eventually your reads will fail.  And in fact, if the
> >> length of the file is 50 blocks, those reads will fail as soon as you
> >> have done this 5 times.  If this is not correct, please let me know!!
> >> :)
> >
> > There is a difference between SoX the utility and libsox the library.
> > I am not sure if SoX itself ever reads a block of audio more than once
> > (I can imagina situations where it would), but that's not a constraint
> > on what the libsox library can do. If it has a sox_seek(), then I suppose
> > it does what the name says; in particular, it lets you read the same
> > block of audio over ano over again as long as you keep seekign back.
> > (Disclaimer: I have never used libsox directly,
> > I only use SoX the binary.)
> 
> This is the crux of the matter, and appears not to be the case.
> 
> I wrote a little program to test exactly this assertion, that you
> cannot repeatedly
> call sox_seek().
> 
> The answer here appears to be that indeed you cannot.
> 
> Here's the test program:
> 
>     #include <stdio.h>
>     #include <stdlib.h>
>     #include <sox.h>
> 
>     int main( int argc, char** argv ) {
>       if ( argc < 2 )  {
>         fprintf(stderr,"Call with one arg, the name of a sound file.\n" );
>         exit(1);
>       }
>       int istat = sox_init();
>       if (istat != SOX_SUCCESS ) {
>         fprintf(stderr, "Failed to initialize sox, error %d.\n", istat);
>         exit(1);
>       }
>       char* infile = argv[1];
>       sox_format_t* s = sox_open_read( infile, 0, 0, 0 );
>       if ( ! s ) {
>         fprintf(stderr,"Failed to open `%s' .\n", infile);
>         exit(1);
>       }
>       int buf[1024];
>       int count = 0;
>       while ( 1 ) {
>         int rcnt = sox_read( s, buf, 1024 );
>         if ( rcnt <= 0 ) {
>           printf( "Failed on read, attempt %d\n", count );
>           exit( 0 );
>         }
>         int status = sox_seek( s, 0, SOX_SEEK_SET );
>         if ( status ) {
>           fprintf(stderr,"Failed on seek.\n" );
>           exit(1);
>         }
>         count++;
>       }
>       return 0; // not reached
>     }
> 

$ cc -o soxseek soxseek.c -lsox -I/usr/local/include/ -L/usr/local/lib
$ sox -n /tmp/file.wav synth trim 0 $((1024 * 1000))s
$ ./soxseek /tmp/file.wav                             
Failed on read, attempt 1000

That makes me suspect it's just an end of file.
To quote the outdated and incomplete libsox manpage:

  sox_read and sox_write return the number of samples successfully read
  or written. If an error occurs, or the end-of-file is reached, the return
  value is a short item count or SOX_EOF. TODO: sox_read does not
  distiguish between end-of-file and error. Need an feof() and ferror()
  concept to determine which occured.


> I ran it on a file a few megabytes long, and it did a few thousand
> seeks, then failed on the read.

The above does exactly 1000 reads of 1024,
which is exactly how many samples the file contains.
So ( rcnt <= 0 ) does not mean there was an error.

> So it behaves as though there's some kind of internal counter
> initialized to the length of the file, and each read decrements that
> counter by the amount read; when the counter runs out, then reads are
> no longer permitted.

Yes.

If I am reading your code right, it does not seek at all.
It just reads up to EOF. Which might be an error in sox_seek().
As I said, I haven't used libsox before, so I don't know if
this is a correct use of sox_seek(), but beware: not every
input is seekable (a regular file on disk should be, though).

> For me, that's the most important point: to try to have an exact
> characterization of the behavior of the library under these
> circumstances.

There is no good documentation of libsox. The libosx(3) man page
is both incomplete and outdated, and it has been for years.
You might want to look an the src/example*c files.

> >
> > ... (cut)
> > Is there anything left of the original problem then?
> 
> No.
> 
> That's been solved.
> 
> But it would be useful to have confirmation that this behavior is
> intentional, or information on how to avoid the phenoomenon, but for
> now i've dealt with it, although perhaps unnecessarily given the right
> combination of function calls and arguments.

I still suspect that it is first of all unnecessary to read the input
again and again while seeking back again and again; but I can't be sure,
because I still have no idea about what you are doing.

> > ... (cut)
> >> A sort of analogous situation is with the file system and linux: if
> >> you're reading through a file the OS will keep it in memory so you
> >> don't have too much overhead just relying on the OS itself to seek
> >> back and forth in a file --- the caching has already been done.
> >
> > You already _have_ the data in memory once you have sox_read() them,
> > so I fail to see the analogy. Why would you seek back and read it
> > again _from_the_file_ once you have it in an array?
> 
> Not necessarily, as you may be reusing the storage you've set aside.

So don't reuse it: keep the copy of what you have read
so that you don't have to read it over again.

> I think the best, simplest way to obtain the same samples over and
> over would be to seek to them, and read them again.

Why do you think that? Just sox_read() it into an array,
then keep reading that array, instead of reading from a file.

> Thanks again for your help, and if anything i've said is wrong, i'd
> appreciate any correction, clarification, or references.

I staill have no idea about what you are actually trying to do.

	Jan


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.