added PD180 support and made image size more flexible

This commit is contained in:
Ahmet Inan 2015-02-02 00:04:40 +01:00
parent 805789bfa6
commit e940f8b3b6
12 changed files with 162 additions and 40 deletions

View file

@ -37,6 +37,8 @@ public class Decoder {
private final int channelConfig = AudioFormat.CHANNEL_IN_MONO;
private final int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
private final int sampleRate = 44100;
private final int maxHeight = freeRunReserve(496);
private final int maxWidth = 640;
private final short[] audioBuffer;
private final int[] pixelBuffer;
private final int[] spectrumBuffer;
@ -70,6 +72,7 @@ public class Decoder {
private final int mode_scottie2 = 6;
private final int mode_scottieDX = 7;
private final int mode_wrasseSC2_180 = 8;
private final int mode_pd180 = 9;
private final Thread thread = new Thread() {
@Override
@ -80,7 +83,7 @@ public class Decoder {
return;
if (drawImage) {
image.drawCanvas();
if(enableAnalyzer) {
if (enableAnalyzer) {
spectrum.drawCanvas();
spectrogram.drawCanvas();
meter.drawCanvas();
@ -98,7 +101,7 @@ public class Decoder {
this.spectrum = spectrum;
this.meter = meter;
this.activity = activity;
pixelBuffer = new int[image.bitmap.getWidth() * image.bitmap.getHeight()];
pixelBuffer = new int[maxWidth * maxHeight];
spectrumBuffer = new int[spectrum.bitmap.getWidth() * spectrum.bitmap.getHeight()];
spectrogramBuffer = new int[spectrogram.bitmap.getWidth() * spectrogram.bitmap.getHeight()];
@ -142,8 +145,7 @@ public class Decoder {
rsDecoder.bind_saved_height(rsDecoderSavedHeight);
rsDecoder.bind_volume(rsDecoderVolume);
rsDecoder.bind_saved_buffer(rsDecoderSavedBuffer);
rsDecoder.invoke_initialize(sampleRate, valueBufferLength,
image.bitmap.getWidth(), image.bitmap.getHeight(),
rsDecoder.invoke_initialize(sampleRate, valueBufferLength, maxWidth, maxHeight,
spectrum.bitmap.getWidth(), spectrum.bitmap.getHeight(),
spectrogram.bitmap.getWidth(), spectrogram.bitmap.getHeight());
@ -166,8 +168,9 @@ public class Decoder {
void scottie2_mode() { rsDecoder.invoke_scottie2_mode(); }
void scottieDX_mode() { rsDecoder.invoke_scottieDX_mode(); }
void wrasseSC2_180_mode() { rsDecoder.invoke_wrasseSC2_180_mode(); }
void pd180_mode() { rsDecoder.invoke_pd180_mode(); }
int freeRunReserve(int height) { return (height * 3) / 2; }
void increaseUpdateRate() { updateRate = Math.min(4, updateRate + 1); }
void decreaseUpdateRate() { updateRate = Math.max(0, updateRate - 1); }
void updateTitle(int id) { activity.updateTitle(activity.getString(id)); }
@ -176,50 +179,45 @@ public class Decoder {
{
switch (mode) {
case mode_raw:
image.imageWidth = image.bitmap.getWidth();
image.imageHeight = image.bitmap.getHeight();
image.setImageResolution(maxWidth, maxHeight);
updateTitle(R.string.action_raw_mode);
break;
case mode_robot36:
image.imageWidth = 320;
image.imageHeight = 240;
image.setImageResolution(320, freeRunReserve(240));
updateTitle(R.string.action_robot36_mode);
break;
case mode_robot72:
image.imageWidth = 320;
image.imageHeight = 240;
image.setImageResolution(320, freeRunReserve(240));
updateTitle(R.string.action_robot72_mode);
break;
case mode_martin1:
image.imageWidth = 320;
image.imageHeight = 256;
image.setImageResolution(320, freeRunReserve(256));
updateTitle(R.string.action_martin1_mode);
break;
case mode_martin2:
image.imageWidth = 320;
image.imageHeight = 256;
image.setImageResolution(320, freeRunReserve(256));
updateTitle(R.string.action_martin2_mode);
break;
case mode_scottie1:
image.imageWidth = 320;
image.imageHeight = 256;
image.setImageResolution(320, freeRunReserve(256));
updateTitle(R.string.action_scottie1_mode);
break;
case mode_scottie2:
image.imageWidth = 320;
image.imageHeight = 256;
image.setImageResolution(320, freeRunReserve(256));
updateTitle(R.string.action_scottie2_mode);
break;
case mode_scottieDX:
image.imageWidth = 320;
image.imageHeight = 256;
image.setImageResolution(320, freeRunReserve(256));
updateTitle(R.string.action_scottieDX_mode);
break;
case mode_wrasseSC2_180:
image.imageWidth = 320;
image.imageHeight = 256;
image.setImageResolution(320, freeRunReserve(256));
updateTitle(R.string.action_wrasseSC2_180_mode);
break;
case mode_pd180:
image.setImageResolution(640, freeRunReserve(496));
updateTitle(R.string.action_pd180_mode);
break;
default:
break;
}
@ -256,12 +254,13 @@ public class Decoder {
rsDecoderAudioBuffer.copyFrom(audioBuffer);
rsDecoder.invoke_decode(samples);
rsDecoderPixelBuffer.copyTo(pixelBuffer);
image.bitmap.setPixels(pixelBuffer, 0, image.bitmap.getWidth(), 0, 0, image.bitmap.getWidth(), image.bitmap.getHeight());
rsDecoderCurrentMode.copyTo(currentMode);
switch_mode(currentMode[0]);
rsDecoderPixelBuffer.copyTo(pixelBuffer);
image.setPixels(pixelBuffer);
rsDecoderVolume.copyTo(volume);
meter.volume = volume[0];

View file

@ -29,20 +29,36 @@ import android.graphics.Paint;
public class ImageView extends SurfaceView implements SurfaceHolder.Callback {
private int canvasWidth = -1, canvasHeight = -1;
private boolean cantTouchThis = true;
public int imageWidth = 320;
public int imageHeight = 240;
private int imageWidth = -1;
private int imageHeight = -1;
public boolean intScale = false;
private final SurfaceHolder holder;
public final Bitmap bitmap;
public Bitmap bitmap = null;
private final Paint paint;
public ImageView(Context context, AttributeSet attrs) {
super(context, attrs);
holder = getHolder();
holder.addCallback(this);
paint = new Paint(Paint.FILTER_BITMAP_FLAG);
bitmap = Bitmap.createBitmap(320, 384, Bitmap.Config.ARGB_8888);
}
public void setImageResolution(int width, int height) {
synchronized (holder) {
if (width != imageWidth || height != imageHeight) {
imageWidth = width;
imageHeight = height;
if (bitmap != null)
bitmap.recycle();
bitmap = Bitmap.createBitmap(imageWidth, imageHeight, Bitmap.Config.ARGB_8888);
}
}
}
public void setPixels(int pixels[]) {
synchronized (holder) {
bitmap.setPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
@ -67,7 +83,7 @@ public class ImageView extends SurfaceView implements SurfaceHolder.Callback {
void drawCanvas() {
synchronized (holder) {
if (cantTouchThis)
if (cantTouchThis || bitmap == null)
return;
Canvas canvas = null;
try {

View file

@ -240,6 +240,9 @@ public class MainActivity extends Activity {
case R.id.action_wrasseSC2_180_mode:
decoder.wrasseSC2_180_mode();
return true;
case R.id.action_pd180_mode:
decoder.pd180_mode();
return true;
}
return super.onOptionsItemSelected(item);
}

View file

@ -42,6 +42,8 @@
android:orderInCategory="100" android:showAsAction="never" />
<item android:id="@+id/action_robot72_mode" android:title="@string/action_robot72_mode"
android:orderInCategory="100" android:showAsAction="never" />
<item android:id="@+id/action_pd180_mode" android:title="@string/action_pd180_mode"
android:orderInCategory="100" android:showAsAction="never" />
<item android:id="@+id/action_martin1_mode" android:title="@string/action_martin1_mode"
android:orderInCategory="100" android:showAsAction="never" />
<item android:id="@+id/action_martin2_mode" android:title="@string/action_martin2_mode"

View file

@ -13,6 +13,7 @@
<string name="action_raw_mode">Raw Mode</string>
<string name="action_robot36_mode">Robot36 Mode</string>
<string name="action_robot72_mode">Robot72 Mode</string>
<string name="action_pd180_mode">PD180 Mode</string>
<string name="action_martin1_mode">Martin1 Mode</string>
<string name="action_martin2_mode">Martin2 Mode</string>
<string name="action_scottie1_mode">Scottie1 Mode</string>

View file

@ -114,6 +114,8 @@ static int calibration_detector(float dat_value, float dat_amp, float cnt_amp, i
return mode_scottieDX;
case 0xb7:
return mode_wrasseSC2_180;
case 0x60:
return mode_pd180;
default:
return -1;
}

View file

@ -22,6 +22,7 @@ static const int decoder_robot36 = 1;
static const int decoder_yuv = 2;
static const int decoder_rgb = 3;
static const int decoder_scottie = 4;
static const int decoder_pd = 5;
static const int mode_raw = 0;
static const int mode_robot36 = 1;
@ -32,6 +33,7 @@ static const int mode_scottie1 = 5;
static const int mode_scottie2 = 6;
static const int mode_scottieDX = 7;
static const int mode_wrasseSC2_180 = 8;
static const int mode_pd180 = 9;
static const float sync_buildup_ms = 1.1f;
static const float scanline_tolerance = 0.05f;
@ -43,5 +45,6 @@ static const float scottie1_scanline_ms = 428.22f;
static const float scottie2_scanline_ms = 277.692f;
static const float scottieDX_scanline_ms = 1050.3f;
static const float wrasseSC2_180_scanline_ms = 711.0225f;
static const float pd180_scanline_ms = 754.24f;
#endif

View file

@ -99,7 +99,7 @@ static void robot36_decoder(int sync_timeout)
if (parity) {
odd_sync_pos = prev_sync_pos;
int even_vpos = vpos;
int odd_vpos = (vpos + 1) % maximum_height;
int odd_vpos = (vpos + 1) % freerun_height;
for (int i = 0; i < bitmap_width; ++i) {
uchar even_y = value_blur(i, even_sync_pos + y_begin, even_sync_pos + y_end);
uchar v = value_blur(i, even_sync_pos + v_begin, even_sync_pos + v_end);
@ -145,6 +145,37 @@ static void yuv_decoder()
++vpos;
}
static void pd_decoder()
{
if (debug_mode) {
for (int i = 0; i < bitmap_width; ++i) {
uchar r, g, b;
r = g = b = value_blur(i, prev_sync_pos, sync_pos);
int pos = (i * (sync_pos - prev_sync_pos) + (sync_pos - prev_sync_pos) / 2) / bitmap_width;
if (v_begin <= pos && pos < v_end)
g = b = 0;
if ((y_even_begin <= pos && pos < y_even_end) || (y_odd_begin <= pos && pos < y_odd_end))
r = b = 0;
if (u_begin <= pos && pos < u_end)
r = g = 0;
pixel_buffer[bitmap_width * vpos + i] = rgb(r, g, b);
}
++vpos;
} else {
int even_vpos = vpos;
int odd_vpos = (vpos + 1) % freerun_height;
for (int i = 0; i < bitmap_width; ++i) {
uchar odd_y = value_blur(i, y_odd_begin + prev_sync_pos, y_odd_end + prev_sync_pos);
uchar u = value_blur(i, u_begin + prev_sync_pos, u_end + prev_sync_pos);
uchar v = value_blur(i, v_begin + prev_sync_pos, v_end + prev_sync_pos);
uchar even_y = value_blur(i, y_even_begin + prev_sync_pos, y_even_end + prev_sync_pos);
pixel_buffer[bitmap_width * even_vpos + i] = yuv(even_y, u, v);
pixel_buffer[bitmap_width * odd_vpos + i] = yuv(odd_y, u, v);
}
vpos += 2;
}
}
static void rgb_decoder()
{
for (int i = 0; i < bitmap_width; ++i) {
@ -306,6 +337,9 @@ void decode(int samples) {
case decoder_robot36:
robot36_decoder(sync_timeout);
break;
case decoder_pd:
pd_decoder();
break;
case decoder_yuv:
yuv_decoder();
break;
@ -320,8 +354,8 @@ void decode(int samples) {
}
if (vpos >= bitmap_height)
save_buffer();
if (vpos >= maximum_height)
vpos -= maximum_height;
if (vpos >= freerun_height)
vpos -= freerun_height;
seperator_counter = 0;
}
}

View file

@ -56,6 +56,7 @@ void initialize(float rate, int length, int iw, int ih, int sw, int sh, int sgw,
scottie2_scanline_length = round((scottie2_scanline_ms * sample_rate) / 1000.0f);
scottieDX_scanline_length = round((scottieDX_scanline_ms * sample_rate) / 1000.0f);
wrasseSC2_180_scanline_length = round((wrasseSC2_180_scanline_ms * sample_rate) / 1000.0f);
pd180_scanline_length = round((pd180_scanline_ms * sample_rate) / 1000.0f);
const float pairwise_minimum_of_scanline_time_distances = 0.018226f;
maximum_absolute_deviaton = 0.5f * pairwise_minimum_of_scanline_time_distances * sample_rate;

View file

@ -21,6 +21,10 @@ limitations under the License.
#include "state.rsh"
#include "exports.rsh"
static int freerun_reserve(int height)
{
return (height * 3) / 2;
}
void toggle_auto()
{
automatic_mode_detection ^= 1;
@ -34,6 +38,7 @@ void raw_mode()
blur_power = -1;
*current_mode = mode_raw;
current_decoder = decoder_raw;
freerun_height = maximum_height;
bitmap_width = maximum_width;
bitmap_height = maximum_height;
sync_length = minimum_sync_length;
@ -48,6 +53,7 @@ void robot36_mode()
current_decoder = decoder_robot36;
bitmap_width = 320;
bitmap_height = 240;
freerun_height = freerun_reserve(bitmap_height);
const float tolerance = 0.8f;
const float sync_ms = 9.0f;
const float sync_porch_ms = 3.0f;
@ -83,6 +89,7 @@ void robot72_mode()
current_decoder = decoder_yuv;
bitmap_width = 320;
bitmap_height = 240;
freerun_height = freerun_reserve(bitmap_height);
const float tolerance = 0.8f;
const float sync_ms = 9.0f;
const float sync_porch_ms = 3.0f;
@ -119,6 +126,42 @@ void robot72_mode()
minimum_length = ((1.0f - scanline_tolerance) * robot72_scanline_ms * sample_rate) / 1000.0f;
maximum_length = ((1.0f + scanline_tolerance) * robot72_scanline_ms * sample_rate) / 1000.0f;
}
void pd180_mode()
{
blur_power = 3;
*current_mode = mode_pd180;
current_decoder = decoder_pd;
bitmap_width = 640;
bitmap_height = 496;
freerun_height = freerun_reserve(bitmap_height);
const float tolerance = 0.8f;
const float sync_ms = 20.0f;
const float porch_ms = 2.08f;
const float yuv_scan_ms = 183.04f;
sync_length = tolerance * (sync_ms * sample_rate) / 1000.0f;
float y_odd_begin_ms = porch_ms;
float y_odd_end_ms = y_odd_begin_ms + yuv_scan_ms;
float v_begin_ms = y_odd_end_ms;
float v_end_ms = v_begin_ms + yuv_scan_ms;
float u_begin_ms = v_end_ms;
float u_end_ms = u_begin_ms + yuv_scan_ms;
float y_even_begin_ms = u_end_ms;
float y_even_end_ms = y_even_begin_ms + yuv_scan_ms;
y_odd_begin = round((y_odd_begin_ms * sample_rate) / 1000.0f);
y_odd_end = round((y_odd_end_ms * sample_rate) / 1000.0f);
v_begin = round((v_begin_ms * sample_rate) / 1000.0f);
v_end = round((v_end_ms * sample_rate) / 1000.0f);
u_begin = round((u_begin_ms * sample_rate) / 1000.0f);
u_end = round((u_end_ms * sample_rate) / 1000.0f);
y_even_begin = round((y_even_begin_ms * sample_rate) / 1000.0f);
y_even_end = round((y_even_end_ms * sample_rate) / 1000.0f);
scanline_length = pd180_scanline_length;
minimum_length = ((1.0f - scanline_tolerance) * pd180_scanline_ms * sample_rate) / 1000.0f;
maximum_length = ((1.0f + scanline_tolerance) * pd180_scanline_ms * sample_rate) / 1000.0f;
}
void martin1_mode()
{
blur_power = 3;
@ -126,6 +169,7 @@ void martin1_mode()
current_decoder = decoder_rgb;
bitmap_width = 320;
bitmap_height = 256;
freerun_height = freerun_reserve(bitmap_height);
const float tolerance = 0.5f;
const float sync_ms = 4.862f;
const float sync_porch_ms = 0.572f;
@ -159,6 +203,7 @@ void martin2_mode()
current_decoder = decoder_rgb;
bitmap_width = 320;
bitmap_height = 256;
freerun_height = freerun_reserve(bitmap_height);
const float tolerance = 0.5f;
const float sync_ms = 4.862f;
const float sync_porch_ms = 0.572f;
@ -192,6 +237,7 @@ void scottie1_mode()
current_decoder = decoder_scottie;
bitmap_width = 320;
bitmap_height = 256;
freerun_height = freerun_reserve(bitmap_height);
const float tolerance = 0.8f;
const float sync_ms = 9.0f;
const float sync_porch_ms = 1.5f;
@ -225,6 +271,7 @@ void scottie2_mode()
current_decoder = decoder_scottie;
bitmap_width = 320;
bitmap_height = 256;
freerun_height = freerun_reserve(bitmap_height);
const float tolerance = 0.8f;
const float sync_ms = 9.0f;
const float sync_porch_ms = 1.5f;
@ -258,6 +305,7 @@ void scottieDX_mode()
current_decoder = decoder_scottie;
bitmap_width = 320;
bitmap_height = 256;
freerun_height = freerun_reserve(bitmap_height);
const float tolerance = 0.8f;
const float sync_ms = 9.0f;
const float sync_porch_ms = 1.5f;
@ -291,6 +339,7 @@ void wrasseSC2_180_mode()
current_decoder = decoder_rgb;
bitmap_width = 320;
bitmap_height = 256;
freerun_height = freerun_reserve(bitmap_height);
const float tolerance = 0.5f;
const float sync_ms = 5.5225f;
const float sync_porch_ms = 0.5f;
@ -345,6 +394,9 @@ static void switch_mode(int new_mode)
case mode_wrasseSC2_180:
wrasseSC2_180_mode();
break;
case mode_pd180:
pd180_mode();
break;
default:
return;
}

View file

@ -53,15 +53,19 @@ static int scanline_estimator(int sync_level)
int scottie2_adev = abs(mean - scottie2_scanline_length);
int scottieDX_adev = abs(mean - scottieDX_scanline_length);
int wrasseSC2_180_adev = abs(mean - wrasseSC2_180_scanline_length);
int pd180_adev = abs(mean - pd180_scanline_length);
int min_adev = min(
min(
min(robot36_adev, robot72_adev),
min(martin1_adev, martin2_adev)
), min(
min(scottie1_adev, scottie2_adev),
min(scottieDX_adev, wrasseSC2_180_adev)
)
min(
min(robot36_adev, robot72_adev),
min(martin1_adev, martin2_adev)
), min(
min(scottie1_adev, scottie2_adev),
min(scottieDX_adev, wrasseSC2_180_adev)
)
),
pd180_adev
);
if (min_adev > maximum_absolute_deviaton)
@ -82,6 +86,8 @@ static int scanline_estimator(int sync_level)
return mode_scottieDX;
else if (min_adev == wrasseSC2_180_adev)
return mode_wrasseSC2_180;
else if (min_adev == pd180_adev)
return mode_pd180;
return -1;
}

View file

@ -37,11 +37,13 @@ static int buffer_length, buffer_mask, buffer_pos;
static int buffer_cleared;
static int bitmap_width, bitmap_height;
static int maximum_width, maximum_height;
static int freerun_height;
static int spectrum_width, spectrum_height;
static int spectrogram_width, spectrogram_height;
static int sync_length, sync_counter, vpos, hpos;
static int seperator_counter, seperator_length;
static int u_sep_begin, u_sep_end, v_sep_begin, v_sep_end;
static int y_even_begin, y_even_end, y_odd_begin, y_odd_end;
static int y_begin, y_end, u_begin, u_end, v_begin, v_end;
static int r_begin, r_end, b_begin, b_end, g_begin, g_end;
static int sync_buildup_length;
@ -53,5 +55,6 @@ static int scottie1_scanline_length;
static int scottie2_scanline_length;
static int scottieDX_scanline_length;
static int wrasseSC2_180_scanline_length;
static int pd180_scanline_length;
#endif