1

I am writing a Fortran90 code to read .wav audio files.

Within the .wav format there is a chunk introduced by a string 'WAVE'. Within this chunk must appear two subchunks introduced by the strings 'fmt ' and 'data'.

In the particular .wav file I am using, to test the code, after the 'WAVE' string there is a gap of 36 characters beginning with the word 'JUNK' before the subchunk beginning with 'fmt ' appears in the file (picture suppled below).

The online resources I have read do not indicate such gaps are to be expected. The expectation is 'fmt ' should appear directly after 'WAVE'.

.wav file format description

I don't want my code to collapse when it encounters untypical formatting.

There appears to be no way to predetermine where the 'fmt ' string appears in the file. My strategy is to search the file for it and then simply discard the rogue section beginning with 'JUNK'.

My initial attempts to search the file stream using SCAN or INDEX have failed because passing these intrinsic functions the open file unit number throws an error which reports the file is not a string.

It may aid clarity to read my code as it is so far.

program main
  
  use iso_fortran_env

  !=========================================================================

  !Variables for .wav header.
  character(4)     :: ChunkID = '____'
  integer  (4)     :: FileSize
  character(4)     :: Wave = 'WAVE'

  !fmt need only be charcter(4) but is extended here for illustation output.
  character(40)    :: fmt = 'fmt '
  
  !=========================================================================

  !Working variables for file handling..
  integer  (1)  :: args
  character(30) :: file
  integer :: stat

  !Exit when no file name is supplied. 
  args = command_argument_count()
  if(args.ne.1)then
     print *
     print *, 'Error. Enter .wav file name'
     print *, 'Example: cat'
     print *, "NB. The '.wav' extension is assumed. You don't need to add it."
     stop
  end if
  call GET_COMMAND_ARGUMENT(1,file)

  !Construct .wav file name.
  file =  trim(file) // '.wav'

  !Try opening .wav file with name supplied
  OPEN(UNIT=1, iostat=stat, FILE=file, &
       form='unformatted', access='stream', status='old')

  !Test file status and exit on error.
  if(stat.ne.0) then
     write(*,'(a)') 'No known file named ', file
     stop
  end if
  print *, 'File existence test: Passed'

  ! Header read.
  read(1) ChunkID, FileSize, Wave, fmt
  print *, 'ChunkID: ', ChunkID
  print *, 'FileSize: ', FileSize
  print *, '"WAVE": ', wave
  print *, '"fmt ":', fmt

END PROGRAM MAIN

The output the program produces using my downloaded trial .wav file is this:

enter image description here

The trouble starts with the unwanted text following "fmt ": ahead of fmt at the end.

My purpose is to discard this redundant string then continue reading the file from the expected string 'fmt '.

What intrinsics should I use in fortran to enable to me to absorb and discard useless file contents, retaining the parts that I need, within a file containing an assortment of data types?

4
  • 1
    Please use tag fortran for all Fortran questions. Be aware that Fortran 90 is a very old incarnation of the standard. There are many more recent ones. Also be aware that stuff like integer(1) and integer(4) is not portable between compilers, see stackoverflow.com/questions/3170239/… Commented Mar 7, 2021 at 16:26
  • 1
    Actually, you are using stream access. That is Fortran 2003, not 90. Also, using file unit number 1 is dangerous. Use numbers higher than 10, some numbers are pre-connected somewhere already. Commented Mar 7, 2021 at 16:30
  • Yes, I had also tried 'sequential'. I am a beginning Fortran programmer not certain of how best to open a file which contains a mixture of data types and unknown length. Commented Mar 7, 2021 at 17:01
  • 1
    Stream is the correct thing, do not use sequential here. That uses records separated by record markers. Commented Mar 7, 2021 at 17:34

1 Answer 1

1

I use this subroutine to change the file position behind the searched string str:

subroutine skip_to(str, stat)
  character(*), intent(in) :: str
  integer, intent(out) :: stat
  character :: ch
  integer :: io

  do
    read(unit, iostat=io) ch

    if (io/=0) then
      stat = 1
      return
    end if

    if (ch==str(1:1)) then
      call check(str(2:), stat)
      if (stat == 0) return
    end if

  end do
end subroutine

subroutine check(str, stat)
  character(*), intent(in) :: str
  integer, intent(out) :: stat
  character :: ch
  integer :: i, io

  stat = 1
  i = 0

  do
    i = i + 1

    read(unit, iostat=io) ch

    if (io/=0) return

    if (ch/=str(i:i)) return

    if (i==len(str)) then
      stat = 0
      return
    end if
  end do
end subroutine

It might be very inefficient because it reads one byte a time for maximum simplicity. It just reads a byte and checks whether the string might be starting there and then it checks whether the next byte is the right one and so on.


Note that I often have to search for a string in the middle of a very large vtk file (gigabytes).

If you actually have just a small header. I would read the whole header into a long string and process it in memory using string-oriented routines.

Sign up to request clarification or add additional context in comments.

5 Comments

"You are reading fixed-length characters so no wonder the character also contains some junk". I don't understand what this means.
Thank you Vladimir, I shall take a close look at this subroutine. In the interim I have altered my question slightly in the hope of producing a clearer question.
Don't worry about that, I think I understand your intent. I have deleted the confusing sentence.
Thank you. Would it be correct to say fortran intrinsics do not provide a function to find a string within a stream of mixed data types, which includes non character types, and it is therefore necessary to write my own function or subroutine to do it, such as you have above?
Probably not. The external file is a stream of bytes. It can be a stream of character(1) if you want to read it that way. But Fortran does not provide intrinsic for searching in external files.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.