Sounds w/o .wav files?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

Sounds w/o .wav files?

Schwab,Wilhelm K
Hello all,

Our A/D board is getting closer to service.  Since we are recording
audio of sorts, it would be prudent to listen to the data.  That often
starts with a .wav file, which I don't have.  Are there any simple ways
to start with 16 bit samples and a frequency and end up producing sound?

At present, I can write files from Dolphin, and then read them in Squeak
to create and play a SampledSound, but it would be nice to do the whole
job from Dolphin.

Have a good one,

Bill

--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Sounds w/o .wav files?

Ian Bartholomew-19
Bill,

> Our A/D board is getting closer to service.  Since we are recording audio
> of sorts, it would be prudent to listen to the data.  That often starts
> with a .wav file, which I don't have.

Creating a wav file manually is not too difficult, it just consists of a
shortish header followed by the sampled data.  It's some time since I
dabbled in this area but, if you want, I can have a look at some old
packages to see what I can find.

ISTR that the header/file format is called RIFF, a MSDN search might turn up
something.

--
Ian

Use the Reply-To address to contact me.
Mail sent to the From address is ignored.


Reply | Threaded
Open this post in threaded view
|

Re: Sounds w/o .wav files?

Schwab,Wilhelm K
Ian,

>>Our A/D board is getting closer to service.  Since we are recording audio
>>of sorts, it would be prudent to listen to the data.  That often starts
>>with a .wav file, which I don't have.
>
>
> Creating a wav file manually is not too difficult, it just consists of a
> shortish header followed by the sampled data.  It's some time since I
> dabbled in this area but, if you want, I can have a look at some old
> packages to see what I can find.

Google found various independent statements of the same sentiment, along
with file formats.  However, they don't agree on all details, and  I
lost a little steam when Squeak's files would not play in Media Player.

Did you manage to make it work?  I would certainly be able to make use
of something that writes .wav format data.  If you think you have
something, I would greatly appreciate your searching for it.

I stumbled on something intersting: there is a flag for PlaySound() that
allows it to take data directly from memory.  It needs to be the byte
image of a .wav file, but it would allow us to create a way to play
sounds w/o a file.

Have a good one,

Bill


--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Sounds w/o .wav files?

Ian Bartholomew-19
Bill,

> Did you manage to make it work?  I would certainly be able to make use of
> something that writes .wav format data.  If you think you have something,
> I would greatly appreciate your searching for it.

OK, the following workspace code is a bit rough but it seems to work.  I've
fixed all the parameters (sample rate, channels etc.) so you'll obviously
have to adjust them for your A/D feed.  You will also need to add a
WriteStream>>nextWORDPut: method to your image.

All it does is create a 5 sec wav file containing a continuous 2205Hz tone
(22050 samples/sec / 10 samples per cycle = 2205 Hz).  I did try to make the
sound a bit more interesting but decided it was a bit too difficult in a
workspace :-)

NB.  It's a bit hazy but I seem to recall that the samplesPerSec parameter
is restricted to a specific set of values.?


format := 1 "WAVE_FORMAT_PCM".
channels := 2.
samplesPerSec := 22050.
bitsPerSample := 16.
blockAlign :=  channels * (bitsPerSample / 8). "i.e. bytes per sample"
avgBytesPerSec :=  samplesPerSec * blockAlign.

sampleCount := samplesPerSec * 5.  " 5 seconds long"
byteCount := sampleCount * blockAlign.  "bytes needed"

stream := ByteArray writeStream.

stream
  nextPutAll: 'RIFF' asByteArray;
  nextDWORDPut: 4 + 8 + 16 + 8 + byteCount;
  nextPutAll: 'WAVE' asByteArray;
  nextPutAll: 'fmt ' asByteArray;
  nextDWORDPut: 16;
  nextWORDPut:  format;
  nextWORDPut:  channels;
  nextDWORDPut:  samplesPerSec;
  nextDWORDPut:  avgBytesPerSec;
  nextWORDPut:  blockAlign;
  nextWORDPut:  bitsPerSample;
  nextPutAll: 'data' asByteArray;
  nextDWORDPut: byteCount.

5 timesRepeat: ["each second"
 2205 timesRepeat: ["22050 / 10"
    "16 bits per sample - 2 channels"
  stream
   nextDWORDPut: 16r00000000;
   nextDWORDPut: 16r10001000;
   nextDWORDPut: 16r20002000;
   nextDWORDPut: 16r10001000;
   nextDWORDPut: 16r00000000;
   nextDWORDPut: 16r00000000;
   nextDWORDPut: 16rF000F000;
   nextDWORDPut: 16rE000E000;
   nextDWORDPut: 16rF000F000;
   nextDWORDPut: 16r00000000]].

fs := FileStream write: 'test.wav' text: false.
[fs nextPutAll: stream contents] ensure: [fs close]

--
Ian

Use the Reply-To address to contact me.
Mail sent to the From address is ignored.


Reply | Threaded
Open this post in threaded view
|

Re: Sounds w/o .wav files?

Chris Uppal-3
In reply to this post by Schwab,Wilhelm K
Bill,

> [...] it would be prudent to listen to the data.  That often
> starts with a .wav file, which I don't have.  Are there any simple ways
> to start with 16 bit samples and a frequency and end up producing sound?

A couple of things I've wanted to do for a long time have needed the ability to
play generated waveforms -- ideally in an arbitrarily long stream,  so I've
been bugged by the same thing.  All the easy stuff seems to require WAV files,
and when you dig into how to play pure buffers of generated sound in -- say --
DirectSound it becomes insanely complicated [*].  In fact I couldn't get it to
work at all.

So your post prompted me to do what I should have done in the first place -- go
back to Petzold and see what the older APIs are like.  It turns out that they
are not too bad at all (more messing than I'd like, but a lot less than there
might
be -- given that it's Windows code).  A lot more straightforward than the "high
level" stuff, in fact (typical!).

I've put together a small package that turns this into a (reasonably) nice
little player object. It's /totally/ brand new code, but it does seem to work
on both Win2K and XP.   I've put it at a temporary home here:
    http://ephemera.metagnostic.org/code/WOP.zip
where it'll stay until I remember to remove it (which, at the latest will be
when I next update my "real" website -- but that could be weeks away), or until
it turns out to have fatal flaws...

I repeat the caution: this is brand new code.  Hardly tested at all, and never
yet used in anger.  But if you, or anyone, would like to take a look at it, and
either use it "as is" or as a basis for something better/different, then please
feel free.  See the class-side of WaveOutPlayer for a few example uses.

    -- chris

([*] And the Java sound APIs are no better !)


Reply | Threaded
Open this post in threaded view
|

Re: Sounds w/o .wav files?

Schwab,Wilhelm K
Chris,

>>[...] it would be prudent to listen to the data.  That often
>>starts with a .wav file, which I don't have.  Are there any simple ways
>>to start with 16 bit samples and a frequency and end up producing sound?
>
>
> A couple of things I've wanted to do for a long time have needed the ability to
> play generated waveforms -- ideally in an arbitrarily long stream,  so I've
> been bugged by the same thing.  All the easy stuff seems to require WAV files,
> and when you dig into how to play pure buffers of generated sound in -- say --
> DirectSound it becomes insanely complicated [*].  In fact I couldn't get it to
> work at all.
>
> So your post prompted me to do what I should have done in the first place -- go
> back to Petzold and see what the older APIs are like.  It turns out that they
> are not too bad at all (more messing than I'd like, but a lot less than there
> might
> be -- given that it's Windows code).  A lot more straightforward than the "high
> level" stuff, in fact (typical!).

[ WaveOutPlayer bangHeadOnWall play. ] repeat.  "When will I learn!!!! :)"

So far I have only loaded the package and run the examples, but I'm more
or less sold on it.  I will exit and backup before continuing with it
loaded.

There is probably room for a sampled sound abstraction that holds the
format and (perhaps is??) the buffer.  There might be subclasses for
stereo and mono to idiot proof the indexing.

Question: might #mono, #mono: (and likewise for stereo) cause confusion?
    It might be better to encounter #monoSize:samplesPerSecond: to
emphasize what is being decided.  Perhaps I am missing something related
to streaming??

This looks great.  Thanks!!!

Bill


--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Sounds w/o .wav files?

Chris Uppal-3
Bill,

> There is probably room for a sampled sound abstraction that holds the
> format and (perhaps is??) the buffer.  There might be subclasses for
> stereo and mono to idiot proof the indexing.

There's certainly a /lot/ of room for more abstraction.  It's very "Windowsy"
as it is.  That's mostly because I didn't (don't) have enough experience of
what works and how it works to be confident that I was creating an appropriate
abstraction.

For instance, I only discovered late yesterday that the layout of >8-bit
buffers uses signed integers.  My code had worked fine with 8-bit buffers
assuming unsigned bytes, but it sounded "odd" using 16-bit buffers.  Only when
I'd found out about that inconsistency (and fixed the code) did it work.  And
that's the problem: up until yesterday afternoon I'd had no idea that the
abstraction might want to hide the difference between 8- and 16- bit sound.
Now I'm tempted to put a layer around the buffers that makes them "look" as if
they all contain data in the [-1.0, +1.0] range.  But a problem with that is
efficiency, the floating point calculations are expensive, and /need/ to be
optimised -- which makes abstraction difficult.  In any case, I'd imagine that
in most applications (mine, anyway ;-) the data will come from somewhere else,
such as being generated in a helper DLL, rather than created directly from
Smalltalk code, so it's not too clear that the abstraction would pay for
itself.  I'm not saying it wouldn't -- I just don't know yet.

Right now, if I were re-engineering this, I think I'd have a SoundStage (which
basically holds a WAVEFORMAT and a number of internal Players) to which you
could add SoundSources (which could be single buffers, lists of buffers, files,
or automatically recycling rings of buffers).  The notion of a buffer would
almost vanish, or at least would loose its Windowsy flavour, and the Players
would be hidden entirely.  This is, of course, a bad case of "second system
effect".  What's more it could become almost as complicated as the DirectSound
stuff that I was trying to avoid in the first place ;-)


> Question: might #mono, #mono: (and likewise for stereo) cause confusion?

Possibly.  Those are only convenient short-hand methods anyway, since there
isn't a preset list of valid buffer configurations.  The choice (in my mind)
was actually between:
        WAVEHDR mono: 16.
or:
        WAVEHDR mono16.
or:
        WAVEHDR mono16bit.
The first seemed short and sweet.  If you want to be explicit then:
        (WAVEHDR new)
            nBitsPerSample: 16
            yourself.
is even better, and would be better still if I bothered to provide sensible
aliases for the Windows accessor names (which I really /ought/ to do...).

BTW, I found a bug in the device capabilities stuff.  I've updated the
temporary webpage with the new version (1.03), but probably won't make any more
changes (barring major bugs) till it gets put on the real website (where
there's a chance it'll include some of the above improvements, and whatever
else occurs to me as I start actually /using/ it...).

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Sounds w/o .wav files?

Janos Kazsoki
In reply to this post by Ian Bartholomew-19
Ian,

in my 5.1.4 I get a walkback telling:
WriteStream does not understand #nextWORDPut:

And really: I see only a nextSDWORDPut: anInteger

Am I missing some extensions?

Thanks,
Janos


Reply | Threaded
Open this post in threaded view
|

Re: Sounds w/o .wav files?

Ian Bartholomew-19
Janos,

> Am I missing some extensions?

I mentioned in the post that adding a #nextWORDPut: method would be needed,
it doesn't come with the Dolphin image.  It's just ....

WriteStream>>nextWORDPut: anInteger
 self nextPutAll: ((ByteArray new: 2)
    wordAtOffset: 0 put: anInteger;
    yourself).
 ^anInteger

--
Ian

Use the Reply-To address to contact me.
Mail sent to the From address is ignored.


Reply | Threaded
Open this post in threaded view
|

Re: Sounds w/o .wav files?

Janos Kazsoki
Ian,

I know it is only a side branch from the main stream...

NextWordPut: is not a problem. The problem is the nextDWORDPut: with
the value
nextDWORDPut: 16rF000F000

I just took the nextSDWORDPut: instead, and unfortunately it calls
sdwordAtOffset: 0 put: anInteger;
 and the anInteger must not be bigger than 16r3FFFFFFF, because it is
supposed to be signed integer.

I tried to call sqwordAtOffset: 0 put: instead, it gave of course Out
of Bound with a ByteArray of size 4. With size 8 the wav file was not
playable.

Do we have a kind of unsigned integer, where we can use the whole range
of the 4 bytes?

Thanks,
Janos


Reply | Threaded
Open this post in threaded view
|

Re: Sounds w/o .wav files?

Chris Uppal-3
Janos,

> NextWordPut: is not a problem. The problem is the nextDWORDPut: with
> the value
> nextDWORDPut: 16rF000F000

This is the implementation I use:

=================
nextDWORDPut: anInteger
 "Append a 32-bit unsigned integer in 2's complement representation
 as the next 4 bytes on the receiver."

#CUadded.

"#dwordAtOffset:put: doesn't check for negative numbers"
 (anInteger < 0) ifTrue: [^ self errorCantHold: anInteger].

 self nextPutAll:
  ((ByteArray new: 4)
   dwordAtOffset: 0 put: anInteger;
   yourself).

 ^anInteger.
=================

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Sounds w/o .wav files?

Janos Kazsoki
Chris, Ian,

it was my ignorance.

Yes, using dwordAtOffset: 0 put: instead of sdwordAtOffset: 0 put: has
solved it.

Only one character difference on the face of it.

Yes, after that also studying the ByteArray methods is enlightening,
and I see the difference...

Now it works fine.

Many thanks for your patience with the struggling of a newbie,
Janos


Reply | Threaded
Open this post in threaded view
|

Re: Sounds w/o .wav files?

Ian Bartholomew-19
In reply to this post by Janos Kazsoki
Janos,

> NextWordPut: is not a problem. The problem is the nextDWORDPut: with
> the value
> nextDWORDPut: 16rF000F000

Sorry, my mistake.  Dolphin 6 does have a #nextDWORDPut: in the basic image
and I incorrectly assumed it was present in Dolphin 5.

Chris has posted the missing method (thanks Chris).

--
Ian

Use the Reply-To address to contact me.
Mail sent to the From address is ignored.


Reply | Threaded
Open this post in threaded view
|

Re: Sounds w/o .wav files?

Schwab,Wilhelm K
In reply to this post by Janos Kazsoki
Janos,

> Do we have a kind of unsigned integer, where we can use the whole range
> of the 4 bytes?

FWIW, see the code below.  Please let me know if you have any problems
with it.  It should probably be higher in the hierarchy; suggestions are
welcome.

Have a good one,

Bill


!WriteStream methodsFor!

nextDWORDPut: anInteger
        "Append a 32-bit unsigned integer in 2's complement representation
        as the next 4 bytes on the receiver."

        self nextPutAll:
                ((ByteArray new: 4)
                        dwordAtOffset: 0 put: anInteger;
                        yourself)! !
!WriteStream categoriesFor: #nextDWORDPut:!binary filing!public! !



--
Wilhelm K. Schwab, Ph.D.
[hidden email]