hi erik,

i've got another strange issue with libnsdfile (1.0.10beta6 and
earlier).

it seems to be related to SFM_RDWR mode again.  if i open an existing
(but empty) file in RDWR mode, then switch to UPDATE_HEADER_AUTO mode,
then write to the file, then try to seek to the end of the file in
order to write again: then the seek command will fail or misbehave.

when seeking to file-end, SEEK SET, it will fail with "Internal
psf_fseek() failed.", if seeking to 0, SEEK_END, it will just seek to
zero regardless of the number of frames in the file.

all this proceeds if not switching to UPDATE_HEADER_AUTO.  though not
included in the test case, i got the same behavior when using
WRITE_HEADER_NOW after each write instead of UPDATE_HEADER_AUTO with
my "real-world" code.

this behavior seems to be independent from the sndfile format, but
just tested with WAV/16bit, AIFF/16bit, AIFF/float.

attached the "small test case", hope erik will like it again...

bests,

martin

/*
 * compile with:
 *
 * gcc -o seek -Wall -lsndfile seek.c
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sndfile.h>


int
main (int argc,
      char **argv)
{
  SF_INFO info;
  int mode;
  sf_count_t file_frames;
  SNDFILE *file;
  char *filename = "/tmp/sndtest.aiff";

  /* create soundfile */
  mode = SFM_WRITE;
  info.samplerate = 48000;
  info.channels = 2;

  /* behavior seems to be bound to a specific file format */
  info.format = SF_FORMAT_AIFF | SF_FORMAT_PCM_16;

  /* delete if already there */
  {
    struct stat st;
    
    if (! stat(filename, &st))
      {
	remove(filename);
      }
  }

  /* open */
  if ((file = sf_open(filename, mode, &info)) == NULL)
    {
      fprintf(stderr, "libsndfile(open): %s\n", sf_strerror(file));
      exit(EXIT_FAILURE);
    }
  
  /* close without writing: just write header */
  if (sf_close(file))
    {
	fprintf(stderr, "libsndfile(close): %s\n", sf_strerror(file));
	exit(EXIT_FAILURE);
    }

  /* open again for writing */
  mode = SFM_RDWR; /* !!! */
  info.format = 0;

  if ((file = sf_open(filename, mode, &info)) == NULL)
    {
      fprintf(stderr, "libsndfile(open): %s\n", sf_strerror(file));
      exit(EXIT_FAILURE);
    }

  /* remember number of frames in file */
  file_frames = info.frames;

  /* in auto header update mode, seeking to the end of the file with
     SEEK_SET will fail from the 2nd seek on.  seeking to 0, SEEK_END
     will seek to 0 anyway */
  if (! sf_command(file, SFC_SET_UPDATE_HEADER_AUTO, NULL, SF_TRUE))
    {
      fprintf(stderr, "libsndfile(sf_command): %s\n", sf_strerror(file));
      exit(EXIT_FAILURE);
    }
  
  /* now write some frames */
  {
    float buffer[1024];
    int blocks = 4; /* we want to write blocks times the buffer */
    long err;
    int frames = 1024 / info.channels;
    int i;

    for (i = 0; i < blocks; ++i)
      {
	fprintf(stderr, "trying to seek to position %d, file_frames: %ld\n", i * frames, (long)file_frames);

	/* this will fail from the 2nd seek on */
	if ((err = sf_seek(file, i * frames, SEEK_SET)) == -1)

        /* this will seek to 0 regardless of the number of frames in
	   the file */
/* 	if ((err = sf_seek(file, 0, SEEK_END)) == -1) */
	  {
	    fprintf(stderr, "libsndfile(sf_seek): %s\n", sf_strerror(file));
	  }
	else
	  {
	    fprintf(stderr, "seeked to position %ld\n", err);
	  }

	/* write */
	if ((err = sf_writef_float(file, buffer, frames)) == -1)
	  {
	    fprintf(stderr, "libsndfile: sf_writef_float(): %s\n", sf_strerror(file));
	  }
	else
	  {
	    fprintf(stderr, "wrote %ld frames\n", err);
	    file_frames += err;
	  }
      }
  }

  /* close */
  if (sf_close(file))
    {
      fprintf(stderr, "libsndfile(close): %s\n", sf_strerror(file));
      exit(EXIT_FAILURE);
    }

  return EXIT_SUCCESS;
} /* main */

Reply via email to