Added start silence skipping and end silence detection
parent
1e0303b1a3
commit
a8b01f16e3
|
@ -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 */,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue