I'm making this game in MonoGame (basically Xna) that uses DynamicSoundEffectInstance class. MonoGame does not have an implementation of DynamicSoundEffectInstance yet, so I made my own:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
#if MONOMAC
using MonoMac.OpenAL;
#else
using OpenTK.Audio.OpenAL;
#endif
using System.Threading;
namespace Microsoft.Xna.Framework.Audio
{
public sealed class DynamicSoundEffectInstance : IDisposable
{
private const int BUFFERCOUNT = 2;
private SoundState soundState = SoundState.Stopped;
private AudioChannels channels;
private int sampleRate;
private ALFormat format;
private bool looped = false;
private float volume = 1.0f;
private float pan = 0;
private float pitch = 0f;
private int sourceId;
private int[] bufferIds;
private int[] bufferIdsToFill;
private int currentBufferToFill;
private bool isDisposed = false;
private bool hasSourceId = false;
private Thread bufferFillerThread = null;
// Events
public event EventHandler<EventArgs> BufferNeeded;
internal void OnBufferNeeded(EventArgs args)
{
if (BufferNeeded != null)
{
BufferNeeded(this, args);
}
}
public DynamicSoundEffectInstance(int sampleRate, AudioChannels channels)
{
this.sampleRate = sampleRate;
this.channels = channels;
switch (channels)
{
case AudioChannels.Mono:
this.format = ALFormat.Mono16;
break;
case AudioChannels.Stereo:
this.format = ALFormat.Stereo16;
break;
default:
break;
}
}
public bool IsDisposed
{
get
{
return isDisposed;
}
}
public float Pan
{
get
{
return pan;
}
set
{
pan = value;
if (hasSourceId)
{
// Listener
// Pan
AL.Source(sourceId, ALSource3f.Position, pan, 0.0f, 0.1f);
}
}
}
public float Pitch
{
get
{
return pitch;
}
set
{
pitch = value;
if (hasSourceId)
{
// Pitch
AL.Source(sourceId, ALSourcef.Pitch, XnaPitchToAlPitch(pitch));
}
}
}
public float Volume
{
get
{
return volume;
}
set
{
volume = value;
if (hasSourceId)
{
// Volume
AL.Source(sourceId, ALSourcef.Gain, volume * SoundEffect.MasterVolume);
}
}
}
public SoundState State
{
get
{
return soundState;
}
}
private float XnaPitchToAlPitch(float pitch)
{
// pitch is different in XNA and OpenAL. XNA has a pitch between -1 and 1 for one octave down/up.
// openAL uses 0.5 to 2 for one octave down/up, while 1 is the default. The default value of 0 would make it completely silent.
return (float)Math.Exp(0.69314718 * pitch);
}
public void Play()
{
if (!hasSourceId)
{
bufferIds = AL.GenBuffers(BUFFERCOUNT);
sourceId = AL.GenSource();
hasSourceId = true;
}
soundState = SoundState.Playing;
if (bufferFillerThread == null)
{
bufferIdsToFill = bufferIds;
currentBufferToFill = 0;
OnBufferNeeded(EventArgs.Empty);
bufferFillerThread = new Thread(new ThreadStart(BufferFiller));
bufferFillerThread.Start();
}
AL.SourcePlay(sourceId);
}
public void Apply3D(AudioListener listener, AudioEmitter emitter)
{
Apply3D(new AudioListener[] { listener }, emitter);
}
public void Pause()
{
if (hasSourceId)
{
AL.SourcePause(sourceId);
soundState = SoundState.Paused;
}
}
public void Apply3D(AudioListener[] listeners, AudioEmitter emitter)
{
// get AL's listener position
float x, y, z;
AL.GetListener(ALListener3f.Position, out x, out y, out z);
for (int i = 0; i < listeners.Length; i++)
{
AudioListener listener = listeners[i];
// get the emitter offset from origin
Vector3 posOffset = emitter.Position - listener.Position;
// set up orientation matrix
Matrix orientation = Matrix.CreateWorld(Vector3.Zero, listener.Forward, listener.Up);
// set up our final position and velocity according to orientation of listener
Vector3 finalPos = new Vector3(x + posOffset.X, y + posOffset.Y, z + posOffset.Z);
finalPos = Vector3.Transform(finalPos, orientation);
Vector3 finalVel = emitter.Velocity;
finalVel = Vector3.Transform(finalVel, orientation);
// set the position based on relative positon
AL.Source(sourceId, ALSource3f.Position, finalPos.X, finalPos.Y, finalPos.Z);
AL.Source(sourceId, ALSource3f.Velocity, finalVel.X, finalVel.Y, finalVel.Z);
}
}
public void Dispose()
{
if (!isDisposed)
{
Stop(true);
AL.DeleteBuffers(bufferIds);
AL.DeleteSource(sourceId);
bufferIdsToFill = null;
hasSourceId = false;
isDisposed = true;
}
}
public void Stop()
{
if (hasSourceId)
{
AL.SourceStop(sourceId);
int pendingBuffers = PendingBufferCount;
if(pendingBuffers > 0)
AL.SourceUnqueueBuffers(sourceId, PendingBufferCount);
if (bufferFillerThread != null)
bufferFillerThread.Abort();
bufferFillerThread = null;
}
soundState = SoundState.Stopped;
}
public void Stop(bool immediate)
{
Stop();
}
public TimeSpan GetSampleDuration(int sizeInBytes)
{
throw new NotImplementedException();
}
public int GetSampleSizeInBytes(TimeSpan duration)
{
int size = (int)(duration.TotalMilliseconds * ((float)sampleRate / 1000.0f));
return (size + (size & 1)) * 16;
}
public void SubmitBuffer(byte[] buffer)
{
this.SubmitBuffer(buffer, 0, buffer.Length);
}
public void SubmitBuffer(byte[] buffer, int offset, int count)
{
if (bufferIdsToFill != null) {
AL.BufferData (bufferIdsToFill [currentBufferToFill], format, buffer, count, sampleRate);
AL.SourceQueueBuffer (sourceId, bufferIdsToFill [currentBufferToFill]);
currentBufferToFill++;
if (currentBufferToFill >= bufferIdsToFill.Length)
bufferIdsToFill = null;
else
OnBufferNeeded (EventArgs.Empty);
} else {
throw new Exception ("Buffer already full.");
}
}
private void BufferFiller()
{
bool done = false;
while (!done)
{
var state = AL.GetSourceState(sourceId);
if (state == ALSourceState.Stopped || state == ALSourceState.Initial)
AL.SourcePlay(sourceId);
if (bufferIdsToFill != null)
continue;
int buffersProcessed;
AL.GetSource(sourceId, ALGetSourcei.BuffersProcessed, out buffersProcessed);
if (buffersProcessed == 0)
continue;
bufferIdsToFill = AL.SourceUnqueueBuffers(sourceId, buffersProcessed);
currentBufferToFill = 0;
OnBufferNeeded(EventArgs.Empty);
}
}
public bool IsLooped
{
get
{
return looped;
}
set
{
looped = value;
}
}
public int PendingBufferCount
{
get
{
if (hasSourceId)
{
int buffersQueued;
AL.GetSource(sourceId, ALGetSourcei.BuffersQueued, out buffersQueued);
return buffersQueued;
}
return 0;
}
}
}
}
Now, I followed this tutorial on making dynamic sounds in Xna, which worked with my custom MonoGame class. However, when I run the project (Xamarin Studio 4, Mac OS X 10.8, with MonoGame 3.0.1), it throws this exception:
Buffer already full
Pointing at the code in my custom class:
public void SubmitBuffer(byte[] buffer, int offset, int count)
{
if (bufferIdsToFill != null) {
AL.BufferData (bufferIdsToFill [currentBufferToFill], format, buffer, count, sampleRate);
AL.SourceQueueBuffer (sourceId, bufferIdsToFill [currentBufferToFill]);
currentBufferToFill++;
if (currentBufferToFill >= bufferIdsToFill.Length)
bufferIdsToFill = null;
else
OnBufferNeeded (EventArgs.Empty);
} else {
throw new Exception ("Buffer already full."); //RIGHT HERE IS THE EXCEPTION
}
}
I commented out the exception, and ran it again. It played the sound, with pops in it, but it still played it. How can I clear the buffer, so it is not full? I followed this tutorial EXACTLY, so all the code I added to my project is in there.
Oh! Figured it out myself; I changed the pending buffer count from 3 to 2. My final submit buffer code was:
while(_instance.PendingBufferCount < 2)
SubmitBuffer();
Where the 2 is, used to be a 3. Now it no longer throws the exception.
Related
I am learning Xamarin.Android recently, I was trying to implement pageviewers with dot sliders for my practice from the last few days but failed to implement it, I had refereed many solutions from popular hubs like stackoverflow and github but failed to do so.
Can any one please explain me how to implement the viewpagers with dot sliders in xamarin.android.
I am attaching a photo to this for your reference, which would give you a clear view on my requirement.
as you can see he is sliding the pages using the dot sliders i was trying to do so.
Please explain me how to do it in Xamarin.Android (Native)
First define your own custom circle page-indicator let it be CirclePageIndicator.cs add this to your project (not activity file)
using Android.Content;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Graphics;
using Android.Support.V4.View;
using Android.Util;
using Java.Lang;
using Java.Interop;
namespace MyApplication.Droid.Library
{
public class CirclePageIndicator : View,PageIndicator
{
const int HORIZONTAL = 0;
const int VERTICAL = 1;
private float mRadius;
private Paint mPaintPageFill;
private Paint mPaintStroke;
private Paint mPaintFill;
private ViewPager mViewPager;
private ViewPager.IOnPageChangeListener mListener;
private int mCurrentPage;
private int mSnapPage;
private int mCurrentOffset;
private int mScrollState;
private int mPageSize;
private int mOrientation;
private bool mCentered;
private bool mSnap;
private const int INVALID_POINTER = -1;
private int mTouchSlop;
private float mLastMotionX = -1;
private int mActivePointerId = INVALID_POINTER;
private bool mIsDragging;
public CirclePageIndicator(Context context) : this(context, null)
{
}
public CirclePageIndicator(Context context, IAttributeSet attrs) : this(context, attrs, Resource.Attribute.vpiCirclePageIndicatorStyle)
{
}
public CirclePageIndicator(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle)
{
//Load defaults from resources
var res = Resources;
int defaultPageColor = res.GetColor(Resource.Color.default_circle_indicator_page_color);
int defaultFillColor = res.GetColor(Resource.Color.default_circle_indicator_fill_color);
int defaultOrientation = res.GetInteger(Resource.Integer.default_circle_indicator_orientation);
int defaultStrokeColor = res.GetColor(Resource.Color.default_circle_indicator_stroke_color);
float defaultStrokeWidth = res.GetDimension(Resource.Dimension.default_circle_indicator_stroke_width);
float defaultRadius = res.GetDimension(Resource.Dimension.default_circle_indicator_radius);
bool defaultCentered = res.GetBoolean(Resource.Boolean.default_circle_indicator_centered);
bool defaultSnap = res.GetBoolean(Resource.Boolean.default_circle_indicator_snap);
//Retrieve styles attributes
var a = context.ObtainStyledAttributes(attrs, Resource.Styleable.CirclePageIndicator, defStyle, Resource.Style.Widget_CirclePageIndicator);
mCentered = a.GetBoolean(Resource.Styleable.CirclePageIndicator_centered, defaultCentered);
mOrientation = a.GetInt(Resource.Styleable.CirclePageIndicator_orientation, defaultOrientation);
mPaintPageFill = new Paint(PaintFlags.AntiAlias);
mPaintPageFill.SetStyle(Paint.Style.Fill);
mPaintPageFill.Color = a.GetColor(Resource.Styleable.CirclePageIndicator_pageColor, defaultPageColor);
mPaintStroke = new Paint(PaintFlags.AntiAlias);
mPaintStroke.SetStyle(Paint.Style.Stroke);
mPaintStroke.Color = a.GetColor(Resource.Styleable.CirclePageIndicator_strokeColor, defaultStrokeColor);
mPaintStroke.StrokeWidth = a.GetDimension(Resource.Styleable.CirclePageIndicator_strokeWidth, defaultStrokeWidth);
mPaintFill = new Paint(PaintFlags.AntiAlias);
mPaintFill.SetStyle(Paint.Style.Fill);
mPaintFill.Color = a.GetColor(Resource.Styleable.CirclePageIndicator_fillColor, defaultFillColor);
mRadius = a.GetDimension(Resource.Styleable.CirclePageIndicator_radius, defaultRadius);
mSnap = a.GetBoolean(Resource.Styleable.CirclePageIndicator_snap, defaultSnap);
a.Recycle();
var configuration = ViewConfiguration.Get(context);
mTouchSlop = ViewConfigurationCompat.GetScaledPagingTouchSlop(configuration);
}
public void SetCentered(bool centered)
{
mCentered = centered;
Invalidate();
}
public bool IsCentered()
{
return mCentered;
}
public void SetPageColor(Color pageColor)
{
mPaintPageFill.Color = pageColor;
Invalidate();
}
public int GetPageColor()
{
return mPaintPageFill.Color;
}
public void SetFillColor(Color fillColor)
{
mPaintFill.Color = fillColor;
Invalidate();
}
public int GetFillColor()
{
return mPaintFill.Color;
}
public void setOrientation(int orientation)
{
switch (orientation)
{
case HORIZONTAL:
case VERTICAL:
mOrientation = orientation;
UpdatePageSize();
RequestLayout();
break;
default:
throw new IllegalArgumentException("Orientation must be either HORIZONTAL or VERTICAL.");
}
}
public int GetOrientation()
{
return mOrientation;
}
public void SetStrokeColor(Color strokeColor)
{
mPaintStroke.Color = strokeColor;
Invalidate();
}
public int GetStrokeColor()
{
return mPaintStroke.Color;
}
public void SetStrokeWidth(float strokeWidth)
{
mPaintStroke.StrokeWidth = strokeWidth;
Invalidate();
}
public float GetStrokeWidth()
{
return mPaintStroke.StrokeWidth;
}
public void SetRadius(float radius)
{
mRadius = radius;
Invalidate();
}
public float GetRadius()
{
return mRadius;
}
public void SetSnap(bool snap)
{
mSnap = snap;
Invalidate();
}
public bool IsSnap()
{
return mSnap;
}
protected override void OnDraw(Canvas canvas)
{
base.OnDraw(canvas);
if (mViewPager == null)
{
return;
}
int count = mViewPager.Adapter.Count;
if (count == 0)
{
return;
}
if (mCurrentPage >= count)
{
SetCurrentItem(count - 1);
return;
}
int longSize;
int longPaddingBefore;
int longPaddingAfter;
int shortPaddingBefore;
if (mOrientation == HORIZONTAL)
{
longSize = Width;
longPaddingBefore = PaddingLeft;
longPaddingAfter = PaddingRight;
shortPaddingBefore = PaddingTop;
}
else
{
longSize = Height;
longPaddingBefore = PaddingTop;
longPaddingAfter = PaddingBottom;
shortPaddingBefore = PaddingLeft;
}
float threeRadius = mRadius * 3;
float shortOffset = shortPaddingBefore + mRadius;
float longOffset = longPaddingBefore + mRadius;
if (mCentered)
{
longOffset += ((longSize - longPaddingBefore - longPaddingAfter) / 2.0f) - ((count * threeRadius) / 2.0f);
}
float dX;
float dY;
float pageFillRadius = mRadius;
if (mPaintStroke.StrokeWidth > 0)
{
pageFillRadius -= mPaintStroke.StrokeWidth / 2.0f;
}
//Draw stroked circles
for (int iLoop = 0; iLoop < count; iLoop++)
{
float drawLong = longOffset + (iLoop * threeRadius);
if (mOrientation == HORIZONTAL)
{
dX = drawLong;
dY = shortOffset;
}
else
{
dX = shortOffset;
dY = drawLong;
}
// Only paint fill if not completely transparent
if (mPaintPageFill.Alpha > 0)
{
canvas.DrawCircle(dX, dY, pageFillRadius, mPaintPageFill);
}
// Only paint stroke if a stroke width was non-zero
if (pageFillRadius != mRadius)
{
canvas.DrawCircle(dX, dY, mRadius, mPaintStroke);
}
}
//Draw the filled circle according to the current scroll
float cx = (mSnap ? mSnapPage : mCurrentPage) * threeRadius;
if (!mSnap && (mPageSize != 0))
{
cx += (mCurrentOffset * 1.0f / mPageSize) * threeRadius;
}
if (mOrientation == HORIZONTAL)
{
dX = longOffset + cx;
dY = shortOffset;
}
else
{
dX = shortOffset;
dY = longOffset + cx;
}
canvas.DrawCircle(dX, dY, mRadius, mPaintFill);
}
public override bool OnTouchEvent(MotionEvent ev)
{
if (base.OnTouchEvent(ev))
{
return true;
}
if ((mViewPager == null) || (mViewPager.Adapter.Count == 0))
{
return false;
}
var action = ev.Action;
switch ((int)action & MotionEventCompat.ActionMask)
{
case (int)MotionEventActions.Down:
mActivePointerId = MotionEventCompat.GetPointerId(ev, 0);
mLastMotionX = ev.GetX();
break;
case (int)MotionEventActions.Move:
{
int activePointerIndex = MotionEventCompat.FindPointerIndex(ev, mActivePointerId);
float x = MotionEventCompat.GetX(ev, activePointerIndex);
float deltaX = x - mLastMotionX;
if (!mIsDragging)
{
if (Java.Lang.Math.Abs(deltaX) > mTouchSlop)
{
mIsDragging = true;
}
}
if (mIsDragging)
{
if (!mViewPager.IsFakeDragging)
{
mViewPager.BeginFakeDrag();
}
mLastMotionX = x;
mViewPager.FakeDragBy(deltaX);
}
break;
}
case (int)MotionEventActions.Cancel:
case (int)MotionEventActions.Up:
if (!mIsDragging)
{
int count = mViewPager.Adapter.Count;
int width = Width;
float halfWidth = width / 2f;
float sixthWidth = width / 6f;
if ((mCurrentPage > 0) && (ev.GetX() < halfWidth - sixthWidth))
{
mViewPager.CurrentItem = mCurrentPage - 1;
return true;
}
else if ((mCurrentPage < count - 1) && (ev.GetX() > halfWidth + sixthWidth))
{
mViewPager.CurrentItem = mCurrentPage + 1;
return true;
}
}
mIsDragging = false;
mActivePointerId = INVALID_POINTER;
if (mViewPager.IsFakeDragging)
mViewPager.EndFakeDrag();
break;
case MotionEventCompat.ActionPointerDown:
{
int index = MotionEventCompat.GetActionIndex(ev);
float x = MotionEventCompat.GetX(ev, index);
mLastMotionX = x;
mActivePointerId = MotionEventCompat.GetPointerId(ev, index);
break;
}
case MotionEventCompat.ActionPointerUp:
int pointerIndex = MotionEventCompat.GetActionIndex(ev);
int pointerId = MotionEventCompat.GetPointerId(ev, pointerIndex);
if (pointerId == mActivePointerId)
{
int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mActivePointerId = MotionEventCompat.GetPointerId(ev, newPointerIndex);
}
mLastMotionX = MotionEventCompat.GetX(ev, MotionEventCompat.FindPointerIndex(ev, mActivePointerId));
break;
}
return true;
}
public void SetViewPager(ViewPager view)
{
if (view.Adapter == null)
{
throw new IllegalStateException("ViewPager does not have adapter instance.");
}
mViewPager = view;
mViewPager.SetOnPageChangeListener(this);
UpdatePageSize();
Invalidate();
}
private void UpdatePageSize()
{
if (mViewPager != null)
{
mPageSize = (mOrientation == HORIZONTAL) ? mViewPager.Width : mViewPager.Height;
}
}
public void SetViewPager(ViewPager view, int initialPosition)
{
SetViewPager(view);
SetCurrentItem(initialPosition);
}
public void SetCurrentItem(int item)
{
if (mViewPager == null)
{
throw new IllegalStateException("ViewPager has not been bound.");
}
mViewPager.CurrentItem = item;
mCurrentPage = item;
Invalidate();
}
public void NotifyDataSetChanged()
{
Invalidate();
}
public void OnPageScrollStateChanged(int state)
{
mScrollState = state;
if (mListener != null)
{
mListener.OnPageScrollStateChanged(state);
}
}
public void OnPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{
mCurrentPage = position;
mCurrentOffset = positionOffsetPixels;
UpdatePageSize();
Invalidate();
if (mListener != null)
{
mListener.OnPageScrolled(position, positionOffset, positionOffsetPixels);
}
}
public void OnPageSelected(int position)
{
if (mSnap || mScrollState == ViewPager.ScrollStateIdle)
{
mCurrentPage = position;
mSnapPage = position;
Invalidate();
}
if (mListener != null)
{
mListener.OnPageSelected(position);
}
}
public void SetOnPageChangeListener(ViewPager.IOnPageChangeListener listener)
{
mListener = listener;
}
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
if (mOrientation == HORIZONTAL)
{
SetMeasuredDimension(MeasureLong(widthMeasureSpec), MeasureShort(heightMeasureSpec));
}
else
{
SetMeasuredDimension(MeasureShort(widthMeasureSpec), MeasureLong(heightMeasureSpec));
}
}
/**
* Determines the width of this view
*
* #param measureSpec
* A measureSpec packed into an int
* #return The width of the view, honoring constraints from measureSpec
*/
private int MeasureLong(int measureSpec)
{
int result = 0;
var specMode = MeasureSpec.GetMode(measureSpec);
var specSize = MeasureSpec.GetSize(measureSpec);
if ((specMode == MeasureSpecMode.Exactly) || (mViewPager == null))
{
//We were told how big to be
result = specSize;
}
else
{
//Calculate the width according the views count
int count = mViewPager.Adapter.Count;
result = (int)(PaddingLeft + PaddingRight
+ (count * 2 * mRadius) + (count - 1) * mRadius + 1);
//Respect AT_MOST value if that was what is called for by measureSpec
if (specMode == MeasureSpecMode.AtMost)
{
result = Java.Lang.Math.Min(result, specSize);
}
}
return result;
}
/**
* Determines the height of this view
*
* #param measureSpec
* A measureSpec packed into an int
* #return The height of the view, honoring constraints from measureSpec
*/
private int MeasureShort(int measureSpec)
{
int result = 0;
var specMode = MeasureSpec.GetMode(measureSpec);
var specSize = MeasureSpec.GetSize(measureSpec);
if (specMode == MeasureSpecMode.Exactly)
{
//We were told how big to be
result = specSize;
}
else
{
//Measure the height
result = (int)(2 * mRadius + PaddingTop + PaddingBottom + 1);
//Respect AT_MOST value if that was what is called for by measureSpec
if (specMode == MeasureSpecMode.AtMost)
{
result = Java.Lang.Math.Min(result, specSize);
}
}
return result;
}
protected override void OnRestoreInstanceState(IParcelable state)
{
try
{
SavedState savedState = (SavedState)state;
base.OnRestoreInstanceState(savedState.SuperState);
mCurrentPage = savedState.CurrentPage;
mSnapPage = savedState.CurrentPage;
}
catch
{
base.OnRestoreInstanceState(state);
// Ignore, this needs to support IParcelable...
}
RequestLayout();
}
protected override IParcelable OnSaveInstanceState()
{
var superState = base.OnSaveInstanceState();
var savedState = new SavedState(superState);
savedState.CurrentPage = mCurrentPage;
return savedState;
}
public class SavedState : BaseSavedState
{
public int CurrentPage { get; set; }
public SavedState(IParcelable superState) : base(superState)
{
}
private SavedState(Parcel parcel) : base(parcel)
{
CurrentPage = parcel.ReadInt();
}
public override void WriteToParcel(Parcel dest, ParcelableWriteFlags flags)
{
base.WriteToParcel(dest, flags);
dest.WriteInt(CurrentPage);
}
[ExportField("CREATOR")]
static SavedStateCreator InitializeCreator()
{
return new SavedStateCreator();
}
class SavedStateCreator : Java.Lang.Object, IParcelableCreator
{
public Java.Lang.Object CreateFromParcel(Parcel source)
{
return new SavedState(source);
}
public Java.Lang.Object[] NewArray(int size)
{
return new SavedState[size];
}
}
}
}
}
Now add PageIndicator.cs file to your project (not activity file)
using Android.Support.V4.View;
namespace MyApplication.Droid.Library
{
public interface PageIndicator : ViewPager.IOnPageChangeListener
{
/**
* Bind the indicator to a ViewPager.
*
* #param view
*/
void SetViewPager(ViewPager view);
/**
* Bind the indicator to a ViewPager.
*
* #param view
* #param initialPosition
*/
void SetViewPager(ViewPager view, int initialPosition);
/**
* <p>Set the current page of both the ViewPager and indicator.</p>
*
* <p>This <strong>must</strong> be used if you need to set the page before
* the views are drawn on screen (e.g., default start page).</p>
*
* #param item
*/
void SetCurrentItem(int item);
/**
* Set a page change listener which will receive forwarded events.
*
* #param listener
*/
void SetOnPageChangeListener(ViewPager.IOnPageChangeListener listener);
/**
* Notify the indicator that the fragment list has changed.
*/
void NotifyDataSetChanged();
}
}
Now add the following files to your values file:
vpi__styles.xml
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<style name="Widget"></style>
<style name="Widget.CirclePageIndicator" parent="Widget">
<item name="centered">#bool/default_circle_indicator_centered</item>
<item name="fillColor">#color/default_circle_indicator_fill_color</item>
<item name="pageColor">#color/default_circle_indicator_page_color</item>
<item name="orientation">#integer/default_circle_indicator_orientation</item>
<item name="radius">#dimen/default_circle_indicator_radius</item>
<item name="snap">#bool/default_circle_indicator_snap</item>
<item name="strokeColor">#color/default_circle_indicator_stroke_color</item>
<item name="strokeWidth">#dimen/default_circle_indicator_stroke_width</item>
</style>
</resources>
vpi__defaults.xml
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<bool name="default_circle_indicator_centered">true</bool>
<color name="default_circle_indicator_fill_color">#FFFFFFFF</color>
<color name="default_circle_indicator_page_color">#00000000</color>
<integer name="default_circle_indicator_orientation">0</integer>
<dimen name="default_circle_indicator_radius">3dp</dimen>
<bool name="default_circle_indicator_snap">false</bool>
<color name="default_circle_indicator_stroke_color">#FFDDDDDD</color>
<dimen name="default_circle_indicator_stroke_width">1dp</dimen>
</resources>
vpi__colors.xml
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<color name="vpi__background_holo_dark">#ff000000</color>
<color name="vpi__background_holo_light">#fff3f3f3</color>
<color name="vpi__bright_foreground_disabled_holo_dark">#ff4c4c4c</color>
<color name="vpi__bright_foreground_disabled_holo_light">#ffb2b2b2</color>
</resources>
vpi__attrs.xml
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<declare-styleable name="ViewPagerIndicator">
<!-- Style of the circle indicator. -->
<attr name="vpiCirclePageIndicatorStyle" format="reference"/>
</declare-styleable>
<declare-styleable name="CirclePageIndicator">
<!-- Whether or not the indicators should be centered. -->
<attr name="centered" format="boolean" />
<!-- Color of the filled circle that represents the current page. -->
<attr name="fillColor" format="color" />
<!-- Color of the filled circles that represents pages. -->
<attr name="pageColor" format="color" />
<!-- Orientation of the indicator. -->
<attr name="orientation">
<enum name="horizontal" value="0" />
<enum name="vertical" value="1" />
</attr>
<!-- Radius of the circles. This is also the spacing between circles. -->
<attr name="radius" format="dimension" />
<!-- Whether or not the selected indicator snaps to the circles. -->
<attr name="snap" format="boolean" />
<!-- Color of the open circles. -->
<attr name="strokeColor" format="color" />
<!-- Width of the stroke used to draw the circles. -->
<attr name="strokeWidth" format="dimension" />
</declare-styleable>
</resources>
Now add this code to design file.
Here you have to notice that MyApplication.Droid.Library is my name space and CirclePageIndicator is my page indicator file name so replace it with your's
<MyApplication.Droid.Library.CirclePageIndicator
android:id="#+id/indicator"
android:padding="10dip"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
/>
now add the following in the activity file.
using Android.Support.V4.App;
using MyApplication.Droid.Library;
//global
public ViewPager mPager;
public PageIndicator mIndicator;
//in on create
var indicator = FindViewById<CirclePageIndicator>(Resource.Id.indicator);
mIndicator = indicator;
indicator.SetViewPager(mPager);
indicator.SetSnap(true);
I had solved this from the github
Look at this the sample project 'Android-ViewPagerIndicator to Xamarin.Android'. You need to include the library, where there are multiple implementation to display the indicators on viewpager.
https://github.com/Cheesebaron/ViewPagerIndicator
I got it working just like iOS PageControl.
Create the custom class as such:
using Android.Content;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.Runtime;
using Android.Util;
using Android.Widget;
using System;
using System.Collections.Generic;
namespace myProject.CustomWidgets
{
public class PageControl : LinearLayout
{
#region Properties
private int _currentPage = 0;
public int CurrentPage
{
get
{
return _currentPage;
}
set
{
_currentPage = value;
SetCurrentPageIndicator();
}
}
public int Pages = 0;
public Color PageIndicatorTintColor = ColorHelper.Clear;
public Color CurrentPageIndicatorTintColor = ColorHelper.Clear;
private readonly Context context;
private List<ImageView> ivList = new List<ImageView>();
private List<Drawable> drawableList = new List<Drawable>();
private readonly int circleSize = 7;
#endregion Properties
#region Constructor
protected PageControl(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}
public PageControl(Context context) : base(context)
{
this.context = context;
InitConfig();
}
public PageControl(Context context, IAttributeSet attrs) : base(context, attrs)
{
this.context = context;
InitConfig();
}
public PageControl(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
{
this.context = context;
InitConfig();
}
public PageControl(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes) : base(context, attrs, defStyleAttr, defStyleRes)
{
this.context = context;
InitConfig();
}
#endregion Constructor
#region Methods
private void InitConfig()
{
Orientation = Orientation.Horizontal;
}
protected override void OnAttachedToWindow()
{
base.OnAttachedToWindow();
Render();
}
private void Render()
{
// Start with a clean slate
RemoveAllViews();
ivList = new List<ImageView>();
drawableList = new List<Drawable>();
if (Pages <= 0)
{
return;
}
for (int i = 0; i < Pages; i++)
{
var iv = new ImageView(context);
var size = ConvertionHelper.DensityToPixels(context, circleSize);
var margin = (int)(size / 2.5);
var lp = new LayoutParams(size, size);
lp.SetMargins(margin, 0, margin, 0);
iv.LayoutParameters = lp;
/* By default, all drawables instances loaded from the same resource share a common state.
* If you modify the state of one instance, all the other instances will receive the same modification.
* Calling this method on a mutable Drawable will have no effect */
var drawable = ResourcesHelper.GetDrawable(context, Resource.Drawable.ic_circle_separator).Mutate();
drawable.SetColorFilter(PageIndicatorTintColor, PorterDuff.Mode.SrcAtop);
iv.SetImageDrawable(drawable);
drawableList.Add(drawable);
ivList.Add(iv);
AddView(iv);
}
// Initial current page indicator set-up
SetCurrentPageIndicator();
}
private void SetCurrentPageIndicator()
{
if (ivList.Count == 0 || drawableList.Count == 0 || ivList.Count != drawableList.Count ||
CurrentPage < 0 || CurrentPage >= ivList.Count)
{
return;
}
// Reset all colors
for (int i = 0; i < ivList.Count; i++)
{
drawableList[i].SetColorFilter(PageIndicatorTintColor, PorterDuff.Mode.SrcIn);
ivList[i].SetImageDrawable(drawableList[i]);
}
// Change color of current page indicator
drawableList[CurrentPage].SetColorFilter(CurrentPageIndicatorTintColor, PorterDuff.Mode.SrcIn);
ivList[CurrentPage].SetImageDrawable(drawableList[CurrentPage]);
}
#endregion Methods
}
}
Then use on your xml file such as:
<myProject.PageControl
android:id="#+id/pagecontrol"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
Then on your activity you would have:
var pagecontrol = FindViewById<PageControl>(Resource.Id.pagecontrol);
pagecontrol.PageIndicatorTintColor = ColorHelper.PositiveBlue;
pagecontrol.CurrentPageIndicatorTintColor = ColorHelper.Orange;
pagecontrol.CurrentPage = 0;
pagecontrol.Pages = 3;
i want to show all folders(images, videos,files) with directories/files, currently only show images folder with files, but other folder are not show. I try to find solution but not found. Here is the code & its screenshot(http://postimg.org/image/wm5ypbk9d/).
FileManager.java
package com.rim.samples.device.mapactiondemo;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.KeypadListener;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.TreeField;
import net.rim.device.api.ui.component.TreeFieldCallback;
import net.rim.device.api.ui.container.MainScreen;
public class FilesManager extends MainScreen {
FTPMessages _ftp = null;
String[] fileList;
// ..................
private final Bitmap openIcon = Bitmap.getBitmapResource("open.png");
private final Bitmap closedIcon = Bitmap.getBitmapResource("closed.png");
private final Bitmap movieIcon = Bitmap.getBitmapResource("movie.png");
private final Bitmap songIcon = Bitmap.getBitmapResource("song.png");
private final Bitmap playIcon = Bitmap.getBitmapResource("play.png");
private final Bitmap imgIcon = Bitmap.getBitmapResource("images.png");
String nodeTen;
int node10;
TreeField myTree;
String[] nodeData;
// ListField to be displayed - null - no Field displayed
// List of entries to be displayed - null or length = 0 means no entries
// protected so that another Thread can update this list....
protected ListDirectory[] _resultsList = null; // entries available for
// display
private ListDirectory _selectedEntry = null;
public FilesManager(FTPMessages ftp) {
super();
_ftp = ftp;
// Setting starting directory
try {
/*
* fileList = _ftp.list(); for (int i = 0; i < fileList.length; i++)
* { _ftp.cwd(fileList[i]); }
*/
_ftp.cwd("images");
_ftp.cwd("files");
_ftp.cwd("videos");
} catch (Exception e) {
}
this.setTitle("Server File List");
TreeCallback myCallback = new TreeCallback();
myTree = new TreeField(myCallback, Field.FOCUSABLE) {
protected boolean navigationClick(int status, int time) {
// We'll only override unvarnished navigation click behavior
if ((status & KeypadListener.STATUS_ALT) == 0
&& (status & KeypadListener.STATUS_SHIFT) == 0) {
final int node = getCurrentNode();
if (getFirstChild(node) == -1) {
// Click is on a leaf node. Do some default action or
// else fall through.
// Note: this will also detect empty folders, which
// might or
// might not be something your app has to handle
Dialog.alert("clicked " + getCookie(node));
// TODO: open player screen, etc.
return true;
}
}
return super.navigationClick(status, time);
}
};
myTree.setDefaultExpanded(false);
myTree.setRowHeight(openIcon.getHeight());
try {
node10 = myTree.addChildNode(0, _ftp.pwd());
} catch (Exception e) {
}
this.add(myTree);
refreshList();
}
private void refreshList() {
// TODO Auto-generated method stub
_resultsList = null;
String[] directory = null;
try {
directory = _ftp.list();
} catch (Exception e) {
}
if (directory != null && directory.length > 0) {
_resultsList = new ListDirectory[directory.length];
for (int i = 0; i < directory.length; i++) {
_resultsList[i] = new ListDirectory(directory[i],
ListDirectory.UNIX_SERVER);
}
}
if (_resultsList != null && _resultsList.length > 0) {
// we have some results
for (int i = 0; i < _resultsList.length; i++) {
String bb = directory[i];
String nodeFive = new String(bb);
this.myTree.addChildNode(node10, nodeFive);
}
} else {
}
}
private class TreeCallback implements TreeFieldCallback {
public void drawTreeItem(TreeField _tree, Graphics g, int node, int y,
int width, int indent) {
final int PAD = 8;
String text = (String) _tree.getCookie(node);
Bitmap icon = closedIcon;
if (text.endsWith(".mp3")) {
icon = songIcon;
} else if (text.endsWith(".avi")) {
icon = movieIcon;
} else if (text.endsWith(".png") || text.endsWith(".jpg")) {
icon = imgIcon;
} else if (_tree.getExpanded(node)) {
icon = openIcon;
}
g.drawBitmap(indent, y, icon.getWidth(), icon.getHeight(), icon, 0,
0);
// This assumes filenames all contain '.' character!
if (text.indexOf(".") > 0) {
// Leaf node, so this is a playable item (movie or song)
g.drawBitmap(_tree.getWidth() - playIcon.getWidth() - PAD, y
+ PAD, playIcon.getWidth(), playIcon.getHeight(),
playIcon, 0, 0);
}
int fontHeight = getFont().getHeight();
g.drawText(text, indent + icon.getWidth() + PAD,
y + (_tree.getRowHeight() - fontHeight) / 2);
}
}
}
The other classes that used with this code, download from that link(complete project classes)
http://remote.offroadstudios.com/files/filemanager.zip
you can also check files on server, ip:64.207.150.31:21, username:remote, password:123456789
Pretty new to monogame (mono for android to be precise) but with some youtube tutorials the process was fairly pain free.
I'm trying to override some functions (from an "XNA library project" dll) I can override all the functions just fine. But when I try to override anything that passes in a SpriteBatch as an argument I get the follow error:
Error 5 'Parkour.Screens.EditorScreen.Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch)':
no suitable method found to override D:\Data\programming and
such\comps\TIGsport\XNA\Parkour\Parkour\Parkour\Screens\EditorScreen.cs 117 30 ParkourAndroid
I'm absolutely sure the method is there, because the XNA project works just fine.
The Draw function also pops up in autocorrect in the mono for android project. But strange enough it seems to have dissapeared from autocorrect after I received the error.
Here is the entire class which holds the to be override function, just so you guys can be sure nothing is wrong.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
namespace SimpleTilebasedLibrary.Utils
{
public class LoopContainer<T> where T : ILoopable
{
protected List<T> _items = new List<T>();
private List<T> _addList = new List<T>();
private List<T> _removeList = new List<T>();
public List<T> items
{
get{return _items;}
}
public virtual void add(T item)
{
//if (_addList.Contains(item)) return;
//_addList.Add(item);
_items.Add(item);
}
public virtual void remove(T item)
{
if (_removeList.Contains(item)) return;
_removeList.Add(item);
}
public T get(int index)
{
return _items[index];
}
public T get(string name)
{
foreach (T item in items)
{
if (item.getName() == name)
{
return item;
}
}
return default(T);
}
public virtual void Update()
{
items.AddRange(_addList);
_addList.Clear();
foreach (T item in items)
{
if (item.status == Status.DEAD)
{
_removeList.Add(item);
//break; //root of all evil
continue;
}
item.Update();
}
//remove
foreach (T i in _removeList)
{
items.Remove(i);
}
_removeList.Clear();
}
public virtual void postUpdate()
{
foreach (T item in items)
{
item.postUpdate();
}
}
public virtual void Draw(SpriteBatch spritebatch)
{
foreach (T item in items)
{
item.Draw(spritebatch);
}
}
}
}
And the class that is trying to override it
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SimpleTilebasedLibrary;
using SimpleTilebasedLibrary.Entities;
using SimpleTilebasedLibrary.Tilesystem;
using SimpleTilebasedLibrary.Services;
using Microsoft.Xna.Framework.Input;
using SimpleTilebasedLibrary.Components;
using SimpleTilebasedLibrary.Utils;
using SimpleTilebasedLibrary.UI;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Parkour.Screens
{
public class EditorScreen : GameScreen //need to couple gamescreens with inputcontexts?
{
public ParkourWorld world;
int currentTile = 0;
GameObject tile;
Checkbox editorEnabled;
Checkbox solidCB;
Checkbox autotileCB;
public EditorScreen(ParkourWorld world)
: base("editorscreen")
{
this.world = world;
tile = new GameObject("tileset", 16, 16); //never actually tested this, doesn't work!
tile.GetC<GraphicsC>().setScale(2, 2);
//add(tile); //something fucks up the coordinates when you add it...
editorEnabled = new Checkbox(Color.White, 10);
editorEnabled.GetC<TransformC>().Y = 10;
editorEnabled.GetC<TransformC>().X = 100;
solidCB = new Checkbox(Color.Red, 10);
solidCB.GetC<TransformC>().Y = 10;//30;
solidCB.GetC<TransformC>().X = 120;
//add(solidCB);
autotileCB = new Checkbox(Color.Blue, 10);
autotileCB.GetC<TransformC>().Y = 10;//50;
autotileCB.GetC<TransformC>().X = 140;
//add(autotileCB);
editorEnabled.value = false;
}
public override void Update()
{
base.Update();
if (GameServices.get<InputManager>().hasScrolledDown() && currentTile > 0)
{
currentTile--;
}
if (GameServices.get<InputManager>().hasScrolledUp() && currentTile < tile.GetC<GraphicsC>().totalFrames - 1)
{
currentTile++;
Console.WriteLine(currentTile);
}
tile.GetC<GraphicsC>().gotoAndStop(currentTile);
//
if (Mouse.GetState().LeftButton == ButtonState.Pressed && editorEnabled.value)
{
GameCamera camera = GameServices.get<CameraManager>().getActiveCamera();
int x = TileMath.PixelToTile((Mouse.GetState().X + (camera.GetC<CameraC>().leftX * camera.GetC<CameraC>().zoom)) / camera.GetC<CameraC>().zoom, world.tilegrid.tileWidth);
int y = TileMath.PixelToTile((Mouse.GetState().Y + (camera.GetC<CameraC>().UpY * camera.GetC<CameraC>().zoom)) / camera.GetC<CameraC>().zoom, world.tilegrid.tileHeight);
if (Keyboard.GetState().IsKeyDown(Keys.Z))
{
world.tilegrid.setTile(x, y, 0, null);
//world.tilegrid.getTile(x, y, 0).id = 1;
//world.tilegrid.getTile(x, y, 0).solid = false;
}
else
{
Tile t = world.tilegrid.setTile(x, y, 0, currentTile);
if (t != null) t.solid = solidCB.value;
if(autotileCB.value)world.tilegrid.AutoTile(t, 0, x, y, true);
//world.tilegrid.setTile(x, y, 0, null);
}
}
// enable and disable cb's //
if (GameServices.get<InputManager>().wasKeyPressed(Keys.LeftShift))
{
solidCB.value = !solidCB.value;
}
if (GameServices.get<InputManager>().wasKeyPressed(Keys.Q))
{
autotileCB.value = !autotileCB.value;
}
if (GameServices.get<InputManager>().wasKeyPressed(Keys.E))
{
editorEnabled.value = !editorEnabled.value;
}
solidCB.Update();
autotileCB.Update();
}
public override void Draw(SpriteBatch spritebatch)
{
base.Draw(spritebatch);
tile.Draw(spritebatch);
editorEnabled.Draw(spritebatch);
solidCB.Draw(spritebatch);
autotileCB.Draw(spritebatch);
CameraC camera = GameServices.get<CameraManager>().getActiveCameraC();
int width = TileMath.PixelToTile(camera.viewrect.Left + camera.viewrect.Width + (world.tilegrid.tileWidth * 2), world.tilegrid.tileWidth);
int height = TileMath.PixelToTile(camera.viewrect.Top + camera.viewrect.Height + (world.tilegrid.tileHeight * 2), world.tilegrid.tileHeight);
if (editorEnabled.value)
{
spritebatch.End();
spritebatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, null, null, null, GameServices.get<CameraManager>().getActiveCameraC().getTransformation());
//getTile(width - 1, 0).GetComponent<GraphicsC>().sprite.gotoAndStop(4);
Rectangle rect = new Rectangle();
Color trans = new Color(255, 0, 0, 10);
for (int x = TileMath.PixelToTile(camera.viewrect.Left, world.tilegrid.tileWidth); x < width; x++)
{
for (int y = TileMath.PixelToTile(camera.viewrect.Top, world.tilegrid.tileHeight); y < height; y++)
{
if (world.tilegrid.getTile(x, y, 0) != null)
{
if (!world.tilegrid.getTile(x, y, 0).solid) continue;
rect.X = x * world.tilegrid.tileWidth;
rect.Y = y * world.tilegrid.tileHeight;
rect.Width = world.tilegrid.tileWidth;
rect.Height = world.tilegrid.tileHeight;
spritebatch.Draw(GameServices.get<AssetManager>().CreateColoredTexture(trans), rect, Color.White);
}
}
}
spritebatch.End();
spritebatch.Begin();
}
}
}
}
There is alot of useless stuff in there for you guys, but I wanted to include it just for the sake of completeness.
I have the exact same problem with another class that has a Draw(SpriteBatch) function that needs to be overriden.
Turned out that I was passing in a MonoGame spritebatch where the library was requiring an XNA spritebatch. I recompiled the library in a seperate project with MonoGame and all problems are sovled.
I was wondering if MonoTouch allows the developer to change the colour of UIPageControl dots to suit a light background - they seem to be fixed white, which makes them very hard to see on a light textured background.
I am aware there is no public API available for this but I was wondering if anything was internally implemented in MonoTouch to improve on this.
Otherwise, what's the recommended approach to using a UIPageControl on a light background?
I took a stab at translating this. I'm not sure it will work, but it does compile. Note that the page linked to contains comments indicating that Apple frowns upon this code and may reject it:
using System;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
namespace Whatever
{
public class StyledPageControl : UIPageControl
{
public StyledPageControl () : base()
{
}
public override int CurrentPage {
get {
return base.CurrentPage;
}
set {
base.CurrentPage = value;
string imgActive = NSBundle.MainBundle.PathForResource("activeImage", "png");
string imgInactive = NSBundle.MainBundle.PathForResource("inactiveImage", "png");
for (int subviewIndex = 0; subviewIndex < this.Subviews.Length; subviewIndex++)
{
UIImageView subview = this.Subviews[subviewIndex] as UIImageView;
if (subviewIndex == value)
subview.Image = UIImage.FromFile(imgActive);
else
subview.Image = UIImage.FromFile(imgInactive);
}
}
}
public override int Pages {
get {
return base.Pages;
}
set {
base.Pages = value;
string img = NSBundle.MainBundle.PathForResource("inactiveImage", "png");
for (int subviewIndex = 0; subviewIndex < this.Subviews.Length; subviewIndex++)
{
UIImageView subview = this.Subviews[subviewIndex] as UIImageView;
subview.Image = UIImage.FromFile(img);
}
}
}
}
}
Convert the following code to C#: http://apptech.next-munich.com/2010/04/customizing-uipagecontrols-looks.html
I combined this and this for monotouch. I hope this helps.
The usage is like this:
_pager.Change += delegate(object sender, EventArgs e) {
var pc = sender as PageControl;
Console.WriteLine ("Change Delegate== " + pc.currentPage);
var toPage = pc.currentPage;
var pageOffset = _scroll.Frame.Width*toPage;
PointF p = new PointF(pageOffset, 0);
Console.WriteLine (pageOffset);
_scroll.SetContentOffset(p,true);
};
And the class like this.
public class PageControl:UIView
{
#region ctor
public PageControl (RectangleF rect) :base(rect)
{
this.BackgroundColor = UIColor.Red;
this.CurrenColor=new CGColor(.2f,15f,10F);
this.OtherColor =new CGColor(.77F,.71F,.60F);
}
#endregion
#region Fields
float kDotDiameter= 7.0f;
float kDotSpacer = 7.0f;
int _currentPage;
int _numberOfPages;
CGColor CurrenColor{get;set;}
CGColor OtherColor{get;set;}
public int currentPage
{
set
{
_currentPage = Math.Min(Math.Max(0, value),_numberOfPages-1);
this.SetNeedsDisplay();
}
get{return _currentPage;}
}
public int numberOfPages
{
set
{
_numberOfPages = Math.Max(0,value);
_currentPage = Math.Min(Math.Max(0, _currentPage), _numberOfPages-1);
this.SetNeedsDisplay();
}
get{return _numberOfPages;}
}
#endregion
#region Overrides
public override void Draw (RectangleF rect)
{
base.Draw (rect);
CGContext context = UIGraphics.GetCurrentContext();
context.SetAllowsAntialiasing(true);
RectangleF currentBounds = this.Bounds;
float dotsWidth = this.numberOfPages*kDotDiameter + Math.Max(0,this.numberOfPages-1)*kDotSpacer;
float x = currentBounds.GetMidX() - dotsWidth/2;
float y = currentBounds.GetMidY() - kDotDiameter/2;
for (int i = 0; i < _numberOfPages; i++) {
RectangleF circleRect = new RectangleF(x,y,kDotDiameter,kDotDiameter);
if (i==_currentPage) {
context.SetFillColor(this.CurrenColor);
}
else {
context.SetFillColor(this.OtherColor);
}
context.FillEllipseInRect(circleRect);
x += kDotDiameter + kDotSpacer;
}
}
public override void TouchesBegan (MonoTouch.Foundation.NSSet touches, UIEvent evt)
{
base.TouchesBegan (touches, evt);
PointF touchpoint = (touches.AnyObject as MonoTouch.UIKit.UITouch).LocationInView(this);
RectangleF currentbounds = this.Bounds;
float x = touchpoint.X- currentbounds.GetMidX();
if (x<0 && this.currentPage>=0) {
this.currentPage--;
Change(this,EventArgs.Empty);
}
else if (x>0 && this.currentPage<this.numberOfPages-1) {
this.currentPage++;
Change(this,EventArgs.Empty);
}
}
#endregion
#region delegate
public event EventHandler Change;
#endregion
}
Is it possible in j2me to measure signal amplitude of audio record made by JSR-135 Player?
I know I can access buffer, but then what?
Target model Bold 9000, supported formats PCM and AMR. Which format I should use?
See also
Blackberry Audio Recording Sample Code
How To - Record Audio on a BlackBerry smartphone
Thank you!
Get raw PCM signal level
Use menu and trackwheel to zoom in/out and move left/right within graph.
Audio format: raw 8000 Hz 16 bit mono pcm.
Tested on Bold 9000 RIM OS 4.6
Algorythm should work in any mobile, where j2me and pcm is supported, of course implementation may require changes.
Using thread for audio recording:
class VoiceNotesRecorderThread extends Thread {
private Player _player;
private RecordControl _rcontrol;
private ByteArrayOutputStream _output;
private byte _data[];
VoiceNotesRecorderThread() {
}
public void run() {
try {
_player = Manager
.createPlayer("capture://audio?encoding=audio/basic");
_player.realize();
_rcontrol = (RecordControl) _player
.getControl("RecordControl");
_output = new ByteArrayOutputStream();
_rcontrol.setRecordStream(_output);
_rcontrol.startRecord();
_player.start();
} catch (final Exception e) {
UiApplication.getUiApplication().invokeAndWait(new Runnable() {
public void run() {
Dialog.inform(e.toString());
}
});
}
}
public void stop() {
try {
_rcontrol.commit();
_data = _output.toByteArray();
_output.close();
_player.close();
} catch (Exception e) {
synchronized (UiApplication.getEventLock()) {
Dialog.inform(e.toString());
}
}
}
byte[] getData() {
return _data;
}
}
And method for painting graph using byte[] buffer:
private Bitmap getGraph(byte[] buffer, int zoom, int startFrom) {
Bitmap result = new Bitmap(Display.getWidth(), Display.getHeight());
Graphics g = new Graphics(result);
g.setColor(Color.BLACK);
int xPos = 0;
int yPos = Display.getHeight() >> 1;
for (int i = startFrom; i < buffer.length; i += 2 * zoom) {
byte[] b = new byte[] { buffer[i], buffer[i + 1] };
int level = (signedShortToInt(b) * 100 / 32767);
if (100 < level) {
level -= 200;
}
g.drawPoint(xPos, yPos - level);
xPos++;
}
return result;
}
public static final int signedShortToInt(byte[] b) {
int result = (b[0] & 0xff) | (b[1] & 0xff) << 8;
return result;
}
Screen class:
class Scr extends MainScreen {
BitmapField mGraphField = new BitmapField(new Bitmap(Display.getWidth(),
Display.getHeight()));
private VoiceNotesRecorderThread m_thread;
public Scr() {
add(mGraphField);
add(new NullField(FOCUSABLE));
}
boolean mRecording = false;
private int mZoom = 1;
private int mStartFrom = 0;
byte[] mAudioData = null;
protected void makeMenu(Menu menu, int instance) {
super.makeMenu(menu, instance);
menu.add(mRecordStopMenuItem);
menu.add(mPaintZoomIn);
menu.add(mPaintZoomOut);
menu.add(mPaintZoomToFitScreen);
menu.add(mPaintMoveRight);
menu.add(mPaintMoveLeft);
menu.add(mPaintMoveToBegin);
}
MenuItem mRecordStopMenuItem = new MenuItem("Record", 0, 0) {
public void run() {
if (!mRecording) {
m_thread = new VoiceNotesRecorderThread();
m_thread.start();
mRecording = true;
this.setText("Stop");
} else {
m_thread.stop();
mAudioData = m_thread.getData();
zoomToFitScreen();
mRecording = false;
this.setText("Record");
}
}
};
MenuItem mPaintZoomIn = new MenuItem("Zoom In", 0, 0) {
public void run() {
zoomIn();
}
};
MenuItem mPaintZoomOut = new MenuItem("Zoom Out", 0, 0) {
public void run() {
zoomOut();
}
};
MenuItem mPaintZoomToFitScreen = new MenuItem("Fit Screen", 0, 0) {
public void run() {
zoomToFitScreen();
}
};
MenuItem mPaintMoveLeft = new MenuItem("Left", 0, 0) {
public void run() {
moveLeft();
}
};
MenuItem mPaintMoveRight = new MenuItem("Right", 0, 0) {
public void run() {
moveRight();
}
};
MenuItem mPaintMoveToBegin = new MenuItem("To Begin", 0, 0) {
public void run() {
moveToBegin();
}
};
private void zoomOut() {
if (mZoom < 200)
mZoom++;
mGraphField.setBitmap(getGraph(mAudioData, mZoom, mStartFrom));
}
private void zoomIn() {
if (mZoom > 1)
mZoom--;
mGraphField.setBitmap(getGraph(mAudioData, mZoom, mStartFrom));
}
private void zoomToFitScreen() {
int lenght = mAudioData.length;
mZoom = (lenght / 2) / Display.getWidth();
mGraphField.setBitmap(getGraph(mAudioData, mZoom, mStartFrom));
}
private void moveRight() {
if (mStartFrom < mAudioData.length - 30)
mStartFrom += 30;
mGraphField.setBitmap(getGraph(mAudioData, mZoom, mStartFrom));
}
private void moveLeft() {
if (mStartFrom > 30)
mStartFrom -= 30;
mGraphField.setBitmap(getGraph(mAudioData, mZoom, mStartFrom));
}
private void moveToBegin() {
mStartFrom = 0;
mGraphField.setBitmap(getGraph(mAudioData, mZoom, mStartFrom));
}
protected boolean navigationMovement(int dx, int dy, int status,
int time) {
if (dx < 0) {
moveLeft();
} else if (dx > 0) {
moveRight();
}
if (dy < 0) {
zoomIn();
} else if (dy > 0) {
zoomOut();
}
return super.navigationMovement(dx, dy, status, time);
}
}
Was helpfull:
ADC -> integer PCM file -> signal processing
SO - How is audio represented with numbers?
Convert byte array to integer
In most devices, only MID format with a single track is supported. That is the mid0 format that supports multiple instruments in one single track. I am not sure if the api provides the facility to measure the amplitude of a signal. To convert mid files to you can use Anvil Studio that has both free and pro versions
To record audio you need to use Manager.createPlayer("capture://audio"). Also leave the encoding (PCM or AMR) to the device implementation because some phones don't support PCM/AMR
Hope this helps!