SoundStream.st
changeset 5407 7e6fb7096445
parent 5406 23d4715dbf4f
child 5408 909d03dd2329
equal deleted inserted replaced
5406:23d4715dbf4f 5407:7e6fb7096445
  1509 
  1509 
  1510 playSineF32:freq forSeconds:nSeconds
  1510 playSineF32:freq forSeconds:nSeconds
  1511     "output some tone for some time
  1511     "output some tone for some time
  1512      in F32 audioFormat - a test method"
  1512      in F32 audioFormat - a test method"
  1513 
  1513 
  1514     |buffer numSamples val scale isUnsigned restSamples|
  1514     |buffer numSamples val scale restSamples numChannels|
  1515 
  1515 
  1516     (audioFormat == #F32) ifFalse:[
  1516     (audioFormat == #F32) ifFalse:[
  1517 	self error:'must be in float mode' mayProceed:true.
  1517         self error:'must be in float mode' mayProceed:true.
  1518     ].
  1518     ].
  1519 
  1519 
  1520     numSamples := self sampleRate.
  1520     numSamples := self sampleRate.
  1521     buffer := FloatArray new:numSamples.
  1521     numChannels := self numberOfChannels.
       
  1522     buffer := FloatArray new:(numSamples * numChannels).
  1522 
  1523 
  1523     "fill it with a sine wave"
  1524     "fill it with a sine wave"
  1524 
  1525 
  1525     scale := freq * 2 * (Float pi).
  1526     scale := freq * 2 * (Float pi).
  1526     1 to:numSamples do:[:i |
  1527     numChannels == 2 ifTrue:[
  1527 	val := (scale * i / self sampleRate) sin.
  1528         1 to:numSamples do:[:i |
  1528 	buffer at:i put:val
  1529             val := (scale * i / self sampleRate) sin.
       
  1530             buffer at:(i-1)*2 put:val.
       
  1531             buffer at:(i-1)*2+1 put:0.
       
  1532         ].
       
  1533     ] ifFalse:[
       
  1534         1 to:numSamples do:[:i |
       
  1535             val := (scale * i / self sampleRate) sin.
       
  1536             buffer at:i put:val
       
  1537         ].
  1529     ].
  1538     ].
  1530 
  1539 
  1531     1 to:nSeconds truncated do:[:s |
  1540     1 to:nSeconds truncated do:[:s |
  1532 	self nextPutBytes:(numSamples*4) from:buffer startingAt:1
  1541         self nextPutBytes:(numSamples*4) from:buffer startingAt:1
  1533     ].
  1542     ].
  1534     restSamples := ((nSeconds - nSeconds truncated) * numSamples) truncated.
  1543     restSamples := ((nSeconds - nSeconds truncated) * numSamples) truncated.
  1535     restSamples > 0 ifTrue:[
  1544     restSamples > 0 ifTrue:[
  1536 	self nextPutBytes:(restSamples*4) from:buffer startingAt:1
  1545         self nextPutBytes:(restSamples*4) from:buffer startingAt:1
  1537     ].
  1546     ].
  1538 
  1547 
  1539     "
  1548     "
  1540      SoundStream writing setAudioFormat:#F32; playSineF32:440 forSeconds:2; close
  1549      SoundStream writing setAudioFormat:#F32; playSineF32:440 forSeconds:2; close
  1541      SoundStream writing setAudioFormat:#F32; playSineF32:880 forSeconds:2; close
  1550      SoundStream writing setAudioFormat:#F32; playSineF32:880 forSeconds:2; close
  1585     "output some tone for nSeconds in S16 audioFormat - a test method"
  1594     "output some tone for nSeconds in S16 audioFormat - a test method"
  1586 
  1595 
  1587     |buffer numSamples val scale restSamples|
  1596     |buffer numSamples val scale restSamples|
  1588 
  1597 
  1589     (audioFormat startsWith:#U16) ifFalse:[
  1598     (audioFormat startsWith:#U16) ifFalse:[
  1590 	(audioFormat startsWith:#S16) ifFalse:[
  1599         (audioFormat startsWith:#S16) ifFalse:[
  1591 	    self error:'must be in 16bit mode' mayProceed:true.
  1600             self error:'must be in 16bit mode' mayProceed:true.
  1592 	    ^ self
  1601             ^ self
  1593 	]
  1602         ]
  1594     ].
  1603     ].
  1595 
  1604 
  1596     "allocate memory for 1 sec playing time"
  1605     "allocate memory for 1 sec playing time"
  1597     numSamples := self sampleRate.
  1606     numSamples := self sampleRate.
  1598     buffer := WordArray new:numSamples.
  1607     buffer := WordArray new:numSamples.
  1599 
  1608 
  1600     "fill it with a sine wave"
  1609     "fill it with a sine wave"
  1601 
  1610 
  1602     scale := freq * 2 * (Float pi).
  1611     scale := freq * 2 * (Float pi).
  1603     1 to:numSamples do:[:i |
  1612     1 to:numSamples do:[:i |
  1604 	val := (scale * i / numSamples) sin.
  1613         val := (scale * i / numSamples) sin.
  1605 	val := (val * 16r7FFF) rounded.
  1614         val := (val * 16r7FFF) rounded.
  1606 	audioFormat == #U16 ifTrue:[
  1615         audioFormat == #U16 ifTrue:[
  1607 	    val := val + 16r8000
  1616             val := val + 16r8000
  1608 	].
  1617         ].
  1609 	buffer at:i put:(val bitAnd:16rFFFF)
  1618         buffer at:i put:(val bitAnd:16rFFFF)
  1610     ].
  1619     ].
  1611 
  1620 
  1612     1 to:nSeconds truncated do:[:s |
  1621     1 to:nSeconds truncated do:[:s |
  1613 	self nextPutBytes:(numSamples*2) from:buffer startingAt:1
  1622         self nextPutBytes:(numSamples*2) from:buffer startingAt:1
  1614     ].
  1623     ].
  1615     restSamples := ((nSeconds - nSeconds truncated) * numSamples) truncated.
  1624     restSamples := ((nSeconds - nSeconds truncated) * numSamples) truncated.
  1616     restSamples > 0 ifTrue:[
  1625     restSamples > 0 ifTrue:[
  1617 	self nextPutBytes:(restSamples*2) from:buffer startingAt:1
  1626         self nextPutBytes:(restSamples*2) from:buffer startingAt:1
  1618     ].
  1627     ].
  1619 
  1628 
  1620     "of course, the frequency should be below half the
  1629     "of course, the frequency should be below half the
  1621      sampleRate - hear below ...
  1630      sampleRate - hear below ...
  1622 
  1631 
  1623      SoundStream writing setSampleRate:4000; tuneTone16:440; close
  1632      SoundStream writing setSampleRate:4000; tuneTone16:440 seconds:1; close
  1624      SoundStream writing setSampleRate:8000; tuneTone16:440; close
  1633      SoundStream writing setSampleRate:8000; tuneTone16:440 seconds:1; close
  1625      SoundStream writing setSampleRate:10000; tuneTone16:440; close
  1634      SoundStream writing setSampleRate:10000; tuneTone16:440 seconds:1; close
  1626      SoundStream writing setSampleRate:20000; tuneTone16:440; close
  1635      SoundStream writing setSampleRate:20000; tuneTone16:440 seconds:1; close
  1627      SoundStream writing setSampleRate:40000; tuneTone16:440; close
  1636      SoundStream writing setSampleRate:40000; tuneTone16:440 seconds:1; close
       
  1637      SoundStream writing tuneTone16:440 seconds:1; close
  1628     "
  1638     "
  1629 
  1639 
  1630     "Modified: / 21.12.1998 / 09:11:30 / cg"
  1640     "Modified: / 21.12.1998 / 09:11:30 / cg"
  1631 !
  1641 !
  1632 
  1642 
  3437 	"normally not reached"
  3447 	"normally not reached"
  3438 	^ nil.
  3448 	^ nil.
  3439     ].
  3449     ].
  3440     self registerForFinalization.
  3450     self registerForFinalization.
  3441 
  3451 
       
  3452 !
       
  3453 
       
  3454 reopenStream
       
  3455     |ok errorStringOrNil error|
       
  3456 
       
  3457 %{
       
  3458 #ifdef SUPPORT_PORTAUDIO
       
  3459     static PaStreamParameters outputParameters;
       
  3460     PaStream *stream;
       
  3461     PaError paErr;
       
  3462     struct paStreamData* paStreamData;
       
  3463     int nChannels, sampleRate, bytesPerSample;
       
  3464 #   define FRAMES_PER_BUFFER 128
       
  3465 
       
  3466     ok = false;
       
  3467 
       
  3468     /* default output device */
       
  3469     outputParameters.device = Pa_GetDefaultOutputDevice();
       
  3470     if (outputParameters.device == paNoDevice) {
       
  3471         fprintf(stderr, "SoundStream [warning]: No default output device.\n");
       
  3472         errorStringOrNil = __MKSTRING("No default output device");
       
  3473         goto out;
       
  3474     }
       
  3475 
       
  3476     if (__isSmallInteger(__INST(numberOfChannels))) {
       
  3477         nChannels = __intVal(__INST(numberOfChannels));
       
  3478     } else {
       
  3479         nChannels = 1;
       
  3480     }
       
  3481     outputParameters.channelCount = nChannels;
       
  3482     outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
       
  3483     outputParameters.hostApiSpecificStreamInfo = NULL;
       
  3484 
       
  3485     // The standard formats paFloat32, paInt16, paInt32, paInt24, paInt8
       
  3486     // and aUInt8 are usually implemented by all implementations.
       
  3487     // The floating point representation (paFloat32) uses +1.0 and -1.0 as the
       
  3488     // maximum and minimum respectively.
       
  3489     // paUInt8 is an unsigned 8 bit format where 128 is considered "ground"
       
  3490 
       
  3491     if (__INST(audioFormat) == @symbol(S16)) {
       
  3492         outputParameters.sampleFormat = paInt16;
       
  3493         bytesPerSample = 2;
       
  3494     } else if (__INST(audioFormat) == @symbol(S32)) {
       
  3495         outputParameters.sampleFormat = paInt32;
       
  3496         bytesPerSample = 4;
       
  3497     } else if (__INST(audioFormat) == @symbol(S24)) {
       
  3498         outputParameters.sampleFormat = paInt24;
       
  3499         bytesPerSample = 3;
       
  3500     } else if (__INST(audioFormat) == @symbol(S8)) {
       
  3501         outputParameters.sampleFormat = paInt8;
       
  3502         bytesPerSample = 1;
       
  3503     } else if (__INST(audioFormat) == @symbol(F32)) {
       
  3504         outputParameters.sampleFormat = paFloat32;
       
  3505         bytesPerSample = 4;
       
  3506     } else if (__INST(audioFormat) == @symbol(U8)) {
       
  3507         outputParameters.sampleFormat = paUInt8;
       
  3508         bytesPerSample = 1;
       
  3509     } else {
       
  3510         fprintf(stderr, "SoundStream [warning]: unknown format - using U8\n");
       
  3511         outputParameters.sampleFormat = paUInt8;
       
  3512         bytesPerSample = 1;
       
  3513     }
       
  3514 
       
  3515     if (__isSmallInteger(__INST(sampleRate))) {
       
  3516         sampleRate = __intVal(__INST(sampleRate));
       
  3517     } else {
       
  3518         fprintf(stderr, "SoundStream [warning]: using default sampleRate 8000\n");
       
  3519         sampleRate = 8000;
       
  3520     }
       
  3521 
       
  3522     paStreamData = (struct paStreamData*)malloc(sizeof(struct paStreamData));
       
  3523     if (paStreamData == NULL) {
       
  3524         fprintf(stderr, "SoundStream [warning]: failed to allocate paStream\n");
       
  3525         errorStringOrNil = __MKSTRING("failed to allocate paStream");
       
  3526         goto out;
       
  3527     }
       
  3528 
       
  3529     paErr = Pa_OpenStream(
       
  3530               &stream,
       
  3531               NULL, /* no input */
       
  3532               &outputParameters,
       
  3533               sampleRate,
       
  3534               FRAMES_PER_BUFFER,
       
  3535               paClipOff,      /* we won't output out of range samples so don't bother clipping them */
       
  3536               paCallback,
       
  3537               paStreamData );
       
  3538 
       
  3539     if (paErr != paNoError) {
       
  3540         fprintf(stderr, "SoundStream [warning]: openStream: %s\n", Pa_GetErrorText( paErr ));
       
  3541         free(paStreamData);
       
  3542         errorStringOrNil = __MKSTRING(Pa_GetErrorText( paErr ));
       
  3543         goto out;
       
  3544     }
       
  3545     paStreamData->stream = stream;
       
  3546 
       
  3547     paStreamData->readOffset = 0;
       
  3548     paStreamData->bytesPerSample = bytesPerSample;
       
  3549     paStreamData->nChannels = nChannels;
       
  3550 
       
  3551     paStreamData->currentBuffer = NULL;
       
  3552     paStreamData->lastBuffer = NULL;
       
  3553     paStreamData->freeList = NULL;
       
  3554     paStreamData->hasFinished = 0;
       
  3555 
       
  3556     ok = true;
       
  3557 out:;
       
  3558 #endif /* SUPPORT_PORTAUDIO */
       
  3559 
       
  3560 %}.
       
  3561     ok == false ifTrue:[
       
  3562         lastErrorString := errorStringOrNil.
       
  3563         lastErrorNumber := error ? -1.
       
  3564         self openError:error.
       
  3565         "normally not reached"
       
  3566         ^ nil.
       
  3567     ].
  3442 ! !
  3568 ! !
  3443 
  3569 
  3444 !SoundStream::PortAudio methodsFor:'private'!
  3570 !SoundStream::PortAudio methodsFor:'private'!
  3445 
  3571 
  3446 initialize
  3572 initialize
  3451     (IsInitialized ? false) ifFalse:[
  3577     (IsInitialized ? false) ifFalse:[
  3452 	self class primitiveInitializeDevice
  3578 	self class primitiveInitializeDevice
  3453     ].
  3579     ].
  3454 
  3580 
  3455     "Created: 17.11.1995 / 17:28:14 / cg"
  3581     "Created: 17.11.1995 / 17:28:14 / cg"
       
  3582 !
       
  3583 
       
  3584 setAudioFormat:aSymbol
       
  3585     super setAudioFormat:aSymbol.
       
  3586     self reopenStream
       
  3587 !
       
  3588 
       
  3589 setChannels:numChannels
       
  3590     super setChannels:numChannels.
       
  3591     self reopenStream
       
  3592 !
       
  3593 
       
  3594 setFragmentSize:blockSize
       
  3595     super setFragmentSize:blockSize.
       
  3596     self reopenStream
       
  3597 !
       
  3598 
       
  3599 setSampleRate:hz
       
  3600     super setSampleRate:hz.
       
  3601     self reopenStream
  3456 ! !
  3602 ! !
  3457 
  3603 
  3458 !SoundStream::PortAudio methodsFor:'queries'!
  3604 !SoundStream::PortAudio methodsFor:'queries'!
  3459 
  3605 
  3460 supportedAudioFormats
  3606 supportedAudioFormats