Added start silence skipping and end silence detection

CQTexperiment
Chris Moeller 2013-10-21 02:52:43 -07:00
parent 1e0303b1a3
commit a8b01f16e3
4 changed files with 177 additions and 17 deletions

View File

@ -148,6 +148,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
8324C584181513A10046F78F /* circular_buffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = circular_buffer.h; sourceTree = "<group>"; };
8343780B17F932B600584396 /* HCDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HCDecoder.h; sourceTree = "<group>"; };
8343780E17F932C900584396 /* Plugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Plugin.h; path = ../../../Audio/Plugin.h; sourceTree = "<group>"; };
8343784A17F93CB500584396 /* psflib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = psflib.xcodeproj; path = ../../Frameworks/psflib/psflib.xcodeproj; sourceTree = "<group>"; };
@ -269,6 +270,7 @@
8360EEED17F92AC8005208A4 /* HighlyComplete */ = {
isa = PBXGroup;
children = (
8324C584181513A10046F78F /* circular_buffer.h */,
834379A717F9818400584396 /* HCDecoder.mm */,
8343786117F944BD00584396 /* hebios.h */,
8343780E17F932C900584396 /* Plugin.h */,

View File

@ -8,13 +8,16 @@
#import <Cocoa/Cocoa.h>
#import "Plugin.h"
#include "circular_buffer.h"
@interface HCDecoder : NSObject<CogDecoder,CogMetadataReader> {
id<CogSource> currentSource;
NSString *currentUrl;
uint8_t *emulatorCore;
void *emulatorExtra;
circular_buffer<int16_t> silence_test_buffer;
NSDictionary *metadataList;
int tagLengthMs;

View File

@ -1091,7 +1091,14 @@ static int twosf_info(void * context, const char * name, const char * value)
else return NO;
framesRead = 0;
silence_test_buffer.resize( sampleRate * 30 * 2 );
if (![self fillBuffer])
return NO;
silence_test_buffer.remove_leading_silence(1);
return YES;
}
@ -1158,15 +1165,23 @@ static int twosf_info(void * context, const char * name, const char * value)
return YES;
}
- (int)readAudio:(void *)buf frames:(UInt32)frames
- (BOOL)fillBuffer
{
if ( !emulatorCore )
unsigned long free_space = silence_test_buffer.free_space() / 2;
while ( free_space )
{
if (![self initializeDecoder])
return 0;
unsigned long samples_to_write = 0;
int16_t * buf = silence_test_buffer.get_write_ptr( samples_to_write );
int samples_read = [self readAudioInternal:buf frames:(UInt32)samples_to_write / 2] * 2;
if ( !samples_read ) break;
silence_test_buffer.samples_written( samples_read );
free_space -= samples_read;
}
return !silence_test_buffer.test_silence();
}
- (int)readAudioInternal:(void *)buf frames:(UInt32)frames
{
if ( type == 1 || type == 2 )
{
uint32_t howmany = frames;
@ -1224,28 +1239,48 @@ static int twosf_info(void * context, const char * name, const char * value)
frames = howmany;
}
if ( framesRead + frames > framesLength ) {
return frames;
}
- (int)readAudio:(void *)buf frames:(UInt32)frames
{
if ( !emulatorCore )
{
if (![self initializeDecoder])
return 0;
}
else if ( ![self fillBuffer] )
return 0;
unsigned long written = silence_test_buffer.data_available() / 2;
if ( written > frames )
written = frames;
if ( written > totalFrames - framesRead )
written = totalFrames - framesRead;
if ( written == 0 )
return 0;
silence_test_buffer.read( (int16_t *) buf, written * 2 );
if ( framesRead + written > framesLength ) {
long fadeStart = (framesLength > framesRead) ? framesLength : framesRead;
long fadeEnd = framesRead + frames;
long fadeEnd = framesRead + written;
long fadeTotal = totalFrames - framesLength;
long fadePos;
int16_t * buf16 = ( int16_t * ) buf;
for (fadePos = fadeStart; fadePos < fadeEnd && fadePos < totalFrames; ++fadePos) {
for (fadePos = fadeStart; fadePos < fadeEnd; ++fadePos) {
long scale = totalFrames - fadePos;
buf16[ 0 ] = buf16[ 0 ] * scale / fadeTotal;
buf16[ 1 ] = buf16[ 1 ] * scale / fadeTotal;
buf16 += 2;
}
if (fadePos < fadeEnd)
frames = (int)(fadePos - fadeStart);
}
framesRead += frames;
return frames;
framesRead += written;
return (int) written;
}
- (void)closeDecoder
@ -1308,6 +1343,20 @@ static int twosf_info(void * context, const char * name, const char * value)
return -1;
}
unsigned long buffered_samples = silence_test_buffer.data_available() / 2;
if ( buffered_samples >= ( frame - framesRead ) )
{
frame -= framesRead;
silence_test_buffer.read( NULL, frame * 2 );
framesRead += frame * 2;
return framesRead;
}
else if ( buffered_samples )
{
silence_test_buffer.read( NULL, buffered_samples * 2 );
framesRead += buffered_samples * 2;
}
if ( type == 1 || type == 2 )
{
do

View File

@ -0,0 +1,106 @@
#ifndef _CIRCULAR_BUFFER_H_
#define _CIRCULAR_BUFFER_H_
#include <algorithm>
#include <vector>
long const silence_threshold = 8;
template <typename T>
class circular_buffer
{
std::vector<T> buffer;
unsigned long readptr, writeptr, used, size;
unsigned long silence_count;
public:
circular_buffer() : readptr( 0 ), writeptr( 0 ), size( 0 ), used( 0 ), silence_count( 0 ) { }
unsigned long data_available() { return used; }
unsigned long free_space() { return size - used; }
T* get_write_ptr( unsigned long & count_out )
{
count_out = size - writeptr;
if ( count_out > size - used ) count_out = size - used;
return &buffer[writeptr];
}
bool samples_written( unsigned long count )
{
unsigned long max_count = size - writeptr;
if ( max_count > size - used ) max_count = size - used;
if ( count > max_count ) return false;
silence_count += count_silent( &buffer[ 0 ] + writeptr, &buffer[ 0 ] + writeptr + count );
used += count;
writeptr = ( writeptr + count ) % size;
return true;
}
unsigned long read( T * dst, unsigned long count )
{
unsigned long done = 0;
for(;;)
{
unsigned long delta = size - readptr;
if ( delta > used ) delta = used;
if ( delta > count ) delta = count;
if ( !delta ) break;
if ( dst ) std::copy( buffer.begin() + readptr, buffer.begin() + readptr + delta, dst );
silence_count -= count_silent( &buffer[ 0 ] + readptr, &buffer[ 0 ] + readptr + delta );
if ( dst ) dst += delta;
done += delta;
readptr = ( readptr + delta ) % size;
count -= delta;
used -= delta;
}
return done;
}
void reset()
{
readptr = writeptr = used = 0;
}
void resize(unsigned long p_size)
{
size = p_size;
buffer.resize( p_size );
reset();
}
bool test_silence() const
{
return silence_count == used;
}
void remove_leading_silence( unsigned long mask )
{
T const* p;
T const* begin;
T const* end;
mask = ~mask;
if ( used )
{
p = begin = &buffer[ 0 ] + readptr - 1;
end = &buffer[ 0 ] + ( writeptr > readptr ? writeptr : size );
while ( ++p < end && ( ( unsigned long ) ( *p + silence_threshold ) <= ( unsigned long ) silence_threshold * 2 ) );
unsigned long skipped = ( p - begin ) & mask;
silence_count -= skipped;
used -= skipped;
readptr = ( readptr + skipped ) % size;
if ( readptr == 0 && readptr != writeptr )
{
p = begin = &buffer[ 0 ];
end = &buffer[ 0 ] + writeptr;
while ( ++p < end && ( ( unsigned long ) ( *p + silence_threshold ) <= ( unsigned long ) silence_threshold * 2 ) );
skipped = ( p - begin ) & mask;
silence_count -= skipped;
used -= skipped;
readptr += skipped;
}
}
}
private:
static unsigned long count_silent(T const* begin, T const* end)
{
unsigned long count = 0;
T const* p = begin - 1;
while ( ++p < end ) count += ( ( unsigned long ) ( *p + silence_threshold ) <= ( unsigned long ) silence_threshold * 2 );
return count;
}
};
#endif