I write a c++ program that send via memorystream a array multi to c# aplication. But i dont know hot to use BlockCopy to array multi:
this is my program c++ that send array multi
struct Pair {
std::pair<int, int> players;
};
struct Pair* p;
HANDLE handle;
float dataSend[70];
bool startShare()
{
try
{
handle = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(Pair), L"DataSend");
p = (struct Pair*) MapViewOfFile(handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, sizeof(Pair));
return true;
}
catch (...)
{
return false;
}
}
for (int i = 0; i < 70; i++)
{
int r1 = rand() % 10 + 1;
int r2 = rand() % 10 + 1;
p->players = { r1,r2 };
}
example aoutput:
players 0 - [10][2]
players 1 - [100][22]
players 2 - [1][26]
players 3 - [50][211]
players 4 - [32][23]
my c# program read:
public static int[,] data = new int[70, 1];
public static MemoryMappedFile mmf;
public static MemoryMappedViewStream mmfvs;
static public bool MemOpen()
{
try
{
mmf = MemoryMappedFile.OpenExisting("DataSend");
mmfvs = mmf.CreateViewStream();
return true;
}
catch
{
return false;
}
}
// here need be somethings like byte[,] bPosition = new byte[70,1];
byte[] bPosition = new byte[70];
mmfvs.Read(bPosition, 0, 100);
Buffer.BlockCopy(bPosition, 0, data, 0, bPosition.Length);
for (int i = 0; i< data.Length; i++)
{
for(int j=0;j<1;j++)
{
Console.WriteLine(data[i][j]);
}
}
example receive :
data 0 - [10][2]
data 1 - [100][22]
data 2 - [1][26]
data 3 - [50][211]
data 4 - [32][23]
I write a c++ program that send via memorystream a array multi to c# aplication. But i dont know hot to use BlockCopy to array multi:
this is my program c++ that send array multi
Try following :
MemoryStream stream = new MemoryStream();
byte[] buffer = new byte[70 * 2 * sizeof(int)];
stream.Read(buffer, 0, 70 * 2 * sizeof(int));
for (int i = 0; i< 70; i++)
{
for (int j = 0; j < 2; j++)
{
Console.WriteLine(BitConverter.ToUInt32(buffer,(i * 2 * sizeof(int)) + (j * sizeof(int))));
}
}
IntPtr bufferPtr = Marshal.AllocHGlobal(BUFFER_SIZE);
//you need to allocate memory before calling the routing
byte[] buffer = new byte[BUFFER_SIZE];
Marshal.Copy(bufferPtr, buffer, 0, BUFFER_SIZE);
for (int i = 0; i < 70; i++)
{
for (int j = 0; j < 2; j++)
{
Console.WriteLine(BitConverter.ToUInt32(buffer, (i * 2 * sizeof(int)) + (j * sizeof(int))));
}
}
//method 2
int[,] array = new int[40, 2];
IntPtr bufferPtr2 = Marshal.AllocHGlobal(Marshal.SizeOf(array));
//call routine then you code below to fill managed memory.
Marshal.PtrToStructure(bufferPtr2, array);
Related
I work with Media Foundataion and what I need to do is convert sound sample frame from byte to audio float data. In order to do it I use such method (that I found somewhere at google):
private static float[] Convert16BitByteArrayToAudioClipData(byte[] source, int headerOffset, int dataSize)
{
int wavSize = BitConverter.ToInt32(source, headerOffset);
headerOffset += sizeof(int);
Debug.AssertFormat(wavSize > 0 && wavSize == dataSize, "Failed to get valid 16-bit wav size: {0} from data bytes: {1} at offset: {2}", wavSize, dataSize, headerOffset);
int x = sizeof(Int16); // block size = 2
int convertedSize = wavSize / x;
float[] data = new float[convertedSize];
Int16 maxValue = Int16.MaxValue;
int i = 0;
while (i < convertedSize)
{
int offset = i * x + headerOffset;
data[i] = (float)BitConverter.ToInt16(source, offset) / maxValue;
++i;
}
Debug.AssertFormat(data.Length == convertedSize, "AudioClip .wav data is wrong size: {0} == {1}", data.Length, convertedSize);
return data;
}
I use it like this :
...
byte[] source = ...; // lenght 43776
... = Convert16BitByteArrayToAudioClipData(source , 0, 0);
...
Looks like this method works wrong, because if I pass an array with size 43776 as a result in while loop at index i = 21886 offset value will be offset = 43776 it lead to exception at this next method
data[i] = (float)BitConverter.ToInt16(source /*43776*/, offset /*43776*/) / maxValue;
because this values could not be the same.
Question is - how to fix this method? Or maybe someone can advice what to use instead?
EDIT
private static float[] Convert16BitByteArrayToAudioClipData(byte[] source)
{
float[] data = new float[source.Length];
for (int i = 0; i < source.Length; i++)
{
data[i] = (float) source[i];
}
return data;
}
Integers need to become -1..+1 floating point values
private static float[] Convert16BitByteArrayToAudioClipData(byte[] source)
{
float[] data = new float[source.Length];
for (int i = 0; i < source.Length; i++)
{
data[i] = ((float) source[i] / Int16.MaxValue); // <<---
}
return data;
}
Eventually I did it this way:
public static float[] Convert16BitByteArrayToAudioClipData(byte[] source)
{
int x = sizeof(Int16);
int convertedSize = source.Length / x;
float[] data = new float[convertedSize];
Int16 maxValue = Int16.MaxValue;
for (int i = 0; i < convertedSize; i++)
{
int offset = i * x;
data[i] = (float)BitConverter.ToInt16(source, offset) / maxValue;
++i;
}
return data;
}
I created a c++ project to test CreateFileMappingW, along with a struct where i create 2 arrays. I was able to read the first array in my C# project via MemoryMappedFile, but for some reason I couldn't get the values for the second array.
C++ code
#include <windows.h>
#include <stdio.h>
#include <iostream>
struct StructOfArray {
int array1[3];
int array2[2];
};
struct StructOfArray* datatoget;
HANDLE handle;
int main() {
handle = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(StructOfArray), L"DataSend");
datatoget = (struct StructOfArray*) MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(StructOfArray));
datatoget->array1[0] = 10;
datatoget->array1[1] = 15;
datatoget->array1[2] = 20;
datatoget->array2[0] = 200;
datatoget->array2[1] = 203;
}
C# project:
int[] firstArray = new int[3];
int[] secondArray = new int[2];
string filePath = "DataSend";
mmf = MemoryMappedFile.OpenExisting(filePath);
mmfvs = mmf.CreateViewStream();
byte[] bPosition = new byte[1680];
mmfvs.Read(bPosition, 0, 1680);
Buffer.BlockCopy(bPosition, 0, firstArray, 0, bPosition.Length);//worked fine
Buffer.BlockCopy(bPosition, 0, secondtArray, 0, bPosition.Length);//did not work
for (int i = 0; i < 3; i++)
{
console.WritLine(firstArray[i])//worked fine
}
for (int i = 0; i < 2; i++)
{
console.WritLine(secondtArray[i])// not sure how to take second array
}
Use a MemoryMappedViewAccessor:
mmf = MemoryMappedFile.OpenExisting(filePath);
using (var accessor = mmf.CreateViewAccessor(0, Marshal.SizeOf(typeof(int)) * 5))
{
int intSize = Marshal.SizeOf(typeof(int));
//Read first array..
for (long i = 0; i < 3 * intSize; i += intSize)
{
int value = 0;
accessor.Read(i, out value);
firstArray[i] = value;
}
//Read second array..
for (long i = 0; i < 2 * intSize; i += intSize)
{
int value = 0;
accessor.Read(i, out value);
secondArrayArray[i] = value;
}
}
OR (your offsets are wrong.. you are literally calling BlockCopy with the exact same parameters but different arrays -- IE: same offsets: 0):
var intSize = Marshal.SizeOf(typeof(int));
//Copy first array..
Buffer.BlockCopy(bPosition, 0, firstArray, 0, intSize * firstArray.Length);
//Copy second array..
Buffer.BlockCopy(bPosition, intSize * firstArray.Length, secondArray, 0, intSize * secondArray.Length);
I got some pixel data from 16-bit(range 0-65535) tif image as an integer array. I got the value using gdal readraster. How do I convert them to 8-bit(0-225) and convert it (the array) to 8-bit tif image ?
Here is some of my code :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OSGeo.GDAL;
using OSGeo.OSR;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
Gdal.AllRegister();
Dataset data1;
int xsize, ysize;
int bandsize;
data1 = Gdal.Open("F:\\po_1473547_bgrn_0000000.tif", Access.GA_ReadOnly);
bandsize = data1.RasterCount;
xsize = data1.RasterXSize; //cols
ysize = data1.RasterYSize; //rows
Console.WriteLine("cols : "+xsize+", rows : "+ysize);
Band[] bands = new Band[bandsize];
for (int i = 0; i < bandsize; i++) {
bands[i] = data1.GetRasterBand(i+1);
}
int[,,] pixel = new int[bandsize,xsize,ysize];
int[] pixtemp = new int[xsize * ysize];
for (int i = 0; i < bandsize; i++)
{
bands[i].ReadRaster(0, 0, xsize, ysize, pixtemp, xsize, ysize, 0, 0);
for (int j = 0; j < xsize; j++)
{
for (int k = 0; k < ysize; k++)
{
pixel[i,j,k] = pixtemp[j + k * xsize];
}
}
}
Console.WriteLine("");
for (int i = 0; i < bandsize; i++)
{
Console.WriteLine("some pixel from band " + (i+1));
for (int j = 0; j < 100; j++)
{
Console.Write(" " + pixel[i,100,j]);
}
Console.WriteLine("\n\n");
}
}
}
}
I was searching Google on how to do that but I only found how to do that if the data type is a byte. Someone please give me a hint.
I don't know about GEO Tiff format, but to convert a regular 16 bit tiff image file to an 8 bit one, you need to scale the 16 bit channel values to 8 bits. The example below shows how this can be achieved for gray scale images.
public static class TiffConverter
{
private static IEnumerable<BitmapSource> Load16BitTiff(Stream source)
{
var decoder = new TiffBitmapDecoder(source, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
for (int i = 0; i < decoder.Frames.Count; i++)
// return all frames that are present in the input.
yield return decoder.Frames[i];
}
private static BitmapSource NormalizeTiffTo8BitImage(BitmapSource source)
{
// allocate buffer & copy image bytes.
var rawStride = source.PixelWidth * source.Format.BitsPerPixel / 8;
var rawImage = new byte[rawStride * source.PixelHeight];
source.CopyPixels(rawImage, rawStride, 0);
// get both max values of first & second byte of pixel as scaling bounds.
var max1 = 0;
int max2 = 1;
for (int i = 0; i < rawImage.Length; i++)
{
if ((i & 1) == 0)
{
if (rawImage[i] > max1)
max1 = rawImage[i];
}
else if (rawImage[i] > max2)
max2 = rawImage[i];
}
// determine normalization factors.
var normFactor = max2 == 0 ? 0.0d : 128.0d / max2;
var factor = max1 > 0 ? 255.0d / max1 : 0.0d;
max2 = Math.Max(max2, 1);
// normalize each pixel to output buffer.
var buffer8Bit = new byte[rawImage.Length / 2];
for (int src = 0, dst = 0; src < rawImage.Length; dst++)
{
int value16 = rawImage[src++];
double value8 = ((value16 * factor) / max2) - normFactor;
if (rawImage[src] > 0)
{
int b = rawImage[src] << 8;
value8 = ((value16 + b) / max2) - normFactor;
}
buffer8Bit[dst] = (byte)Math.Min(255, Math.Max(value8, 0));
src++;
}
// return new bitmap source.
return BitmapSource.Create(
source.PixelWidth, source.PixelHeight,
source.DpiX, source.DpiY,
PixelFormats.Gray8, BitmapPalettes.Gray256,
buffer8Bit, rawStride / 2);
}
private static void SaveTo(IEnumerable<BitmapSource> src, string fileName)
{
using (var stream = File.Create(fileName))
{
var encoder = new TiffBitmapEncoder();
foreach (var bms in src)
encoder.Frames.Add(BitmapFrame.Create(bms));
encoder.Save(stream);
}
}
public static void Convert(string inputFileName, string outputFileName)
{
using (var inputStream = File.OpenRead(inputFileName))
SaveTo(Load16BitTiff(inputStream).Select(NormalizeTiffTo8BitImage), outputFileName);
}
}
Usage:
TiffConverter.Convert(#"c:\temp\16bit.tif", #"c:\temp\8bit.tif");
Interpolate pixels from 16 bit to 8 bit, some resampling methods could perform.
Linear Interpolation may help.
//Convert tiff from 16-bit to 8-bit
byte[,,] ConvertBytes(int[,,] pixel, bandsize, xsize, ysize)
{
byte[,,] trgPixel = new byte[bandsize,xsize,ysize];
for (int i = 0; i < bandsize; i++)
{
for (int j = 0; j < xsize; j++)
{
for (int k = 0; k < ysize; k++)
{
//Linear Interpolation
trgPixel[i,j,k] = (byte)((65535-pixel[i,j,k])/65536.0*256);
}
}
}
return trgPixel;
}
//Save 8-bit tiff to file
void SaveBytesToTiff(string destPath, byte[,,] pixel, bandsize, xsize, ysize)
{
string fileformat = "GTiff";
Driver dr = Gdal.getDriverByName(fileformat);
Dataset newDs = dr.Create(destPath, xsize, ysize, bandsize, DateType.GDT_Byte, null);
for(int i=0; i< bandsize;i++)
{
byte[] buffer = new byte[xsize * ysize];
for (int j = 0; j < xsize; j++)
{
for (int k = 0; k < ysize; k++)
{
buffer[j+k*xsize] = pixel[i,j,k];
}
}
newDs.WriteRaster(0, 0, xsize, ysize, buffer, xsize, ysize, i+1, null, 0, 0, 0);
newDs.FlushCache();
}
newDs.Dispose();
}
I'm trying to create a VSTstream class based on this thread: http://vstnet.codeplex.com/discussions/228692.
To record and playback the sound I'm using the AsioOut object that gives me available to IntPtr[] buffers type in the callback function OnAudioAvailable().
To do this I created the VSTstream class, taking example from the thread linked, appropriately modified to process directly the IntPtr[] buffers.
During the various processes of casting, however, it gives me an error of "AccessViolationException", probably due to the casting wrong.
I'm testing the VSTstream class opening the Jacobi.Vst.Samples.Delay.dll
EDIT: The error occurs on this line:
Marshal.Copy(sourceBuffer[1], rightBuf, 0, sampleCount/channels);
Does anyone know what I did wrong? If you need additional information or code I'm available.
Thanks to all.
OnAudioAvailable():
private void OnAudioAvailable(object sender, AsioAudioAvailableEventArgs e)
{
//No Effect
for (int i = 0; i < e.InputBuffers.Length; i++)
{
MoveMemory(e.OutputBuffers[i], e.InputBuffers[i], e.SamplesPerBuffer * e.InputBuffers.Length * 2);
}
//Effect
if (Parametri.effetto)
{
//Accendo i plugin
for (int i = 0; i < plugins.Count; i++)
{
plugins[i].MainsChanged(true);
plugins[i].StartProcess();
}
//Processo i sample
vstStream.ProcessSample(e.OutputBuffers, 0, e.SamplesPerBuffer * e.InputBuffers.Length * 2, e.InputBuffers);
//Spengo i plugin
for (int i = 0; i < plugins.Count; i++)
{
plugins[i].StopProcess();
plugins[i].MainsChanged(false);
}
}
e.WrittenToOutputBuffers = true;
}
VSTstream class:
class VSTstream
{
public List<IVstPluginCommandStub> plugins;
VstAudioBufferManager vstBufManIn, vstBufManOut;
private VstAudioBuffer[] vstBufIn = null;
private VstAudioBuffer[] vstBufOut = null;
private int sampleRate, channels, blockSize;
private float[] leftBuf, rightBuf;
public VSTstream(int sampleRate, int channels, int blockSize, List<IVstPluginCommandStub> plugins)
{
this.plugins = plugins;
this.sampleRate = sampleRate;
this.channels = channels;
this.blockSize = blockSize;
plugins[0].SetBlockSize(blockSize);
plugins[0].SetSampleRate((float)sampleRate);
vstBufManIn = new VstAudioBufferManager(channels, blockSize); //*channels
vstBufManOut = new VstAudioBufferManager(channels, blockSize);
//vstBufIn = vstBufManIn.ToArray();
//vstBufOut = vstBufManOut.ToArray();
vstBufIn = vstBufManIn.Cast<VstAudioBuffer>().ToArray();
vstBufOut = vstBufManOut.Cast<VstAudioBuffer>().ToArray();
leftBuf = new float[(blockSize * 4)/channels];
rightBuf = new float[(blockSize * 4)/channels];
}
public int ProcessSample(IntPtr[] destBuffer, int offset, int sampleCount, IntPtr[] sourceBuffer)
{
//da IntPtr[L][R] a Lfloat[]+Rfloat[]
Marshal.Copy(sourceBuffer[0], leftBuf, 0, sampleCount/channels);// (/channels)
Marshal.Copy(sourceBuffer[1], rightBuf, 0, sampleCount/channels);
unsafe
{
fixed (float* Lfloat = &leftBuf[0])
{
fixed (float* Rfloat = &rightBuf[0])
{
for (int i = 0; i < sampleCount / channels; i++)
{
vstBufIn[0][i] = *(Lfloat + i);
vstBufIn[1][i] = *(Rfloat + i);
}
}
}
}
//Qui dovrà rimanere solo 'ProcessReplacing();'
//plugins[0].MainsChanged(true);
//plugins[0].StartProcess();
plugins[0].ProcessReplacing(vstBufIn, vstBufOut);
//plugins[0].StopProcess();
//plugins[0].MainsChanged(false);
unsafe
{
float* tmpBufL = ((IDirectBufferAccess32)vstBufOut[0]).Buffer;
float* tmpBufR = ((IDirectBufferAccess32)vstBufOut[1]).Buffer;
for (int i = 0; i < (sampleCount / channels); i++)
{
leftBuf[i] = *(tmpBufL + i);
rightBuf[i] = *(tmpBufR + i);
}
}
//da Lfloat[]+Rfloat[] a IntPtr[L][R]
Marshal.Copy(leftBuf, 0, destBuffer[0], sampleCount/channels);
Marshal.Copy(rightBuf, 0, destBuffer[1], sampleCount/channels);
return sampleCount;
}
}
I am learning how to call C code from my C# code. I want to call a C function that returns a 2D array of ints. This function takes no arguments. Here is the function:
extern "C" _declspec(dllexport) int** intMatrixReturn()
{
int** A = (int**)malloc(3 * sizeof(int *));
for(int i = 0; i < 3; i++)
{
A[i] = (int*)malloc(3 * sizeof(int));
for(int j = 0; j < 3; j++)
{
A[i][j] = i * j;
}
}
return A;
}
This is how I am trying to access the array in my C# code:
IntPtr ip = intArrayReturn();
int[] iarr = new int[9];
Marshal.Copy(ip, iarr, 0, 9);
foreach (var item in iarr)
{
Console.WriteLine(item);
}
This is my console output:
1
2
3
4218
86245572
86252624
0
0
0
I assume that my problem is my C# code. How do I read the 2D int array that gets returned from my C function? Also, does the garbage-collector free the memory that holds the 2D array, or should I do that in the C# code?
My apologies if this is a duplicate, but all of the questions I found concerning 2D arrays involve sending them from C# to C, not the other way araound.
You're passing Marshal.Copy a one dimensional array so of course that's what you're going to get back. Additionally that foreach loop won't work with a 2d array.
This is by no means a solution, only a starting point;
1) make iarr a 2d array - int[] iarr = new int[9][9];
2) make your print function a nested for loop -
for (int i = 0; i < 9; i++)
{
for (int j = 0; i < 9; j++)
{
Console.WriteLine(iarr[i][j]);
}
}
Don't. Use one dimensional array of proper size on the native side, then everything works out of the box. Otherwise you will need to marshal the native array as array of pointers where each element points to the proper memory chunk. Then, do what evanmcdonnal told you, using the respective overload of Marshal.Copy. With regard to memory deallocation, you are in charge, or better, the native library is: the safe way is to pass the arrays back to native library which takes care of proper deallocation.
I ended up using the suggestion of Paul Michalik. I've used a one-dimensional array. It's not a straightfoward manner but it really works well as a 2D:
C side:
extern "C" {
struct Matrix
{
int size1; // rows number
int size2; // cols number
int *data;
};
Matrix* intMatrixReturn(int size1, int size2) {
Matrix *m = (Matrix*)malloc(sizeof(Matrix) * 1);
m->data = (int*)malloc(sizeof(int) * size1 * size2);
m->size1 = size1;
m->size2 = size2;
for (int i = 0; i < size1; i++)
{
for (int j = 0; j < size2; j++)
{
m->data[i*size2+j] = i*size2+j;
}
}
return m;
}
}
C# side:
[StructLayout(LayoutKind.Sequential)]
public struct Matrix
{
public int size1;
public int size2;
public IntPtr data;
}
[DllImport(#"dllname.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr intMatrixReturn(int size1, int size2);
static void Main(string[] args)
{
int size1 = 3; // rows
int size2 = 3; // cols
IntPtr p1 = intMatrixReturn(size1, size2);
Matrix m1 = (Matrix)Marshal.PtrToStructure(p1, typeof(Matrix));
int[] tmp = new int[m1.size1 * m1.size2];
IntPtr pd2 = m1.data;
Marshal.Copy(pd2, tmp, 0, m1.size1 * m1.size2);
for (int i = 0; i < m1.size1; i++)
{
for (int j = 0; j < m1.size2; j++)
{
Console.Write(tmp[i * m1.size2 + j] + " ");
}
Console.WriteLine();
}
}
Output:
0 1 2
3 4 5
6 7 8