Nov 4 2011

Enable 32-bit Color if Your Application Supports It

Category: MobileJoel Ivory Johnson @ 04:56

The first generation Windows Phones had hardware that used both 16-bit and 32-bit color, but the operating system would force the display to use 16 color regardless. If you have graphics with smooth gradients then then you would end up seeing color bands on a 16-bit display. On Mango if a phone supports 32-bit color you can take advantage of it, but only if you ask! If you want to enable 32-bit color you will need to edit your WMAppManifest.xml. In the <App /> element add an attribute called BitsPerPixel setting its value to 32. That's all you need to do. After doing that when your application runs on a device with 32-bit graphics hardware it will display in 32-bit color mode. 

 

Tags:

Oct 15 2011

Augmented Reality Part 1: Getting Orientation Data

Category: MobileJoel Ivory Johnson @ 07:03
Download Code (382 Kb)

A few days ago I started developing a program for controlling my computerized telescope with my phone. Before I knew it I found myself in topics that are all a part of augmented reality. I thought it may be helpful to others if I collected my notes together to share. I'm trying something new with this post also. In addition to the blog post and the code I've also made this information available in video form at the links above. The video and this post cover the same information.

Before getting started with Augmented Reality you will want to make sure that you have a device that has the supported features. A lot of the concepts that I share in this series could be applied to other phones, but I will be concentrating on Windows Phone and taking advantage of the features and functionality that it has to provide. If you want to make use the information these posts on other devices you may have to find or make implementations for some high level functionality if your device and development environment does not already provide it.

To get started you will need a computer with the Windows Phone Developer Tools installed and a Windows Phone. Not all Windows Phones will work though. The phone will need to have GPS hardware and a compass/magnometer. All windows phones GPS hardware but not all phones have the magnometer. There are some devices that have a magnometer but don't have the driver needed to make it available to third party developers. At the time I am writing this I have two phones that have Mango installed. My HD7 has a compass but it does not have the necessary driver. My Samsung Focus does have the necessary driver. Before we go any further let's ensure that your device supports the magnometer. If it doesn't you'll need to find a device that does before you can proceed any further with development.

Does My Phone Support the Needed APIs

To test your device create a new Windows Phone project and add a reference to Microsoft.Devices.Sensors. You only need one line of code to check whether or not your device has a mangometer.

bool compassFound = Motion.IsMotionAvailable;

Set a break point after that line and run the program on your phone (at present it will always return "false" on the emulator). Hopefully it will return "true" for you.

Getting the Device's Orientation

Once you have a device that supports the compass let's get the device's orientation. At the very least your device has a magnometer and an accelerometer in it. It may also have a gyrometer in it too if it is a more recent device. You could get the readings from all of these sensor's individually but we'll rely on the Motion API to get the information from the sensors that it finds present and let it perform the math needed to get the data in an easy-to-consume form. The general pattern that you will use when interacting with the sensor APIs is that you'll create an object to represent a sensor, subscribe to an event to get notifications about the reading changing, and then call a Start() method to turn on the sensor and to start receiving data from it.

The compass (And thus the Motion API) requires calibration from time to time. In addition to an event that is called when there is sensor data there is also an event for notification that the device requires calibration. If this event is fired you'll need to tell the user to move his or her phone in a figure 8. Once the phone is calibrated your application will start to receive readings and you can remove the notification.

bool IsMotionAvailable {get; set; }
private Motion _motion;

IsMotionAvailable = Motion.IsSupported; 
if (IsMotionAvailable)
{
    _motion = new Motion();
    _motion.Calibrate += new EventHandler(motion_Calibrate);
    _motion.CurrentValueChanged += new EventHandler>(motion_CurrentValueChanged);
    _motion.Start();
}

The information that comes back from the Motion API tells us both the device's current orientation and movement/acceleration. For now we are only concerned with the device's orientation and will ignore the other data that is available. For now the fields of interest are the Pitch, Yaw, Roll, and Quanternion. The fist three figures are also used when describing the motion of an aircraft. If an aircraft is changing it's pitch that means that the front of the plan is being tilted up or down. If the airplanes wings remained level but it started moving to the left or right then its yaw is changing. And finally if the plane starts to tilt to the left or right then we would say the plane is rolling. These terms are applied to the phone in a similar way. If you have the device laying face up on a level table with the top of the device facing north than it's pitch, yaw, and roll are all set to zero. (I will call this the "zero position"). As you change the device's orientation these fields will change accordingly. The Motion API returns rotational measurements in radians. This makes sense given that the math functions available from the .Net framework also work with radians. But when displaying them on the screen it is easier to work with degrees. So for display only I have radian to degree converter.

public class RadToDegreeConverter : IValueConverter
{

    public object Convert(object value, Type targetType, 
                                      object parameter, 
                                      System.Globalization.CultureInfo culture)
    {
        double v;
        if (value is float)
            v = (float)value;
        else if (value is double)
            v = (double)value;
        else if (value is decimal)
            v = (double)(decimal)value;
        else
            return String.Empty;
        v = v * 180d / Math.PI;
        return v.ToString("000.0");

    }

    public object ConvertBack(object value, 
                                             Type targetType, 
                                             object parameter, 
                                             System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

The Quanternion figure that comes back also contains rotational information and is consumable by the XNA vector classes. I use the Yaw, Pitch, and Roll for display purposes only but use the Quanternion field in actual algorithms. Your augmented reality application will want to know the direction hat the camera on the phone is facing. Assuming that you are using the rear facing camera that means you will want to know the direction that the rear of the device is facing. To get this information start with creating a Vector3 that represents the direction that the rear of the device is facing when it is at the zero position. This vector will get rotated with the data that comes back from the Motion API and the resulting vector tells us which way that the device is facing.

Vector3 DeviceFaceVector = new Vector3(0,0,-10); 
Vector CurrentDirectionVector { get; set; } 

void motion_CurrentValueChanged(object sender, SensorReadingEventArgs e) 
{
 var attitude = e.SensorReading.Attitude;
 this.Dispatcher.BeginInvoke(() => 
  { 
     IsCalibrated = true; 
     Pitch = attitude.Pitch; 
     Yaw = attitude.Yaw; 
     Roll = attitude.Roll; 
     CurrentDirectionVector = Vector3.Transform(DeviceFaceVector, attitude.Quaternion); 
   }); 
} 

The CurrentDirectionVector will tell us what direction that the back of the device is facing. Let's convert it from a Cartesian (x,y,z) coordinate to a polar coordinate so that we can display the direction the phone is facing (measured as degrees from north) and the angle towards the sky or ground that the phone is tilted. Only a few function calls are needed to do this conversion

void CalculateAltaAzimuth()
{
    double x = CurrentDirectionVector.X;
    double y = CurrentDirectionVector.Y;
    double z = CurrentDirectionVector.Z;

    ViewingAzimuth = Math.Atan2(x, y);
    ViewingAltitude = Math.Atan2(z, Math.Sqrt(x*x + y*y));
}

Displaying the Values on the Screen

To display these values on the screen I will make use of data binding. But I also want to have the camera's point of view used as the program background. Eventually we will be overlaying images on this background. To have the image as a background create a framework element (grid, rectangle, canvas, or some other element) that is stretched over the portion of the screen in which you want the background to display. I'll have it stretched over the entire screen.

<Canvas Width="800" Height="480" x:Name="RealityOverlay">

In the code-behind I need to make a video brush that will be used to paint this surface. The video-brush will have the camera set as it's source.

_photoCamera = new PhotoCamera(CameraType.Primary);
VideoBrush vb = new VideoBrush();
vb.SetSource(_photoCamera);
PhotoBackground.Fill = vb;

This get's us as far as knowing how to tell the device's position. In the next post I'll show how to get the distance and direction to points of interest. Then I'll show how to project those points of interest onto the screen so that they appear to be part of the environment.

Video Explaining the Above

3 minute Code Walkthrough

Tags: ,

Oct 13 2011

I seem to have Stumbled Into Augmented Reality...

Category: Joel Ivory Johnson @ 10:07

At this time of the year the best time to get a picture of the planet Jupiter from where I live is around 3:00am. I've got my telescope by the door so that at first opportunity I can quickly take it outside to perform setup and start taking pictures. But I didn't get a chance to do this Saturday on account of weather. It was cloudy outside and rain was in the forecast, so I knew I wouldn't have an opportunity. So I instead decided to turn my efforts towards something that would be of assistance to my telescope usage in the future. The telescope has a hand control device but in an age with so many smart phones I thought I could do better. So I decided to start on implementing my own hand control with my Windows Phone. 

My first goal was to simply make something that I could use to control the telescope within 24 hours. For the initial run there is a laptop connected to the RS232 port on my telescope. It will eventually be replaced with a .Net Micro Framework device, but for a prototype with 24-hour turn around trying to get custom hardware up and running was not possible. I made a client for my phone that would be my primary point of control for the telescope. I was successful at getting my goal achieved but at the end of it I came to realize that I had started to get into some augmented reality concepts without trying.

I had been taking notes and video logs of my progress (one video log entry is below) and I'll be breaking them down into a form that is more applicable to general applications. Some of the math involved can be scary, so to keep it understandable by more people I will by be making use of the math routines available in XNA and allow the reader to look further into XNA if he or she wants to know what it is doing behind the scenes. For example, you will see how to use an XNA matrix to do rotation calculations, but I won't be explaining what XNA is doing behind the scenes to perform such operation.

The first of several post that comes from my weekend efforts will come tomorrow evening after I proof a few things.

Video

Tags: ,

Oct 11 2011

What Does Windows 8 Mean for Windows Phone Developers?

Category: Desktop and Server | MobileJoel Ivory Johnson @ 01:24

It was only a few weeks ago that Windows 8 was unveiled at the Build conference. At first glance it looks a lot like Windows Phone with heavy use of the Metro visual language. The only part of the system that hasn't had the Metro touch is the desktop (unlike previous versions of Windows the Desktop is not something that is always running). The Start menu looks like the Windows Phone start screen only it scrolls horizontally instead of vertically. The only mention of Silverlight is that you could still use it in Desktop mode for backwards compatibility, but the Metro [default] instance of IE would run no plug-ins, including Silverlight. The programming model also is not based off of Silverlight or the Desktop .Net runtime. Its based on something new called WinRT (Windows Runtime). 

At first glance this is something that has concerned Silverlight and Windows Phone developers. At first glance some one might come to the conclusion that the skill in which he or she has invested has become second class in Windows 8. Is Silverlight really getting killed off? What's going to happen for the Silverlight based Windows Phone?

I don't know the future any more than the next person, but what I saw at Build isn't something that raised concern. I found it to be rather reassuring. Before I explain why let me grant the elephant in the room, the rumor that Silverlight is going to be dead. I don't believe this rumour. For years people have predicted that certain Microsoft Technologies were dead (DirectX, .Net, and many other technologies that we still use today). But I'll grant it anyway so that we can explore what seems to be a popular concern. 

Let's assume that next year Microsoft announces that it is going to sunset Silverlight and toss out the Windows Phone programming model in favour of the Windows 8 programming model. What does this mean for the skills that you have developed? Are they now useless? You've been developing skills in C#/VB, XAML, asynchronous programming, and some APIs that were specific to Silverlight and Windows Phone. Let's look at how each one of these will contribute to your Windows 8 development. 

Languages: C# and VB

C# and VB are still being used on Windows 8. If you've been using these languages you can continue to use them. Additionally if you know C++ or have algorithms that had been written in C++ you'll be able to port them over to Windows 8. Windows 8 also supports JavaScript as a programming language too. 

XAML

XAML is still used on Windows 8 for building your UI. Many of the elements you've become familiar with are present in addition to some new ones. No huge changes there. 

Asynchronous Programming

One of the challenges for developers that were new to Silverlight was that task that one may have been used to doing synchronously are only available as asynchronous calls. On Windows 8 you'll find that many of the tasks that were asynchronous in Silverlight and Windows Phone are still asynchronous. Additionally other APIs have been made asynchronous, including File IO. 

The Familiar and What This All Means

You'll come across APIs that look similar of not identical to what you've seen in Windows Phone and Silverlight. Windows 8 has the concept of an application getting tombstoned, specifying the permissions it needs, and so on. Windows 8 Metro applications will only be distributed through the Marketplace. Doesn't all of this sound familiar. If you are a Windows Phone developer it should. You've already got a head start on Windows 8 development. This is far from the doom and gloom picture that some stories would have some one believe. 

If you want to dive into Windows 8 programming the 64-bit development images are available for download. I suggest running them on real hardware. I tried them in the emulator VirtualBox and it's just not the same experience there. 

Tags: , , ,

Sep 20 2011

Remember the Permission

Category: MobileJoel Ivory Johnson @ 08:01

I had a bit of a late night last night. I had just downloaded the Windows Live SDK and wanted to try it out. I took the Voice Memo application tha tI put on CodeProject.com and tried to add a feature to upload recordings to Skydrive. In the SDK there is a SignInButton controll and setting some parameters on this control along with responding to an event the control has is all that is needed to to make use of it. When I ran my program it failed with an error about the WebBrowserControl neededing to be on the visual tree before it is used. 

You cannot call WebBrowser methods until it is in the visual tree."

This was a little confusing to me at first. I am not using a web browser control anywhere in my program. So I played with the parameters on the control trying to see if I could change the response I was getting. After continual failure I posted a question on the Windows Live Connect support forums.  One of the Microsoft employees asked me if I could make a simple project demonstrating the problem. When I made my simple project the error would not occur. I then realized what was causing the problem. The Voice Memo application has had its permissions appropriately reduced. But those reduced permissions did not include what was needed by the login control. I ran the Windows Phone Marketplace Test kit and it told me the other permissions that I needed; ID_CAP_WEBBROWSERCOMPONENT  and ID_CAP_NETWORKING. After adding those permissions it worked like a charm!

Rather than sweep my mistake under a rug I thought I would share it in the hopes that posting this will save some one from having made the simple yet time consuming oversight that I had

 

Tags: ,

Sep 16 2011

Windows Phone Camp is Coming!

Category: MobileJoel Ivory Johnson @ 16:08

What's a Windows Phone Camp? 
A free, full day event chock-full of everything you need to know to develop a Windows Phone application. Whether you're a seasoned veteran or just getting started with .NET development this full-day event is for you. Interested in profit? We'll also lead discussions on how to monetize your applications and generate profits with your apps.

Don't miss the new Windows Phone 7.5 (codename "Mango") features as well - with detailed sessions in the afternoon around Fast Application Switching, Multitasking, Live Tiles, Push Notifications, and more. 

The day will be capped with an 
open lab hands-on session and prizes for apps completed. This is the perfect opportunity to begin work on your dream application, or finish that app you've already started, with Windows Phone experts there to guide you every step of the way. Bring your own laptop to join in the fun and show off your killer app! 

Agenda

9:00 AM

 

Description: Description: Description: C:\Users\Public\Documents\Webcamps Email - All\PHONE CAMPS\phonecamps_metro_er_allup_OFT_EVANG\spacer.gif

 

Welcome Campers

9:15 AM

 

Description: Description: Description: C:\Users\Public\Documents\Webcamps Email - All\PHONE CAMPS\phonecamps_metro_er_allup_OFT_EVANG\spacer.gif

 

How to make money with your Windows Phone app

10:00 AM

 

Description: Description: Description: C:\Users\Public\Documents\Webcamps Email - All\PHONE CAMPS\phonecamps_metro_er_allup_OFT_EVANG\spacer.gif

 

Frameworks for fun and profit > Silverlight and XNA

 

 

Description: Description: Description: C:\Users\Public\Documents\Webcamps Email - All\PHONE CAMPS\phonecamps_metro_er_allup_OFT_EVANG\spacer.gif

 

Canteen

1:00 PM

 

Description: Description: Description: C:\Users\Public\Documents\Webcamps Email - All\PHONE CAMPS\phonecamps_metro_er_allup_OFT_EVANG\spacer.gif

 

Hands-on lab

3:00 PM

 

Description: Description: Description: C:\Users\Public\Documents\Webcamps Email - All\PHONE CAMPS\phonecamps_metro_er_allup_OFT_EVANG\spacer.gif

 

Cool stuff your app can do

4:00 PM

 

Description: Description: Description: C:\Users\Public\Documents\Webcamps Email - All\PHONE CAMPS\phonecamps_metro_er_allup_OFT_EVANG\spacer.gif

 

To the Cloud

4:45 PM

 

Description: Description: Description: C:\Users\Public\Documents\Webcamps Email - All\PHONE CAMPS\phonecamps_metro_er_allup_OFT_EVANG\spacer.gif

 

Be What's Next > People's Choice Awards


Prerequisites 

Bring a notebook computer and identification. Also check out the APP HUB where you can get developer toolslearn about application featuresunderstand common task for Apps and register and load your APP.


Notes:
 
This event is brought to you by Microsoft and is free of charge. However, you are responsible for booking and paying for your own travel and accommodations.

Event Locations
9/20 - Charlotte, NC
9/22 - Alpharetta, GA
9/27 - Malvern, PA
9/29 - Reston, VA
10/18 - Chevy Chase, MD
10/19 - New York, NY
10/25 - Tampa, FL
10/27 - Burlington, VT
11/2 - Raleigh, NC
11/4 - Ft. Lauderdale, FL
11/8 - Orlando, FL
11/10 - New Paltz, NY
11/10 - Miami, FL
11/15 - Blacksburg, VA
11/17 - Washington, DC
11/29 - Pittsburgh, PA
11/29 - Atlanta, GA
12/1 - Long Island, NY

Tags: , ,

Aug 29 2011

StartUp Camp

Category: Joel Ivory Johnson @ 16:01

This weekend I went to an event known as "StartUp." Apparently these events are not uncommon, but it was new to me and was an interesting experience. In a Start-up weekend people present their ideas for an application to developers, artists, and people of other skills. After the presentation of the initial ideas people organize themselves into teams and try to make the application a reality.

The event ran from Friday to Sunday. Of those three days I was only present on Sunday to help some people out and ended up being dedicated to a single team helping them out with their Windows Phone coding. At the end of the event every one does their presentations on what they came up with to a panel of judges. There's also people there that are ready to fund projects. I wish I had known of events like this before. These are perfect opportunities for people that have application ideas but can't make the application by themselves. 

Tags: ,

Aug 27 2011

Slides from What's New in Windows Phone Mango

Category: Joel Ivory Johnson @ 16:36
Last month I did a presentation at the Macon .Net user group on what's new in Windows Phone Mango. I also presented this at the Atlanta Windows Phone developer's group. The slides were uploaded to Skydrive a few days ago but I never did post the link. So here it is. You can download the slides and the example code from here.

Tags: , ,

Aug 7 2011

Windows Phone NTP Client

Category: MobileJoel Ivory Johnson @ 04:17
Download Code (53 KB)

I've got plans for an application in which I need to know with certainty the current time. So I don't want to trust the time as reported by the user's device. Instead I need to retrieve the time from a server. I made a NTP (Network Time Protocol) client for retrieving this information. This is something that couldn't be done on Windows Phone 7 prior to Mango. But with the fall update (Mango) access to sockets is granted.

The use of the client is pretty simple. At minimum one can create the client with the default constructor, subscribe to the ReceivedTime event, and call the RequestTime method to initiate a request. The ReceivedTime event may be called on a thread other than the UI thread so remember to use a dispatcher when making UI updates.

NTP Client

This is an example of a client using the code to display both the system time and the network time.

public partial class MainPage : PhoneApplicationPage
{
    private NtpClient _ntpClient;
    public MainPage()
    {
        InitializeComponent();
        _ntpClient = new NtpClient();
        _ntpClient.TimeReceived += new EventHandler<NtpClient.TimeReceivedEventArgs>(_ntpClient_TimeReceived);
    }

    void _ntpClient_TimeReceived(object sender, NtpClient.TimeReceivedEventArgs e)
    {
        this.Dispatcher.BeginInvoke(() =>
                                        {
                                            txtCurrentTime.Text = e.CurrentTime.ToLongTimeString();
                                            txtSystemTime.Text = DateTime.Now.ToUniversalTime().ToLongTimeString();
                                        });
    }

    private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
    {
            
    }

    private void UpdateTimeButton_Click(object sender, RoutedEventArgs e)
    {
        _ntpClient.RequestTime();
    }
}

Tags: ,

Jul 10 2011

XNA Animated Sprite code uploaded to CodeProject.com

Category: Desktop and ServerJoel Ivory Johnson @ 06:51

I've uploaded some code I was working on to animate sprites in XNA.

Animating a sprite isn't difficult, but I wanted some way to animate them but reduce the coupling between code and the animation. The Content Pipeline is perfect for this. So I created a component that will handle the animation scenarios that I need along with a content extension so that I could load these animations as content. Right now the animation information is in an XML file. This is a stepping point towards having a graphical tool for handling this.

You can read about the code here or see a brief description of it in the video below

Tags: , , ,

Jun 30 2011

Mango Beta 2 Available for Phones Today!

Category: MobileJoel Ivory Johnson @ 03:48

The Beta 2 Mango Windows Phone Tools are available to developers today! Included with the beta is the ability for developers registered with the AppHub to flash their retail devices.

I know there are some non-developers out there that want to also flash their phones and they may wonder how they get get their phones reflashed with the Mango beta. For the time being they cannot. There is an inherent risk in reflashing the phone; you could end up with a bricked phone if something goes bad. If this happens Microsoft has budgeted to take care of repairing up to one phone per developer. But Microsoft doesn't see this risk as being appropriate for user audiences. [Some] developers on the other hand are willing to risk their device's life and limb to have early access to something new. If you brick your device today Microsoft won't be prepared to act on it for another couple of weeks. That's not the best case scenario. But the alternative was to wait another couple of weeks before releasing the Mango tools. If you don't feel safe walking the tight rope without a safety net then don't re-flash your device yet.

According to the Windows Phone Developer site if you are a registered developer you will receive an e-mail inviting you to participate in early access to Mango.

Tags: , ,

Jun 28 2011

Changing the Pitch of a Sound

Category: MobileJoel Ivory Johnson @ 15:28

I got a tweet earlier today from some one asking me how to change the pitch of a wave file. The person asking was aware that SoundEffectInstance has a setting to alter pitch but it wasn't sufficient for his needs. He needed to be able to save the modified WAV to a file. It's something that is easy to do. So I made a quick example

Video Example

I used a technique that comes close to matching linear interpolation. It get's the job done but isn't the best technique because of the opportunity for certain types of distortion to introduced. Methods with less distortion are available at the cost of potentially more CPU cycles. For the example I made no matter what the original sample rate was I am playing back at 44KHz and adjusting my interpolation accordingly so that no unintentional changes in pitch are introduced.

To do the work I've created a class named AdjustedSoundEffect. It has a Play() method that takes as it's argument the factor by which the pitch should be adjusted where 1 plays the sound at the original pitch, 2 plays it at twice its pitch, and 0.5 plays it at half its pitch.

If you are interested the code I used is below.

using System;
using System.IO;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Xna.Framework.Audio;

namespace J2i.Net.VoiceRecorder.Utility
{
    public class AdjustedSoundEffect
    {
        //I will always playback at 44KHz regardless of the original sample rate. 
        //I'm making appropriate adjustments to prevent this from resulting in the
        //pitch being shifted. 
        private const int PlaybackSampleRate = 16000;
        private const int BufferSize = PlaybackSampleRate*2;

        private int _channelCount = 1;
        private int _sampleRate;
        private int _bytesPerSample = 16;
        private int _byteCount = 0;
        private float _baseStepRate = 1;
        private float _adjustedStepRate;
        private float _index = 0;
        private int playbackBufferIndex = 0;
        private int _sampleStep = 2;

        private bool _timeToStop = false;

        private byte[][] _playbackBuffers;

        public bool IsPlaying { get; set;  }

        public object SyncRoot = new object();


        private DynamicSoundEffectInstance _dse;

        public static AdjustedSoundEffect FromStream(Stream source)
        {
            var retVal = new AdjustedSoundEffect(source);
            return retVal;
        }

        public AdjustedSoundEffect()
        {
            _playbackBuffers = new byte[3][];
            for (var i = 0; i < _playbackBuffers.Length;++i )
            {
                _playbackBuffers[i] = new byte[BufferSize];
            }
                _dse = new DynamicSoundEffectInstance(PlaybackSampleRate, AudioChannels.Stereo);
            _dse.BufferNeeded += new EventHandler<EventArgs>(_dse_BufferNeeded);
        }

        void SubmitNextBuffer()
        {
            if(_timeToStop)
            {
                Stop();
            }
            lock (SyncRoot)
            {
                byte[] nextBuffer = _playbackBuffers[playbackBufferIndex];
                playbackBufferIndex = (playbackBufferIndex + 1)%_playbackBuffers.Length;
                int i_step = 0;
                int i = 0;

                int endOfBufferMargin = 2*_channelCount;
                for (;
                    i < (nextBuffer.Length / 4) && (_index < (_sourceBuffer.Length - endOfBufferMargin));
                    ++i, i_step += 4)
                {

                    int k = _sampleStep*(int) _index;
                    if (k > _sourceBuffer.Length - endOfBufferMargin)
                        k = _sourceBuffer.Length -endOfBufferMargin ;
                    nextBuffer[i_step + 0] = _sourceBuffer[k + 0];
                    nextBuffer[i_step + 1] = _sourceBuffer[k + 1];
                    if (_channelCount == 2)
                    {
                        nextBuffer[i_step + 2] = _sourceBuffer[k + 2];
                        nextBuffer[i_step + 3] = _sourceBuffer[k + 3];
                    }
                    else
                    {
                        nextBuffer[i_step + 2] = _sourceBuffer[k + 0];
                        nextBuffer[i_step + 3] = _sourceBuffer[k + 1];

                    }
                    _index += _adjustedStepRate;
                }

                if ((_index >= _sourceBuffer.Length - endOfBufferMargin))
                    _timeToStop = true;
                for (; i < (nextBuffer.Length/4); ++i, i_step += 4)
                {
                    nextBuffer[i_step + 0] = 0;
                    nextBuffer[i_step + 1] = 0;
                    if (_channelCount == 2)
                    {
                        nextBuffer[i_step + 2] = 0;
                        nextBuffer[i_step + 3] = 0;
                    }
                }
                _dse.SubmitBuffer(nextBuffer);
            }
        }

        void _dse_BufferNeeded(object sender, EventArgs e)
        {
            SubmitNextBuffer();
        }

        private byte[] _sourceBuffer;
        

        public AdjustedSoundEffect(Stream source): this()
        {
            byte[] header = new byte[44];
            source.Read(header, 0, 44);

            // I'm assuming you passed a proper wave file so I won't bother 
            // verifying  that  the  header  is properly formatted and will 
            // accept it on faith :-)

            _channelCount = header[22] + (header[23] << 8);
            _sampleRate = header[24] | (header[25] << 8) | (header[26] << 16) | (header[27] << 24);
            _bytesPerSample = header[34]/8;
            _byteCount = header[40] | (header[41] << 8) | (header[42] << 16) | (header[43] << 24);
            _sampleStep = _bytesPerSample*_channelCount;
            _sourceBuffer = new byte[_byteCount];
            source.Read(_sourceBuffer, 0, _sourceBuffer.Length);


            _baseStepRate = ((float)_sampleRate) / PlaybackSampleRate;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pitchFactor">Factor by which pitch will be adjusted. 2 doubles the frequency,
        /// // 1 is normal speed, 0.5 halfs the frequency</param>
        public void Play(float pitchFactor)
        {
            _timeToStop = false;

            _index = 0;
            lock (SyncRoot)
            {
                _adjustedStepRate = _baseStepRate * pitchFactor;
                _index = 0;
                playbackBufferIndex = 0;
            }
            if(!IsPlaying)
            {
                SubmitNextBuffer();
                SubmitNextBuffer();
                SubmitNextBuffer();
                _dse.Play();
                IsPlaying = true;
            }
        }

        public void Stop()
        {
            if(IsPlaying)
            {
                _dse.Stop();
            }
        }
    }
}

Tags: , , ,

Jun 22 2011

Adding an E-Mail Account to the WP Emulator

Category: MobileJoel Ivory Johnson @ 07:03

For one reason or another you may find that you want to add a real e-mail account to the Windows Phone emulator. Unfortunately the emulator doesn't directly expose a way for you to do this; the settings area on the phone doesn't display the tile to access the e-mail settings. You can get to the settings application indirectly though. This path is convoluted, but it works.

You'll need to make a simple application that does nothing more than show a phone call task. Once the task is displayed accept the phone call then select the option to add another caller. This takes you to the People Hub. Swipe through the People Hub to the "What's New" and you will be prompted to add a Facebook or Twitter account. Select the option to do this (even though you are not really adding an account of that type) and when you asked what type of account you want to add you can select one of the e-mail account types.

Tags: ,

Jun 21 2011

Setting Custom Ringtones from Code [Mango:Beta 1]

Category: MobileJoel Ivory Johnson @ 03:20
Written against pre-release information

One of the new features coming with the next update to Windows Phone 7 is the ability to set custom ring tones. From within code you can make a ring tone available to a user (it's up to the user to accept the ring tone, so user settings won't ever be changed without user permission). I was looking at the new API for doing this, the SaveRingtonTask()

To use the API you first need to get the ringtone of interest into isolated storage. It can be either an MP3 file or a WMA file up to 30 seconds in length. If the file is a part of your application. Just set it's build type to "Resource".

file settings

Getting the file from being packed in the application to isolated storage is a matter of reading from a resource stream and writing to isolated storage.

var
s =
    Application.GetResourceStream(new Uri("/MyApplicationName;component/1up.mp3",
                                            UriKind.Relative));
{
    using (var f = IsolatedStorageFile.GetUserStoreForApplication().CreateFile("1up.mp3"))
    {

        var buffer = new byte[2048];
        int bytesRead = 0;

        do
        {
            bytesRead = s.Stream.Read(buffer, 0, 1024);
            f.Write(buffer, 0, bytesRead);
        } while (bytesRead > 0);

        f.Close();
    }
}

Once the file is in isolated storage you must pass the URL to the SaveRingtoneTask(). URIs to isolated storage are preceded with "isostore:" (there is also an "appdata:" prefix, but we won't be using it here). Give the ringtone a display name and call the show method to present the user with the option to save it. If you don't set the

SaveRingtoneTask srt = new SaveRingtoneTask();
srt.DisplayName = "1up";
srt.IsoStore= new Uri("isostore:/1up.mp3", UriKind.Absolute);
srt.IsShareable = true;
srt.Show();

Tags: , ,

Jun 20 2011

Peer Communication on Windows Phone 7

Category: MobileJoel Ivory Johnson @ 14:28

Written against pre-release information

One of the new things that we get with Windows Phone 7 is socket support. While I expected to be able to open sockets to other machines with servers running on them one thing caught me by surprised; that you can also send communication from phone to phone using UDP. I've got to give credit to Ricky_T for pointint out the presence of this feature and posting a code sample. I wanted to try this out myself. So I made a version of the code sample that would run on both Windows Phone and on the desktop (Silverlight 4 in Out of Browser mode). I was pleasantly surprised to that I was able to open up peer communication between the desktop and phone without a problem. This capability provides a number of solutions for other problems that I've been considering, such as automatic discovery and configuration for communicating with services hosted on a user's local network. 

Most of the code used in the desktop and phone version of this example are identical; I've shared some of the same files between projects. From the files that are not shared the counterparts in the phone and desktop version are still similar.  The core of the code is in a class called Peer. Let's take a look at part of the body of that class. 

 

//Define the port and multicast address to be used for communication
private string _channelAddress = "224.0.0.1";
private int _channelPort = 3007;

//The event to be raised when a message comes in
public event EventHandler<MessageReceivedEventArgs> MessageReceived; 

//the UDP channel over which communication will occur.
private UdpAnySourceMulticastClient _channel;

//Create tje cjamme;
public void Initialize()
{
    _channel = new UdpAnySourceMulticastClient(IPAddress.Parse(_channelAddress), _channelPort);
}

//Open the channel and start listening
public void Open()
{
    if (_channel == null)
        Initialize();
    ClientState = ClientStatesEnum.Opening;
            

    _openResult = _channel.BeginJoinGroup((result) =>
                                                {
                                                    _channel.EndJoinGroup(result);
                                                    ClientState = ClientStatesEnum.Opened;
                                                }, null);   
            
    Receive();
}


 

//The receive method is recursive. At the end of a call to receive it calls itself 
//so that the class can continue listening for incoming requests.
void Receive()
{
    byte[] _receiveBuffer = new byte[1024];

    _channel.BeginReceiveFromGroup(_receiveBuffer, 0, _receiveBuffer.Length, (r) =>
    {
        if(ClientState!=ClientStatesEnum.Closing)
        {
            try
            {
            IPEndPoint source;
            int size= _channel.EndReceiveFromGroup(r, out source);
            OnMessageReceived(_receiveBuffer, size,  source);                                                                                   
            }
            catch (Exception )
            {
            }
            finally
            {
                this.Receive();
            }
        }
    }, null);
}
public void Send(byte[] data)
{
    if(ClientState==ClientStatesEnum.Opened)
    {
        _channel.BeginSendToGroup(data, 0, data.Length, (r) => _channel.EndSendToGroup(r),null);
    }
}

This class only sends and receives byte arrays. My only goal here was to see the code work so there are other considerations that I have decided to overlook for now. I made a client to use this code too. The client sends and receives plain text. Before sending a block of text it is necessary to convert the text to a byte array. The encoding classes in .Net will take care of this for me. When a message comes in I can also use an encoder to convert the byte array back to a string.

For this program I am adding the incoming message to a list along with the IP address from which it came

void _peer_MessageReceived(object sender, MessageReceivedEventArgs e)
{
    Action a = () =>
                    {
                        string message = System.Text.UTF8Encoding.Unicode.GetString(e.Data, 0, e.Size);
                        MessageList.Add(String.Format("{0}:{1}", e.Endpoint.Address.ToString(), message));
                        OnIncomingMessageReceived(message, e.Endpoint.Address.ToString());
                    };
    if (UIDispatcher == null)
        a();
    else
        UIDispatcher.BeginInvoke(a);
}

public void SendMessage(string message)
{
    byte[] encodedMessage= UTF8Encoding.Unicode.GetBytes(message);
    _peer.Send(encodedMessage);
}

When the code is run on any combination of multiply phones or computers a message types on any one of the devices appears on all of them. Nice! Now to start making use of it.

Tags: ,