AH_SIntPtr buffer_read(t_symbol *buffer, long chan, float *out, AH_SIntPtr max_length)
{
    AH_SIntPtr length;
    long n_chans, format;
    void *samps;

    void *b = ibuffer_get_ptr(buffer);

    if (!b)
        return 0;

    if (!ibuffer_info(b, &samps, &length, &n_chans, &format))
        return 0;

    if (chan >= n_chans)
        return 0;

    if (length > max_length || !length)
        return 0;

    ibuffer_increment_inuse(b);
    ibuffer_get_samps(samps, out, 0L, length, n_chans, chan, format);
    ibuffer_decrement_inuse(b);

    return length;
}
AH_SIntPtr buffer_read_part(t_symbol *buffer, long chan, float *out, AH_SIntPtr offset, AH_SIntPtr read_length)
{
    AH_SIntPtr length;
    long n_chans, format;
    void *samps;

    void *b = ibuffer_get_ptr(buffer);

    if (!b)
        return 0;

    if (!ibuffer_info(b, &samps, &length, &n_chans, &format))
        return 0;

    ibuffer_increment_inuse(b);
    ibuffer_get_samps(samps, out, offset, read_length, n_chans, chan, format);
    ibuffer_decrement_inuse(b);

    return read_length;
}
void ibufconcatenate_append(t_ibufconcatenate *x, t_symbol *source_name)
{
    ibuffer_data target(x->attachment->buffer_name);
    ibuffer_data source(source_name);
	
	float *out_samps;
	
	double *starts = x->attachment->starts;
	double *ends = x->attachment->ends;
	
	long samp_offset = x->attachment->samp_offset;
	long num_items = x->attachment->num_items;
	long new_size;
	long old_size;
	
	double sr_const;
		
	t_atom last_added_list[3];

	if (target.get_type() == kBufferMaxBuffer)
	{
		// Check we have a mono buffer and that there is space for another item
		
		if (target.get_num_chans() > 1)
		{
			error ("ibufconcatenate: only supports writing to mono buffers at this time");
			return;
		}
		
		if (num_items >= MAX_ITEMS)
			return;

		// Check we have enough memory in the buffer
		
		if (samp_offset + source.get_length() + 1 > target.get_length())
		{
			// Calculate memory to allocate
			
			float *temp;

			new_size = samp_offset + source.get_length() + 1;
			old_size = target.get_length();
			
			if (old_size + GROW_SIZE > new_size)
				new_size = old_size + GROW_SIZE;
			
			// Allocate temporary memory
			
			temp = static_cast<float*>(malloc(sizeof(float) * target.get_length()));
			
			if (!temp)
			{
				error ("ibufconcatenate: no room left in buffer");
				return;
			}

			// Copy out
            
            out_samps = static_cast<float *>(target.get_samples());
            std::copy(out_samps, out_samps + old_size, temp);
			
			// Set buffer to new size
			
            target.set_size_in_samples(new_size);
			
            out_samps = static_cast<float *>(target.get_samples());
			if (target.get_length());
                std::copy(temp, temp + old_size, out_samps);
			
			// Free temporary memory and check the resize has worked 
			
			free(temp);

            if (samp_offset + source.get_length() + 1 > target.get_length())
			{
				error ("ibufconcatenate: no room left in buffer");
				return;
			}
		}
		
		out_samps = static_cast<float *>(target.get_samples());
		
		// Get samples from the source - this is constrained to only msp buffers do to unknown pointer alignment in the target (with the offset)
		
        ibuffer_get_samps(source, out_samps, samp_offset, source.get_length(), 0);
		
		// Add a silent sample
		
		*(out_samps + samp_offset + source.get_length()) = 0.f;
		
		// Store data
		
		sr_const = 1000.0 / target.get_sample_rate();
		starts[num_items] = (double) samp_offset * sr_const;
		samp_offset = samp_offset + source.get_length() + 1;
		ends[num_items] = (double) (samp_offset - 1) * sr_const; 
		
		x->attachment->num_items = num_items + 1;
		x->attachment->samp_offset = samp_offset;
		
		// Set the buffer as dirty
		
        target.set_dirty();
		
		// We are done with the buffers
        
        target.release();
        source.release();
        
		// Output Values
		
		atom_setlong(last_added_list, num_items + 1);
		atom_setfloat(last_added_list+1, starts[num_items]);
		atom_setfloat(last_added_list+2, ends[num_items]);
		
		outlet_list(x->last_added_out, 0, 3, last_added_list);
	}
}